diff --git a/simulators/ethereum/engine/client/node/node.go b/simulators/ethereum/engine/client/node/node.go index 87b92f4d27..7db6a552e6 100644 --- a/simulators/ethereum/engine/client/node/node.go +++ b/simulators/ethereum/engine/client/node/node.go @@ -48,7 +48,8 @@ type GethNodeTestConfiguration struct { PoWMinerEtherBase common.Address PoWRandomTransactions bool // Prepare the Ethash instance even if we don't mine (to seal blocks) - Ethash bool + Ethash bool + // Disable gossiping of newly mined blocks (peers need to sync to obtain the blocks) DisableGossiping bool // Block Modifier @@ -432,7 +433,7 @@ func (n *GethNode) PoWMiningLoop() { // Modify the block before sealing if n.config.BlockModifier != nil { - b, err = n.config.BlockModifier.ModifyUnsealedBlock(b) + b, err = n.config.BlockModifier.ModifyUnsealedBlock(n.eth.BlockChain(), s, b) if err != nil { panic(err) } diff --git a/simulators/ethereum/engine/helper/block.go b/simulators/ethereum/engine/helper/block.go index aa58ebd703..40037774bd 100644 --- a/simulators/ethereum/engine/helper/block.go +++ b/simulators/ethereum/engine/helper/block.go @@ -7,23 +7,32 @@ import ( "math/rand" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" ) type BlockModifier interface { - ModifyUnsealedBlock(*types.Block) (*types.Block, error) + ModifyUnsealedBlock(consensus.ChainHeaderReader, *state.StateDB, *types.Block) (*types.Block, error) ModifySealedBlock(func(*types.Header) bool, *types.Block) (*types.Block, error) } type PoWBlockModifier struct { - Difficulty *big.Int - RandomStateRoot bool + // Modify the difficulty of the block by a given amount, block will be correctly sealed + Difficulty *big.Int + // Increase the balance of a random account by 1 wei + BalanceIncrease bool + // Randomize the state root value + RandomStateRoot bool + // Invalidate the sealed mixHash of the block according to ethash consensus InvalidSealedMixHash bool - InvalidSealedNonce bool - TimeSecondsInFuture uint64 + // Invalidate the sealed nonce of the block according to ethash consensus + InvalidSealedNonce bool + // Modify the timestamp by a given amount of seconds + TimeSecondsInFuture uint64 } -func (m PoWBlockModifier) ModifyUnsealedBlock(baseBlock *types.Block) (*types.Block, error) { +func (m PoWBlockModifier) ModifyUnsealedBlock(chain consensus.ChainHeaderReader, state *state.StateDB, baseBlock *types.Block) (*types.Block, error) { modifiedHeader := types.CopyHeader(baseBlock.Header()) if m.Difficulty != nil { @@ -35,6 +44,12 @@ func (m PoWBlockModifier) ModifyUnsealedBlock(baseBlock *types.Block) (*types.Bl if m.TimeSecondsInFuture > 0 { modifiedHeader.Time += m.TimeSecondsInFuture } + if m.BalanceIncrease { + var acc common.Address + rand.Read(acc[:]) + state.AddBalance(acc, common.Big1) + modifiedHeader.Root = state.IntermediateRoot(chain.Config().IsEIP158(modifiedHeader.Number)) + } modifiedBlock := types.NewBlockWithHeader(modifiedHeader) modifiedBlock = modifiedBlock.WithBody(baseBlock.Transactions(), baseBlock.Uncles()) diff --git a/simulators/ethereum/engine/suites/transition/tests.go b/simulators/ethereum/engine/suites/transition/tests.go index 3ff82c5df4..dd836fc86b 100644 --- a/simulators/ethereum/engine/suites/transition/tests.go +++ b/simulators/ethereum/engine/suites/transition/tests.go @@ -648,6 +648,36 @@ var mergeTestSpecs = []MergeTestSpec{ }, }, }, + { + Name: "Syncing on an Invalid Terminal Execution - Difficulty", + TTD: 696608, + TimeoutSeconds: 30, + MainChainFile: "blocks_1_td_196608.rlp", + DisableMining: true, + SkipMainClientTTDWait: true, + TransitionPayloadStatusSync: test.Invalid, + SecondaryClientSpecs: []SecondaryClientSpec{ + { + ClientStarter: node.GethNodeEngineStarter{ + Config: node.GethNodeTestConfiguration{ + Name: "PoW Producer", + PoWMiner: true, + MaxPeers: big.NewInt(1), + BlockModifier: helper.PoWBlockModifier{ + Difficulty: big.NewInt(500000), + }, + // Mined blocks are not gossiped, peers have to sync + DisableGossiping: true, + }, + TerminalTotalDifficulty: big.NewInt(696608), + ChainFile: "blocks_1_td_196608.rlp", + }, + BuildPoSBlocksForSync: 1, + BuildPoSChainOnTop: true, + MainClientShallSync: false, + }, + }, + }, { Name: "Transition on an Invalid Terminal Execution - Distant Future", TTD: 290000, @@ -702,6 +732,36 @@ var mergeTestSpecs = []MergeTestSpec{ }, }, }, + { + Name: "Syncing on an Invalid Terminal Execution - Sealed MixHash", + TTD: 290000, + TimeoutSeconds: 30, + MainChainFile: "blocks_1_td_196608.rlp", + DisableMining: true, + SkipMainClientTTDWait: true, + TransitionPayloadStatusSync: test.Invalid, + SecondaryClientSpecs: []SecondaryClientSpec{ + { + ClientStarter: node.GethNodeEngineStarter{ + Config: node.GethNodeTestConfiguration{ + Name: "PoW Producer", + PoWMiner: true, + MaxPeers: big.NewInt(1), + BlockModifier: helper.PoWBlockModifier{ + InvalidSealedMixHash: true, + }, + // Mined blocks are not gossiped, peers have to sync + DisableGossiping: true, + }, + TerminalTotalDifficulty: big.NewInt(290000), + ChainFile: "blocks_1_td_196608.rlp", + }, + BuildPoSBlocksForSync: 1, + BuildPoSChainOnTop: true, + MainClientShallSync: false, + }, + }, + }, { Name: "Transition on an Invalid Terminal Execution - Sealed Nonce", TTD: 290000, @@ -729,6 +789,93 @@ var mergeTestSpecs = []MergeTestSpec{ }, }, }, + { + Name: "Syncing on an Invalid Terminal Execution - Sealed Nonce", + TTD: 290000, + TimeoutSeconds: 30, + MainChainFile: "blocks_1_td_196608.rlp", + DisableMining: true, + SkipMainClientTTDWait: true, + TransitionPayloadStatusSync: test.Invalid, + SecondaryClientSpecs: []SecondaryClientSpec{ + { + ClientStarter: node.GethNodeEngineStarter{ + Config: node.GethNodeTestConfiguration{ + Name: "PoW Producer", + PoWMiner: true, + MaxPeers: big.NewInt(1), + BlockModifier: helper.PoWBlockModifier{ + InvalidSealedNonce: true, + }, + // Mined blocks are not gossiped, peers have to sync + DisableGossiping: true, + }, + TerminalTotalDifficulty: big.NewInt(290000), + ChainFile: "blocks_1_td_196608.rlp", + }, + BuildPoSBlocksForSync: 1, + BuildPoSChainOnTop: true, + MainClientShallSync: false, + }, + }, + }, + { + Name: "Transition on an Invalid Terminal Execution - Balance Mismatch", + TTD: 290000, + TimeoutSeconds: 30, + MainChainFile: "blocks_1_td_196608.rlp", + DisableMining: true, + SkipMainClientTTDWait: true, + KeepCheckingUntilTimeout: true, + SecondaryClientSpecs: []SecondaryClientSpec{ + { + ClientStarter: node.GethNodeEngineStarter{ + Config: node.GethNodeTestConfiguration{ + Name: "PoW Producer", + PoWMiner: true, + MaxPeers: big.NewInt(1), + BlockModifier: helper.PoWBlockModifier{ + BalanceIncrease: true, + }, + }, + TerminalTotalDifficulty: big.NewInt(290000), + ChainFile: "blocks_1_td_196608.rlp", + }, + BuildPoSChainOnTop: true, + MainClientShallSync: false, + }, + }, + }, + { + Name: "Syncing on an Invalid Terminal Execution - Balance Mismatch", + TTD: 290000, + TimeoutSeconds: 30, + MainChainFile: "blocks_1_td_196608.rlp", + DisableMining: true, + SkipMainClientTTDWait: true, + TransitionPayloadStatusSync: test.Invalid, + SecondaryClientSpecs: []SecondaryClientSpec{ + { + ClientStarter: node.GethNodeEngineStarter{ + Config: node.GethNodeTestConfiguration{ + Name: "PoW Producer", + PoWMiner: true, + MaxPeers: big.NewInt(1), + BlockModifier: helper.PoWBlockModifier{ + BalanceIncrease: true, + }, + // Mined blocks are not gossiped, peers have to sync + DisableGossiping: true, + }, + TerminalTotalDifficulty: big.NewInt(290000), + ChainFile: "blocks_1_td_196608.rlp", + }, + BuildPoSBlocksForSync: 1, + BuildPoSChainOnTop: true, + MainClientShallSync: false, + }, + }, + }, } var Tests = func() []test.Spec {