diff --git a/minigeth/consensus/ethash/fake_ethash.go b/minigeth/consensus/ethash/fake_ethash.go index 55518e4f02af201bfdf29e8ddbcba79d308411fb..368e98fd7779f835aaa8986d9af60dc9186876db 100644 --- a/minigeth/consensus/ethash/fake_ethash.go +++ b/minigeth/consensus/ethash/fake_ethash.go @@ -5,6 +5,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -17,8 +18,11 @@ func (ethash *Ethash) Author(header *types.Header) (common.Address, error) { return header.Coinbase, nil } +// CalcDifficulty is the difficulty adjustment algorithm. It returns +// the difficulty that a new block should have when created at time +// given the parent block's time and difficulty. func (ethash *Ethash) CalcDifficulty(chain consensus.ChainHeaderReader, time uint64, parent *types.Header) *big.Int { - return nil + return CalcDifficulty(chain.Config(), time, parent) } func (ethash *Ethash) Close() error { @@ -33,29 +37,28 @@ var ( maxUncles = 2 // Maximum number of uncles allowed in a single block allowedFutureBlockTimeSeconds = int64(15) // Max seconds from current time allowed for blocks, before they're considered future blocks - /* - // calcDifficultyEip3554 is the difficulty adjustment algorithm as specified by EIP 3554. - // It offsets the bomb a total of 9.7M blocks. - // Specification EIP-3554: https://eips.ethereum.org/EIPS/eip-3554 - calcDifficultyEip3554 = makeDifficultyCalculator(big.NewInt(9700000)) - - // calcDifficultyEip2384 is the difficulty adjustment algorithm as specified by EIP 2384. - // It offsets the bomb 4M blocks from Constantinople, so in total 9M blocks. - // Specification EIP-2384: https://eips.ethereum.org/EIPS/eip-2384 - calcDifficultyEip2384 = makeDifficultyCalculator(big.NewInt(9000000)) - - // calcDifficultyConstantinople is the difficulty adjustment algorithm for Constantinople. - // It returns the difficulty that a new block should have when created at time given the - // parent block's time and difficulty. The calculation uses the Byzantium rules, but with - // bomb offset 5M. - // Specification EIP-1234: https://eips.ethereum.org/EIPS/eip-1234 - calcDifficultyConstantinople = makeDifficultyCalculator(big.NewInt(5000000)) - - // calcDifficultyByzantium is the difficulty adjustment algorithm. It returns - // the difficulty that a new block should have when created at time given the - // parent block's time and difficulty. The calculation uses the Byzantium rules. - // Specification EIP-649: https://eips.ethereum.org/EIPS/eip-649 - calcDifficultyByzantium = makeDifficultyCalculator(big.NewInt(3000000))*/ + // calcDifficultyEip3554 is the difficulty adjustment algorithm as specified by EIP 3554. + // It offsets the bomb a total of 9.7M blocks. + // Specification EIP-3554: https://eips.ethereum.org/EIPS/eip-3554 + calcDifficultyEip3554 = makeDifficultyCalculator(big.NewInt(9700000)) + + // calcDifficultyEip2384 is the difficulty adjustment algorithm as specified by EIP 2384. + // It offsets the bomb 4M blocks from Constantinople, so in total 9M blocks. + // Specification EIP-2384: https://eips.ethereum.org/EIPS/eip-2384 + calcDifficultyEip2384 = makeDifficultyCalculator(big.NewInt(9000000)) + + // calcDifficultyConstantinople is the difficulty adjustment algorithm for Constantinople. + // It returns the difficulty that a new block should have when created at time given the + // parent block's time and difficulty. The calculation uses the Byzantium rules, but with + // bomb offset 5M. + // Specification EIP-1234: https://eips.ethereum.org/EIPS/eip-1234 + calcDifficultyConstantinople = makeDifficultyCalculator(big.NewInt(5000000)) + + // calcDifficultyByzantium is the difficulty adjustment algorithm. It returns + // the difficulty that a new block should have when created at time given the + // parent block's time and difficulty. The calculation uses the Byzantium rules. + // Specification EIP-649: https://eips.ethereum.org/EIPS/eip-649 + calcDifficultyByzantium = makeDifficultyCalculator(big.NewInt(3000000)) ) // Some weird constants to avoid constant memory allocs for them. @@ -131,3 +134,181 @@ func (ethash *Ethash) VerifyHeaders(chain consensus.ChainHeaderReader, headers [ func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { return nil } + +// CalcDifficulty is the difficulty adjustment algorithm. It returns +// the difficulty that a new block should have when created at time +// given the parent block's time and difficulty. +func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int { + next := new(big.Int).Add(parent.Number, big1) + switch { + case config.IsCatalyst(next): + return big.NewInt(1) + case config.IsLondon(next): + return calcDifficultyEip3554(time, parent) + case config.IsMuirGlacier(next): + return calcDifficultyEip2384(time, parent) + case config.IsConstantinople(next): + return calcDifficultyConstantinople(time, parent) + case config.IsByzantium(next): + return calcDifficultyByzantium(time, parent) + case config.IsHomestead(next): + return calcDifficultyHomestead(time, parent) + default: + return calcDifficultyFrontier(time, parent) + } +} + +// Some weird constants to avoid constant memory allocs for them. +var ( + expDiffPeriod = big.NewInt(100000) + big1 = big.NewInt(1) + big2 = big.NewInt(2) + big9 = big.NewInt(9) + big10 = big.NewInt(10) + bigMinus99 = big.NewInt(-99) +) + +// makeDifficultyCalculator creates a difficultyCalculator with the given bomb-delay. +// the difficulty is calculated with Byzantium rules, which differs from Homestead in +// how uncles affect the calculation +func makeDifficultyCalculator(bombDelay *big.Int) func(time uint64, parent *types.Header) *big.Int { + // Note, the calculations below looks at the parent number, which is 1 below + // the block number. Thus we remove one from the delay given + bombDelayFromParent := new(big.Int).Sub(bombDelay, big1) + return func(time uint64, parent *types.Header) *big.Int { + // https://github.com/ethereum/EIPs/issues/100. + // algorithm: + // diff = (parent_diff + + // (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)) + // ) + 2^(periodCount - 2) + + bigTime := new(big.Int).SetUint64(time) + bigParentTime := new(big.Int).SetUint64(parent.Time) + + // holds intermediate values to make the algo easier to read & audit + x := new(big.Int) + y := new(big.Int) + + // (2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9 + x.Sub(bigTime, bigParentTime) + x.Div(x, big9) + if parent.UncleHash == types.EmptyUncleHash { + x.Sub(big1, x) + } else { + x.Sub(big2, x) + } + // max((2 if len(parent_uncles) else 1) - (block_timestamp - parent_timestamp) // 9, -99) + if x.Cmp(bigMinus99) < 0 { + x.Set(bigMinus99) + } + // parent_diff + (parent_diff / 2048 * max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99)) + y.Div(parent.Difficulty, params.DifficultyBoundDivisor) + x.Mul(y, x) + x.Add(parent.Difficulty, x) + + // minimum difficulty can ever be (before exponential factor) + if x.Cmp(params.MinimumDifficulty) < 0 { + x.Set(params.MinimumDifficulty) + } + // calculate a fake block number for the ice-age delay + // Specification: https://eips.ethereum.org/EIPS/eip-1234 + fakeBlockNumber := new(big.Int) + if parent.Number.Cmp(bombDelayFromParent) >= 0 { + fakeBlockNumber = fakeBlockNumber.Sub(parent.Number, bombDelayFromParent) + } + // for the exponential factor + periodCount := fakeBlockNumber + periodCount.Div(periodCount, expDiffPeriod) + + // the exponential factor, commonly referred to as "the bomb" + // diff = diff + 2^(periodCount - 2) + if periodCount.Cmp(big1) > 0 { + y.Sub(periodCount, big2) + y.Exp(big2, y, nil) + x.Add(x, y) + } + return x + } +} + +// calcDifficultyHomestead is the difficulty adjustment algorithm. It returns +// the difficulty that a new block should have when created at time given the +// parent block's time and difficulty. The calculation uses the Homestead rules. +func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int { + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md + // algorithm: + // diff = (parent_diff + + // (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) + // ) + 2^(periodCount - 2) + + bigTime := new(big.Int).SetUint64(time) + bigParentTime := new(big.Int).SetUint64(parent.Time) + + // holds intermediate values to make the algo easier to read & audit + x := new(big.Int) + y := new(big.Int) + + // 1 - (block_timestamp - parent_timestamp) // 10 + x.Sub(bigTime, bigParentTime) + x.Div(x, big10) + x.Sub(big1, x) + + // max(1 - (block_timestamp - parent_timestamp) // 10, -99) + if x.Cmp(bigMinus99) < 0 { + x.Set(bigMinus99) + } + // (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) + y.Div(parent.Difficulty, params.DifficultyBoundDivisor) + x.Mul(y, x) + x.Add(parent.Difficulty, x) + + // minimum difficulty can ever be (before exponential factor) + if x.Cmp(params.MinimumDifficulty) < 0 { + x.Set(params.MinimumDifficulty) + } + // for the exponential factor + periodCount := new(big.Int).Add(parent.Number, big1) + periodCount.Div(periodCount, expDiffPeriod) + + // the exponential factor, commonly referred to as "the bomb" + // diff = diff + 2^(periodCount - 2) + if periodCount.Cmp(big1) > 0 { + y.Sub(periodCount, big2) + y.Exp(big2, y, nil) + x.Add(x, y) + } + return x +} + +// calcDifficultyFrontier is the difficulty adjustment algorithm. It returns the +// difficulty that a new block should have when created at time given the parent +// block's time and difficulty. The calculation uses the Frontier rules. +func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int { + diff := new(big.Int) + adjust := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor) + bigTime := new(big.Int) + bigParentTime := new(big.Int) + + bigTime.SetUint64(time) + bigParentTime.SetUint64(parent.Time) + + if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 { + diff.Add(parent.Difficulty, adjust) + } else { + diff.Sub(parent.Difficulty, adjust) + } + if diff.Cmp(params.MinimumDifficulty) < 0 { + diff.Set(params.MinimumDifficulty) + } + + periodCount := new(big.Int).Add(parent.Number, big1) + periodCount.Div(periodCount, expDiffPeriod) + if periodCount.Cmp(big1) > 0 { + // diff = diff + 2^(periodCount - 2) + expDiff := periodCount.Sub(periodCount, big2) + expDiff.Exp(big2, expDiff, nil) + diff.Add(diff, expDiff) + diff = math.BigMax(diff, params.MinimumDifficulty) + } + return diff +} diff --git a/minigeth/main.go b/minigeth/main.go index 2481ef760eeb0519063542957bae1cca3e7c365b..3f81d8e81cca83f9438194fd2f52937880fd0634 100644 --- a/minigeth/main.go +++ b/minigeth/main.go @@ -68,6 +68,8 @@ func main() { processor := core.NewStateProcessor(params.MainnetChainConfig, bc, bc.Engine()) fmt.Println("processing state:", parent.Number, "->", newheader.Number) + newheader.Difficulty = bc.Engine().CalcDifficulty(bc, newheader.Time, &parent) + // read txs //traverseStackTrie(newheader.TxHash) diff --git a/minigeth/oracle/prefetch.go b/minigeth/oracle/prefetch.go index 09e9f2c026e38acf661bc6afe547863cac41dfa6..78e231783bf5fe835db1a63ed322cbe166eca12f 100644 --- a/minigeth/oracle/prefetch.go +++ b/minigeth/oracle/prefetch.go @@ -197,7 +197,7 @@ func Output(output common.Hash) { if output == inputs[6] { fmt.Println("good transition") } else { - fmt.Println(output, "!=", inputs[5]) + fmt.Println(output, "!=", inputs[6]) panic("BAD transition :((") } } diff --git a/minigeth/oracle/preimage.go b/minigeth/oracle/preimage.go index 93c0ec140f0766f91a091b1555edcff5a4e6aae6..1dee38b6d8ab24696d73b2d85f259487a7751545 100644 --- a/minigeth/oracle/preimage.go +++ b/minigeth/oracle/preimage.go @@ -21,7 +21,7 @@ func Preimage(hash common.Hash) []byte { fmt.Println("can't find preimage", hash) } comphash := crypto.Keccak256Hash(val) - if hash != comphash { + if ok && hash != comphash { panic("corruption in hash " + hash.String()) } return val