diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index f35b28510c..5178c0d4df 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -160,6 +160,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, isEIP4762 = chainConfig.IsUBT(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp) isAmsterdam = chainConfig.IsAmsterdam(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp) + rules = chainConfig.Rules(big.NewInt(int64(pre.Env.Number)), pre.Env.Random != nil, pre.Env.Timestamp) ) if pre.AllocPath != "" { var err error @@ -308,7 +309,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, receipts = append(receipts, receipt) blockAccessList.Merge(bal) } - statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)) + statedb.IntermediateRoot(rules) // TODO(rjl493456442) call engine.Finalize() instead // Add mining reward? (-1 means rewards are disabled) @@ -369,7 +370,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, blockAccessList.Merge(bal) // Commit block - root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber), chainConfig.IsCancun(vmContext.BlockNumber, vmContext.Time)) + root, err := statedb.Commit(rules, vmContext.BlockNumber.Uint64()) if err != nil { return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) } @@ -455,7 +456,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, isBintrie bool } } // Commit and re-open to start with a clean state. - root, err = statedb.Commit(0, false, false) + root, err = statedb.Commit(params.Rules{}, 0) if err != nil { panic(fmt.Errorf("failed to commit initial state: %v", err)) } @@ -530,7 +531,7 @@ func MakePreStateStreaming(db ethdb.Database, allocPath string, isBintrie bool) return nil, NewError(ErrorJson, fmt.Errorf("failed reading alloc closing token: %v", err)) } - root, err = statedb.Commit(0, false, false) + root, err = statedb.Commit(params.Rules{}, 0) if err != nil { return nil, NewError(ErrorEVM, fmt.Errorf("failed to commit initial state: %v", err)) } diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 6c6667e409..5d6a627980 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -253,7 +253,7 @@ func Transition(ctx *cli.Context) error { return NewError(ErrorEVM, errors.New("UBT alloc recorder was not enabled")) } collector = Alloc(rec.Alloc()) - if err := mergeUnmigratedBaseAlloc(udb, s.IntermediateRoot(false), collector); err != nil { + if err := mergeUnmigratedBaseAlloc(udb, s.IntermediateRoot(params.Rules{}), collector); err != nil { return NewError(ErrorEVM, fmt.Errorf("failed to merge base MPT alloc: %v", err)) } } diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 2b77741738..5d33b56f00 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/params" "github.com/urfave/cli/v2" // Force-load the tracer engines to trigger registration @@ -340,7 +341,8 @@ func collectFiles(path string) []string { // dump returns a state dump for the most current trie. func dump(s *state.StateDB) *state.Dump { - root := s.IntermediateRoot(false) + // A dump is not a state transition: report accounts exactly as they are. + root := s.IntermediateRoot(params.Rules{}) cpy, _ := state.New(root, s.Database()) dump := cpy.RawDump(nil) return &dump diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 6d80056d04..e2923bce6e 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -339,7 +339,7 @@ func runCmd(ctx *cli.Context) error { output, stats, err := timedExec(bench, execFunc) if ctx.Bool(DumpFlag.Name) { - root, err := runtimeConfig.State.Commit(genesisConfig.Number, true, false) + root, err := runtimeConfig.State.Commit(params.Rules{IsEIP158: true}, genesisConfig.Number) if err != nil { fmt.Printf("Failed to commit changes %v\n", err) return err diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 1b0eb2ca2a..04341e98b3 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/internal/flags" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/tests" "github.com/urfave/cli/v2" ) @@ -132,7 +133,7 @@ func runStateTest(ctx *cli.Context, fname string) ([]testResult, error) { test.Run(st, cfg, false, rawdb.HashScheme, func(err error, state *tests.StateTestState) { var root common.Hash if state.StateDB != nil { - root = state.StateDB.IntermediateRoot(false) + root = state.StateDB.IntermediateRoot(params.Rules{}) result.Root = &root fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) // Dump any state to aid debugging. diff --git a/core/block_validator.go b/core/block_validator.go index 962fffb82a..bb43e51bb2 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -201,7 +201,8 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD } // Validate the state root against the received state root and throw // an error if they don't match. - if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { + rules := v.config.Rules(header.Number, header.Difficulty.Sign() == 0, header.Time) + if root := statedb.IntermediateRoot(rules); header.Root != root { return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error()) } return nil diff --git a/core/blockchain.go b/core/blockchain.go index 1bcdaa071b..54b8ddf447 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1665,12 +1665,11 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. var ( err error root common.Hash - isEIP158 = bc.chainConfig.IsEIP158(block.Number()) - isCancun = bc.chainConfig.IsCancun(block.Number(), block.Time()) hasStateHook = bc.logger != nil && bc.logger.OnStateUpdate != nil + rules = bc.chainConfig.Rules(block.Number(), block.Difficulty().Sign() == 0, block.Time()) ) if hasStateHook { - r, update, err := statedb.CommitWithUpdate(block.NumberU64(), isEIP158, isCancun) + r, update, err := statedb.CommitWithUpdate(rules, block.NumberU64()) if err != nil { return err } @@ -1681,7 +1680,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types. bc.logger.OnStateUpdate(trUpdate) root = r } else { - root, err = statedb.Commit(block.NumberU64(), isEIP158, isCancun) + root, err = statedb.Commit(rules, block.NumberU64()) if err != nil { return err } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 863e53474f..7820ee3d58 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -173,7 +173,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { blockchain.chainmu.MustLock() rawdb.WriteBlock(blockchain.db, block) - statedb.Commit(block.NumberU64(), false, false) + statedb.Commit(params.Rules{}, block.NumberU64()) blockchain.chainmu.Unlock() } return nil diff --git a/core/chain_makers.go b/core/chain_makers.go index aebc9eaa51..99c36b5366 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -356,7 +356,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse genblock := func(i int, parent *types.Block, triedb *triedb.Database, statedb *state.StateDB) (*types.Block, types.Receipts) { b := &BlockGen{i: i, cm: cm, parent: parent, statedb: statedb, engine: engine} - b.header = cm.makeHeader(parent, statedb, b.engine) + b.header = cm.makeHeader(parent, b.engine) b.bal = bal.NewConstructionBlockAccessList() // Set the difficulty for clique block. The chain maker doesn't have access @@ -441,7 +441,8 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse block := AssembleBlock(cm, b.header, statedb, &body, b.receipts, b.bal) // Write state changes to db - root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number), config.IsCancun(b.header.Number, b.header.Time)) + rules := config.Rules(b.header.Number, b.header.Difficulty.Sign() == 0, b.header.Time) + root, err := statedb.Commit(rules, b.header.Number.Uint64()) if err != nil { panic(fmt.Sprintf("state write error: %v", err)) } @@ -452,7 +453,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse } // Forcibly use hash-based state scheme for retaining all nodes in disk. - var triedbConfig *triedb.Config = triedb.HashDefaults + var triedbConfig = triedb.HashDefaults if config.IsUBT(config.ChainID, 0) { triedbConfig = triedb.UBTDefaults } @@ -516,11 +517,10 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, return db, blocks, receipts } -func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header { +func (cm *chainMaker) makeHeader(parent *types.Block, engine consensus.Engine) *types.Header { time := parent.Time() + 10 // block time is fixed at 10 seconds parentHeader := parent.Header() header := &types.Header{ - Root: state.IntermediateRoot(cm.config.IsEIP158(parent.Number())), ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), Difficulty: engine.CalcDifficulty(cm, time, parentHeader), @@ -528,7 +528,6 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi Number: new(big.Int).Add(parent.Number(), common.Big1), Time: time, } - if cm.config.IsLondon(header.Number) { header.BaseFee = eip1559.CalcBaseFee(cm.config, parentHeader) if !cm.config.IsLondon(parent.Number()) { diff --git a/core/eip7928_test.go b/core/eip7928_test.go index 3f53fcecc9..3f36060eec 100644 --- a/core/eip7928_test.go +++ b/core/eip7928_test.go @@ -133,7 +133,7 @@ func assertParallelEquiv(t *testing.T, gspec *Genesis, engine consensus.Engine, if err != nil { t.Fatalf("parallel process: %v", err) } - parRoot := parState.IntermediateRoot(gspec.Config.IsEIP158(block.Number())) + parRoot := parState.IntermediateRoot(gspec.Config.Rules(block.Number(), block.Difficulty().Sign() == 0, block.Time())) // Sequential path, forced explicitly via DisableParallelExecution. seqState, err := bc.State() diff --git a/core/eip8037_test.go b/core/eip8037_test.go index 8dc99d7aa6..a0b9cc6ee9 100644 --- a/core/eip8037_test.go +++ b/core/eip8037_test.go @@ -71,7 +71,7 @@ func mkState(alloc types.GenesisAlloc) *state.StateDB { sdb.SetState(addr, k, v) } } - sdb.Finalise(true) + sdb.Finalise(params.Rules{IsEIP158: true}) return sdb } @@ -98,7 +98,7 @@ func mkCommittedState(t *testing.T, alloc types.GenesisAlloc) *state.StateDB { sdb.SetState(addr, k, v) } } - root, err := sdb.Commit(0, false, false) + root, err := sdb.Commit(params.Rules{}, 0) if err != nil { t.Fatalf("commit prestate: %v", err) } diff --git a/core/genesis.go b/core/genesis.go index 4073d0f86c..2cc3312f02 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -148,6 +148,7 @@ func hashAlloc(ga *types.GenesisAlloc, isUBT bool) (common.Hash, error) { emptyRoot = types.EmptyBinaryHash } db := rawdb.NewMemoryDatabase() + statedb, err := state.New(emptyRoot, state.NewDatabase(triedb.NewDatabase(db, config), nil)) if err != nil { return common.Hash{}, err @@ -162,7 +163,7 @@ func hashAlloc(ga *types.GenesisAlloc, isUBT bool) (common.Hash, error) { statedb.SetState(addr, key, value) } } - return statedb.Commit(0, false, false) + return statedb.Commit(params.Rules{}, 0) } // flushAlloc is very similar with hash, but the main difference is all the @@ -191,7 +192,7 @@ func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database, tracer *tracing var root common.Hash if tracer != nil && tracer.OnStateUpdate != nil { - r, update, err := statedb.CommitWithUpdate(0, false, false) + r, update, err := statedb.CommitWithUpdate(params.Rules{}, 0) if err != nil { return common.Hash{}, err } @@ -202,7 +203,7 @@ func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database, tracer *tracing tracer.OnStateUpdate(trUpdate) root = r } else { - root, err = statedb.Commit(0, false, false) + root, err = statedb.Commit(params.Rules{}, 0) if err != nil { return common.Hash{}, err } diff --git a/core/state/state_test.go b/core/state/state_test.go index eeeb7fa2df..1640be880a 100644 --- a/core/state/state_test.go +++ b/core/state/state_test.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" "github.com/holiman/uint256" ) @@ -54,7 +55,7 @@ func TestDump(t *testing.T) { obj3.SetBalance(uint256.NewInt(44)) // write some of them to the trie - root, _ := s.state.Commit(0, false, false) + root, _ := s.state.Commit(params.Rules{}, 0) // check that DumpToCollector contains the state objects that are in trie s.state, _ = New(root, tdb) @@ -112,7 +113,7 @@ func TestIterativeDump(t *testing.T) { obj4.AddBalance(uint256.NewInt(1337)) // write some of them to the trie - root, _ := s.state.Commit(0, false, false) + root, _ := s.state.Commit(params.Rules{}, 0) s.state, _ = New(root, tdb) b := &bytes.Buffer{} @@ -138,7 +139,7 @@ func TestNull(t *testing.T) { var value common.Hash s.state.SetState(address, common.Hash{}, value) - s.state.Commit(0, false, false) + s.state.Commit(params.Rules{}, 0) if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) { t.Errorf("expected empty current value, got %x", value) diff --git a/core/state/statedb.go b/core/state/statedb.go index 3cc67cebee..8a65cb4028 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -776,9 +776,9 @@ func (s *StateDB) GetRefund() uint64 { // Finalise finalises the state by removing the destructed objects and clears // the journal as well as the refunds. Finalise, however, will not push any updates // into the tries just yet. Only IntermediateRoot or Commit will do that. -func (s *StateDB) Finalise(deleteEmptyObjects bool) *bal.ConstructionBlockAccessList { - if s.stateAccessList != nil { - return s.finaliseAmsterdam(deleteEmptyObjects) +func (s *StateDB) Finalise(rules params.Rules) *bal.ConstructionBlockAccessList { + if rules.IsAmsterdam { + return s.finaliseAmsterdam(rules) } addressesToPrefetch := make([]common.Address, 0, len(s.journal.mutations)) for addr := range s.journal.mutations { @@ -795,7 +795,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) *bal.ConstructionBlockAccess // finalise or delete, so ignore it here. continue } - if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) { + if obj.selfDestructed || (rules.IsEIP158 && obj.empty()) { delete(s.stateObjects, obj.address) s.markDelete(addr) @@ -817,12 +817,17 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) *bal.ConstructionBlockAccess } } // Invalidate journal because reverting across transactions is not allowed. - s.clearJournalAndRefund() + s.clearInternal() return nil } func (s *StateDB) recordAccessListChanges(addr common.Address, state *journalMutationState) { + // No list means we are outside a transaction scope (e.g, PostExecution + // without a preceding Prepare), skip BAL recording. + if s.stateAccessList == nil { + return + } var ( balance = uint256.NewInt(0) nonce uint64 @@ -849,7 +854,7 @@ func (s *StateDB) recordAccessListChanges(addr common.Address, state *journalMut } // finaliseAmsterdam is the Amsterdam-and-later variant of Finalise. -func (s *StateDB) finaliseAmsterdam(deleteEmptyObjects bool) *bal.ConstructionBlockAccessList { +func (s *StateDB) finaliseAmsterdam(rules params.Rules) *bal.ConstructionBlockAccessList { addressesToPrefetch := make([]common.Address, 0, len(s.journal.mutations)) for addr, state := range s.journal.mutations { obj, exist := s.stateObjects[addr] @@ -886,7 +891,7 @@ func (s *StateDB) finaliseAmsterdam(deleteEmptyObjects bool) *bal.ConstructionBl } } - case deleteEmptyObjects && obj.empty(): + case rules.IsEIP158 && obj.empty(): // EIP-161: a touched, empty account is removed. delete(s.stateObjects, obj.address) s.markDelete(addr) @@ -913,17 +918,17 @@ func (s *StateDB) finaliseAmsterdam(deleteEmptyObjects bool) *bal.ConstructionBl } } // Invalidate journal because reverting across transactions is not allowed. - s.clearJournalAndRefund() - - return s.stateAccessList + bal := s.stateAccessList + s.clearInternal() + return bal } // IntermediateRoot computes the current root hash of the state trie. // It is called in between transactions to get the root hash that // goes into transaction receipts. -func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { +func (s *StateDB) IntermediateRoot(rules params.Rules) common.Hash { // Finalise all the dirty storage states and write them into the tries - s.Finalise(deleteEmptyObjects) + s.Finalise(rules) // Initialize the trie if it's not constructed yet. If the prefetch // is enabled, the trie constructed below will be replaced by the @@ -1134,9 +1139,17 @@ func (s *StateDB) SetTxContext(thash common.Hash, ti int, blockAccessIndex uint3 s.blockAccessIndex = blockAccessIndex } -func (s *StateDB) clearJournalAndRefund() { +func (s *StateDB) clearInternal() { s.journal.reset() s.refund = 0 + + // The access list built during this scope has been handed off to the caller, + // which merges it into the block-level list by adopting the account objects + // rather than copying them. + // + // Dereferencing the accessList explicitly, avoiding any following mutations + // affecting the external BAL. + s.stateAccessList = nil } // deleteStorage is designed to delete the storage trie of a designated account. @@ -1204,7 +1217,7 @@ func (s *StateDB) deleteStorage(addrHash common.Hash, root common.Hash) (map[com // with their values be tracked as original value. // In case (d), **original** account along with its storages should be deleted, // with their values be tracked as original value. -func (s *StateDB) handleDestruction(noStorageWiping bool) (map[common.Hash]*AccountDelete, []*trienode.NodeSet, error) { +func (s *StateDB) handleDestruction(rules params.Rules) (map[common.Hash]*AccountDelete, []*trienode.NodeSet, error) { var ( nodes []*trienode.NodeSet deletes = make(map[common.Hash]*AccountDelete) @@ -1232,7 +1245,7 @@ func (s *StateDB) handleDestruction(noStorageWiping bool) (map[common.Hash]*Acco if prev.Root == types.EmptyRootHash || s.db.Type().Is(TypeUBT) { continue } - if noStorageWiping { + if rules.IsCancun { return nil, nil, fmt.Errorf("unexpected storage wiping, %x", addr) } // Remove storage slots belonging to the account. @@ -1256,13 +1269,13 @@ func (s *StateDB) GetTrie() Trie { // commit gathers the state mutations accumulated along with the associated // trie changes, resetting all internal flags with the new state as the base. -func (s *StateDB) commit(deleteEmptyObjects bool, noStorageWiping bool, blockNumber uint64) (*StateUpdate, error) { +func (s *StateDB) commit(rules params.Rules, blockNumber uint64) (*StateUpdate, error) { // Short circuit in case any database failure occurred earlier. if s.dbErr != nil { return nil, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) } // Finalize any pending changes and merge everything into the tries - root := s.IntermediateRoot(deleteEmptyObjects) + root := s.IntermediateRoot(rules) // Short circuit if any error occurs within the IntermediateRoot. if s.dbErr != nil { @@ -1310,7 +1323,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool, noStorageWiping bool, blockNum // the same block, account deletions must be processed first. This ensures // that the storage trie nodes deleted during destruction and recreated // during subsequent resurrection can be combined correctly. - deletes, delNodes, err := s.handleDestruction(noStorageWiping) + deletes, delNodes, err := s.handleDestruction(rules) if err != nil { return nil, err } @@ -1406,7 +1419,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool, noStorageWiping bool, blockNum s.originalRoot = root typ := StorageKeyHashed - if noStorageWiping { + if rules.IsCancun { typ = StorageKeyPlain } return NewStateUpdate(typ, origin, root, blockNumber, deletes, updates, nodes), nil @@ -1414,8 +1427,8 @@ func (s *StateDB) commit(deleteEmptyObjects bool, noStorageWiping bool, blockNum // commitAndFlush is a wrapper of commit which also commits the state mutations // to the configured data stores. -func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool, noStorageWiping bool, deriveCodeFields bool) (*StateUpdate, error) { - ret, err := s.commit(deleteEmptyObjects, noStorageWiping, block) +func (s *StateDB) commitAndFlush(rules params.Rules, block uint64, deriveCodeFields bool) (*StateUpdate, error) { + ret, err := s.commit(rules, block) if err != nil { return nil, err } @@ -1446,12 +1459,10 @@ func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool, noStorag // The associated block number of the state transition is also provided // for more chain context. // -// noStorageWiping is a flag indicating whether storage wiping is permitted. -// Since self-destruction was deprecated with the Cancun fork and there are -// no empty accounts left that could be deleted by EIP-158, storage wiping -// should not occur. -func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (common.Hash, error) { - ret, err := s.commitAndFlush(block, deleteEmptyObjects, noStorageWiping, false) +// Whether empty accounts are deleted and whether storage wiping is permitted +// both follow from the fork rules this state was created with. +func (s *StateDB) Commit(rules params.Rules, block uint64) (common.Hash, error) { + ret, err := s.commitAndFlush(rules, block, false) if err != nil { return common.Hash{}, err } @@ -1459,9 +1470,9 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool, noStorageWiping } // CommitWithUpdate writes the state mutations and returns the state update for -// external processing (e.g., live tracing hooks). -func (s *StateDB) CommitWithUpdate(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (common.Hash, *StateUpdate, error) { - ret, err := s.commitAndFlush(block, deleteEmptyObjects, noStorageWiping, true) +// external processing (e.g., live tracing hooks or size tracker). +func (s *StateDB) CommitWithUpdate(rules params.Rules, block uint64) (common.Hash, *StateUpdate, error) { + ret, err := s.commitAndFlush(rules, block, true) if err != nil { return common.Hash{}, nil, err } diff --git a/core/state/statedb_eip_7928_test.go b/core/state/statedb_eip_7928_test.go index d96aad8fde..37f5460e49 100644 --- a/core/state/statedb_eip_7928_test.go +++ b/core/state/statedb_eip_7928_test.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types/bal" + "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -49,7 +50,7 @@ func TestApplyBlockAccessListConcurrentPrefetch(t *testing.T) { base.SetCode(addr, code, tracing.CodeChangeUnspecified) base.SetState(addr, slot, common.HexToHash("0xaa")) } - root0, err := base.Commit(0, false, false) + root0, err := base.Commit(params.Rules{}, 0) if err != nil { t.Fatalf("commit base: %v", err) } @@ -63,7 +64,7 @@ func TestApplyBlockAccessListConcurrentPrefetch(t *testing.T) { } seq, _ := New(root0, db) mutate(seq) - wantRoot := seq.IntermediateRoot(true) + wantRoot := seq.IntermediateRoot(params.Rules{IsEIP158: true}) cb := bal.NewConstructionBlockAccessList() for i := range n { @@ -77,7 +78,7 @@ func TestApplyBlockAccessListConcurrentPrefetch(t *testing.T) { balState.StopPrefetcher() t.Fatalf("apply block access list: %v", err) } - gotRoot := balState.IntermediateRoot(true) + gotRoot := balState.IntermediateRoot(params.Rules{IsEIP158: true}) balState.StopPrefetcher() if gotRoot != wantRoot { @@ -113,7 +114,7 @@ func TestApplyBlockAccessListMatchesSequential(t *testing.T) { base.SetCode(contract, code, tracing.CodeChangeUnspecified) base.SetState(contract, slotA, common.HexToHash("0xaa")) base.SetState(contract, slotB, common.HexToHash("0xbb")) - root0, err := base.Commit(0, false, false) + root0, err := base.Commit(params.Rules{}, 0) if err != nil { t.Fatalf("commit base: %v", err) } @@ -131,7 +132,7 @@ func TestApplyBlockAccessListMatchesSequential(t *testing.T) { // Sequential reference root. seq, _ := New(root0, db) mutate(seq) - wantRoot := seq.IntermediateRoot(true) + wantRoot := seq.IntermediateRoot(params.Rules{IsEIP158: true}) if wantRoot == root0 { t.Fatal("mutations did not change the state root") } @@ -152,7 +153,7 @@ func TestApplyBlockAccessListMatchesSequential(t *testing.T) { balState.StopPrefetcher() t.Fatalf("apply block access list: %v", err) } - gotRoot := balState.IntermediateRoot(true) + gotRoot := balState.IntermediateRoot(params.Rules{IsEIP158: true}) balState.StopPrefetcher() if gotRoot != wantRoot { diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go index c796b416a3..29def3c91a 100644 --- a/core/state/statedb_fuzz_test.go +++ b/core/state/statedb_fuzz_test.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/triedb" @@ -217,19 +218,19 @@ func (test *stateTest) run() bool { for i, action := range actions { if i%test.chunk == 0 && i != 0 { if byzantium { - state.Finalise(true) // call finalise at the transaction boundary + state.Finalise(params.Rules{IsEIP158: true}) // call finalise at the transaction boundary } else { - state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary + state.IntermediateRoot(params.Rules{IsEIP158: true}) // call intermediateRoot at the transaction boundary } } action.fn(action, state) } if byzantium { - state.Finalise(true) // call finalise at the transaction boundary + state.Finalise(params.Rules{IsEIP158: true}) // call finalise at the transaction boundary } else { - state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary + state.IntermediateRoot(params.Rules{IsEIP158: true}) // call intermediateRoot at the transaction boundary } - ret, err := state.commitAndFlush(0, true, false, false) // call commit at the block boundary + ret, err := state.commitAndFlush(params.Rules{IsEIP158: true}, 0, false) // call commit at the block boundary if err != nil { panic(err) } diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go index 73e8253311..bebe21cdf1 100644 --- a/core/state/statedb_hooked.go +++ b/core/state/statedb_hooked.go @@ -230,10 +230,10 @@ func (s *hookedStateDB) AddLog(log *types.Log) { } } -func (s *hookedStateDB) Finalise(deleteEmptyObjects bool) *bal.ConstructionBlockAccessList { +func (s *hookedStateDB) Finalise(rules params.Rules) *bal.ConstructionBlockAccessList { if s.hooks.OnBalanceChange == nil && s.hooks.OnNonceChangeV2 == nil && s.hooks.OnNonceChange == nil && s.hooks.OnCodeChangeV2 == nil && s.hooks.OnCodeChange == nil { // Short circuit if no relevant hooks are set. - return s.inner.Finalise(deleteEmptyObjects) + return s.inner.Finalise(rules) } // Collect all self-destructed addresses first, then sort them to ensure @@ -255,7 +255,7 @@ func (s *hookedStateDB) Finalise(deleteEmptyObjects bool) *bal.ConstructionBlock // EIP-8246 (Amsterdam) removes the SELFDESTRUCT burn: a self-destructed // account that retains a non-zero balance is preserved as a balance-only // account rather than removed, so its balance is no longer burnt. - burnsBalance := s.inner.stateAccessList == nil + burnsBalance := !rules.IsAmsterdam for _, addr := range selfDestructedAddrs { obj := s.inner.stateObjects[addr] @@ -288,7 +288,7 @@ func (s *hookedStateDB) Finalise(deleteEmptyObjects bool) *bal.ConstructionBlock s.hooks.OnCodeChange(addr, prevCodeHash, s.inner.GetCode(addr), types.EmptyCodeHash, nil) } } - return s.inner.Finalise(deleteEmptyObjects) + return s.inner.Finalise(rules) } func (s *hookedStateDB) SetTxContext(thash common.Hash, ti int, blockAccessIndex uint32) { diff --git a/core/state/statedb_hooked_test.go b/core/state/statedb_hooked_test.go index fad234f848..76bd683d59 100644 --- a/core/state/statedb_hooked_test.go +++ b/core/state/statedb_hooked_test.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -66,14 +67,14 @@ func TestBurn(t *testing.T) { createAndDestroy(addB) hooked.AddBalance(addA, uint256.NewInt(200), tracing.BalanceChangeUnspecified) hooked.AddBalance(addB, uint256.NewInt(200), tracing.BalanceChangeUnspecified) - hooked.Finalise(true) + hooked.Finalise(params.Rules{IsEIP158: true}) // Tx 2: create and destroy address C, then commit createAndDestroy(addC) hooked.AddBalance(addC, uint256.NewInt(200), tracing.BalanceChangeUnspecified) - hooked.Finalise(true) + hooked.Finalise(params.Rules{IsEIP158: true}) - s.Commit(0, false, false) + s.Commit(params.Rules{}, 0) if have, want := burned, uint256.NewInt(600); !have.Eq(want) { t.Fatalf("burn-count wrong, have %v want %v", have, want) } @@ -160,7 +161,7 @@ func TestHooks_OnCodeChangeV2(t *testing.T) { sdb.SetCode(common.Address{0xbb}, []byte{0x13, 38}, tracing.CodeChangeContractCreation) sdb.CreateContract(common.Address{0xbb}) sdb.SelfDestruct(common.Address{0xbb}) - sdb.Finalise(true) + sdb.Finalise(params.Rules{IsEIP158: true}) if len(result) != len(wants) { t.Fatalf("number of tracing events wrong, have %d want %d", len(result), len(wants)) diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index 6f4282054e..8aa412b51e 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" @@ -70,7 +71,7 @@ func TestUpdateLeaks(t *testing.T) { } } - root := state.IntermediateRoot(false) + root := state.IntermediateRoot(params.Rules{}) if err := tdb.Commit(root, false); err != nil { t.Errorf("can not commit trie %v to persistent database", root.Hex()) } @@ -111,7 +112,7 @@ func TestIntermediateLeaks(t *testing.T) { modify(transState, common.Address{i}, i, 0) } // Write modifications to trie. - transState.IntermediateRoot(false) + transState.IntermediateRoot(params.Rules{}) // Overwrite all the data with new values in the transient database. for i := byte(0); i < 255; i++ { @@ -120,7 +121,7 @@ func TestIntermediateLeaks(t *testing.T) { } // Commit and cross check the databases. - transRoot, err := transState.Commit(0, false, false) + transRoot, err := transState.Commit(params.Rules{}, 0) if err != nil { t.Fatalf("failed to commit transition state: %v", err) } @@ -128,7 +129,7 @@ func TestIntermediateLeaks(t *testing.T) { t.Errorf("can not commit trie %v to persistent database", transRoot.Hex()) } - finalRoot, err := finalState.Commit(0, false, false) + finalRoot, err := finalState.Commit(params.Rules{}, 0) if err != nil { t.Fatalf("failed to commit final state: %v", err) } @@ -173,7 +174,7 @@ func TestCopy(t *testing.T) { obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i})) obj.AddBalance(uint256.NewInt(uint64(i))) } - orig.Finalise(false) + orig.Finalise(params.Rules{}) // Copy the state copy := orig.Copy() @@ -195,7 +196,7 @@ func TestCopy(t *testing.T) { // Finalise the changes on all concurrently finalise := func(wg *sync.WaitGroup, db *StateDB) { defer wg.Done() - db.Finalise(true) + db.Finalise(params.Rules{IsEIP158: true}) } var wg sync.WaitGroup @@ -235,7 +236,7 @@ func TestCopyWithDirtyJournal(t *testing.T) { obj.AddBalance(uint256.NewInt(uint64(i))) obj.data.Root = common.HexToHash("0xdeadbeef") } - root, _ := orig.Commit(0, true, false) + root, _ := orig.Commit(params.Rules{IsEIP158: true}, 0) orig, _ = New(root, db) // modify all in memory without finalizing @@ -246,21 +247,21 @@ func TestCopyWithDirtyJournal(t *testing.T) { } cpy := orig.Copy() - orig.Finalise(true) + orig.Finalise(params.Rules{IsEIP158: true}) for i := byte(0); i < 255; i++ { balance := orig.GetBalance(common.BytesToAddress([]byte{i})) if !balance.IsZero() { t.Errorf("Unexpected balance %x", root) } } - cpy.Finalise(true) + cpy.Finalise(params.Rules{IsEIP158: true}) for i := byte(0); i < 255; i++ { balance := cpy.GetBalance(common.BytesToAddress([]byte{i})) if !balance.IsZero() { t.Errorf("Unexpected balance %x", root) } } - if cpy.IntermediateRoot(true) != orig.IntermediateRoot(true) { + if cpy.IntermediateRoot(params.Rules{IsEIP158: true}) != orig.IntermediateRoot(params.Rules{IsEIP158: true}) { t.Error("State is not equal after copy") } } @@ -278,14 +279,14 @@ func TestCopyObjectState(t *testing.T) { obj.AddBalance(uint256.NewInt(uint64(i))) obj.data.Root = common.HexToHash("0xdeadbeef") } - orig.Finalise(true) + orig.Finalise(params.Rules{IsEIP158: true}) cpy := orig.Copy() for _, op := range cpy.mutations { if have, want := op.applied, false; have != want { t.Fatalf("Error in test itself, the 'done' flag should not be set before Commit, have %v want %v", have, want) } } - orig.Commit(0, true, false) + orig.Commit(params.Rules{IsEIP158: true}, 0) for _, op := range cpy.mutations { if have, want := op.applied, false; have != want { t.Fatalf("Error: original state affected copy, have %v want %v", have, want) @@ -690,7 +691,7 @@ func equalMutationSets(a, b map[common.Address]*journalMutationState) bool { func TestTouchDelete(t *testing.T) { s := newStateEnv() s.state.getOrNewStateObject(common.Address{}) - root, _ := s.state.Commit(0, false, false) + root, _ := s.state.Commit(params.Rules{}, 0) s.state, _ = New(root, s.state.db) snapshot := s.state.Snapshot() @@ -820,7 +821,7 @@ func TestCopyCommitCopy(t *testing.T) { t.Fatalf("second copy committed storage slot mismatch: have %x, want %x", val, common.Hash{}) } // Commit state, ensure states can be loaded from disk - root, _ := state.Commit(0, false, false) + root, _ := state.Commit(params.Rules{}, 0) state, _ = New(root, tdb) if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42) @@ -934,11 +935,11 @@ func TestCommitCopy(t *testing.T) { if val := state.GetCommittedState(addr, skey1); val != (common.Hash{}) { t.Fatalf("initial committed storage slot mismatch: have %x, want %x", val, common.Hash{}) } - root, _ := state.Commit(0, true, false) + root, _ := state.Commit(params.Rules{IsEIP158: true}, 0) state, _ = New(root, db) state.SetState(addr, skey2, sval2) - state.Commit(1, true, false) + state.Commit(params.Rules{IsEIP158: true}, 1) // Copy the committed state database, the copied one is not fully functional. copied := state.Copy() @@ -979,19 +980,19 @@ func TestDeleteCreateRevert(t *testing.T) { addr := common.BytesToAddress([]byte("so")) state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) - root, _ := state.Commit(0, false, false) + root, _ := state.Commit(params.Rules{}, 0) state, _ = New(root, state.db) // Simulate self-destructing in one transaction, then create-reverting in another state.SelfDestruct(addr) - state.Finalise(true) + state.Finalise(params.Rules{IsEIP158: true}) id := state.Snapshot() state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified) state.RevertToSnapshot(id) // Commit the entire state and make sure we don't crash and have the correct state - root, _ = state.Commit(0, true, false) + root, _ = state.Commit(params.Rules{IsEIP158: true}, 0) state, _ = New(root, state.db) if state.getStateObject(addr) != nil { @@ -1006,7 +1007,7 @@ func TestWitnessIncludesAbsentAccountReads(t *testing.T) { addr := common.Address{i + 1} state.SetBalance(addr, uint256.NewInt(uint64(i+1)), tracing.BalanceChangeUnspecified) } - root, err := state.Commit(0, false, false) + root, err := state.Commit(params.Rules{}, 0) if err != nil { t.Fatalf("failed to commit initial state: %v", err) } @@ -1027,7 +1028,7 @@ func TestWitnessIncludesAbsentAccountReads(t *testing.T) { if err := state.Error(); err != nil { t.Fatalf("unexpected state error after read: %v", err) } - if got := state.IntermediateRoot(false); got != root { + if got := state.IntermediateRoot(params.Rules{}); got != root { t.Fatalf("unexpected root after read-only access: have %x want %x", got, root) } if err := state.Error(); err != nil { @@ -1075,7 +1076,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) { a2 := common.BytesToAddress([]byte("another")) state.SetBalance(a2, uint256.NewInt(100), tracing.BalanceChangeUnspecified) state.SetCode(a2, []byte{1, 2, 4}, tracing.CodeChangeUnspecified) - root, _ = state.Commit(0, false, false) + root, _ = state.Commit(params.Rules{}, 0) t.Logf("root: %x", root) // force-flush tdb.Commit(root, false) @@ -1106,7 +1107,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) { } // Modify the state state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified) - root, err := state.Commit(0, false, false) + root, err := state.Commit(params.Rules{}, 0) if err == nil { t.Fatalf("expected error, got root :%x", root) } @@ -1297,7 +1298,7 @@ func TestFlushOrderDataLoss(t *testing.T) { state.SetState(common.Address{a}, common.Hash{a, s}, common.Hash{a, s}) } } - root, err := state.Commit(0, false, false) + root, err := state.Commit(params.Rules{}, 0) if err != nil { t.Fatalf("failed to commit state trie: %v", err) } @@ -1372,7 +1373,7 @@ func TestDeleteStorage(t *testing.T) { value := common.Hash(uint256.NewInt(uint64(10 * i)).Bytes32()) state.SetState(addr, slot, value) } - root, _ := state.Commit(0, true, false) + root, _ := state.Commit(params.Rules{IsEIP158: true}, 0) // Init phase done, create two states, one with snap and one without fastState, _ := New(root, NewMPTDatabase(tdb, nil).WithSnapshot(snaps)) slowState, _ := New(root, NewMPTDatabase(tdb, nil)) diff --git a/core/state/sync_test.go b/core/state/sync_test.go index e5e22deae5..f3bfd57891 100644 --- a/core/state/sync_test.go +++ b/core/state/sync_test.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/triedb" @@ -81,7 +82,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *triedb.Database, c } accounts = append(accounts, acc) } - root, _ := state.Commit(0, false, false) + root, _ := state.Commit(params.Rules{}, 0) // Return the generated state return db, sdb, nodeDb, root, accounts diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go index 8a03d93a08..977effed6e 100644 --- a/core/state/trie_prefetcher_test.go +++ b/core/state/trie_prefetcher_test.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/testrand" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/triedb" "github.com/holiman/uint256" ) @@ -83,7 +84,7 @@ func TestVerklePrefetcher(t *testing.T) { state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie state.SetCode(addr, []byte("hello"), tracing.CodeChangeUnspecified) // Change an external metadata state.SetState(addr, skey, sval) // Change the storage trie - root, _ := state.Commit(0, true, false) + root, _ := state.Commit(params.Rules{IsEIP158: true}, 0) state, _ = New(root, sdb) fetcher := newTriePrefetcher(sdb, root, "", false) diff --git a/core/state_processor.go b/core/state_processor.go index 43ee7f34e5..15ce6c9d99 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -232,9 +232,9 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, // Update the state with pending changes. var root []byte if evm.ChainConfig().IsByzantium(blockNumber) { - bal = evm.StateDB.Finalise(true) + bal = evm.StateDB.Finalise(evm.GetRules()) } else { - root = statedb.IntermediateRoot(evm.ChainConfig().IsEIP158(blockNumber)).Bytes() + root = statedb.IntermediateRoot(evm.GetRules()).Bytes() } // Merge the tx-local access event into the "block-local" one, in order to collect // all values, so that the witness can be built. @@ -337,7 +337,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM, blockAccessList if evm.StateDB.AccessEvents() != nil { evm.StateDB.AccessEvents().Merge(evm.AccessEvents) } - blockAccessList.Merge(evm.StateDB.Finalise(true)) + blockAccessList.Merge(evm.StateDB.Finalise(evm.GetRules())) } // ProcessParentBlockHash stores the parent block hash in the history storage contract @@ -370,7 +370,7 @@ func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM, blockAccessList * if evm.StateDB.AccessEvents() != nil { evm.StateDB.AccessEvents().Merge(evm.AccessEvents) } - blockAccessList.Merge(evm.StateDB.Finalise(true)) + blockAccessList.Merge(evm.StateDB.Finalise(evm.GetRules())) } // ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract. @@ -414,14 +414,14 @@ func processRequestsSystemCall(requests *[][]byte, rules params.Rules, evm *vm.E To: &addr, } evm.SetTxContext(NewEVMTxContext(msg)) - evm.StateDB.Prepare(rules, common.Address{}, common.Address{}, nil, nil, nil) + evm.StateDB.Prepare(evm.GetRules(), common.Address{}, common.Address{}, nil, nil, nil) evm.StateDB.SetTxContext(common.Hash{}, 0, blockAccessIndex) evm.StateDB.AddAddressToAccessList(addr) ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, gasBudget, common.U2560) if evm.StateDB.AccessEvents() != nil { evm.StateDB.AccessEvents().Merge(evm.AccessEvents) } - bal := evm.StateDB.Finalise(true) + bal := evm.StateDB.Finalise(evm.GetRules()) if err != nil { return fmt.Errorf("system call failed to execute: %v", err) } @@ -471,9 +471,10 @@ func onSystemCallStart(tracer *tracing.Hooks, ctx *tracing.VMContext) { // body and receipts. func AssembleBlock(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, blockAccessList *bal.ConstructionBlockAccessList) *types.Block { // Assign the post-transition state root - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + rules := chain.Config().Rules(header.Number, header.Difficulty.Sign() == 0, header.Time) + header.Root = state.IntermediateRoot(rules) - if !chain.Config().IsAmsterdam(header.Number, header.Time) { + if !rules.IsAmsterdam { return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)) } // Assign the BlockAccessListHash if Amsterdam has been enabled diff --git a/core/state_processor_parallel.go b/core/state_processor_parallel.go index 4df1899f2a..6b4df1af85 100644 --- a/core/state_processor_parallel.go +++ b/core/state_processor_parallel.go @@ -105,7 +105,6 @@ func (p *StateProcessor) processParallel(ctx context.Context, block *types.Block // blockAccessList is the access list rebuilt from the actual execution. blockAccessList = bal.NewConstructionBlockAccessList() ) - // Resolve the parent state root, the point all execution reads from. parent := p.chain.GetHeader(block.ParentHash(), block.NumberU64()-1) if parent == nil { @@ -135,7 +134,7 @@ func (p *StateProcessor) processParallel(ctx context.Context, block *types.Block stateApply = time.Since(start) start = time.Now() - statedb.IntermediateRoot(config.IsEIP158(header.Number)) + statedb.IntermediateRoot(config.Rules(header.Number, header.Difficulty.Sign() == 0, header.Time)) stateHash = time.Since(start) return statedb.Error() }) diff --git a/core/stateless.go b/core/stateless.go index 6c094248bd..0ca111c67d 100644 --- a/core/stateless.go +++ b/core/stateless.go @@ -77,6 +77,6 @@ func ExecuteStateless(ctx context.Context, config *params.ChainConfig, vmconfig } // Almost everything validated, but receipt and state root needs to be returned receiptRoot := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil)) - stateRoot := db.IntermediateRoot(config.IsEIP158(block.Number())) + stateRoot := db.IntermediateRoot(config.Rules(block.Number(), block.Difficulty().Sign() == 0, block.Time())) return stateRoot, receiptRoot, nil } diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index 56e018d175..84b5bb4522 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -727,7 +727,7 @@ func TestOpenDrops(t *testing.T) { statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000), tracing.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(duplicater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) statedb.AddBalance(crypto.PubkeyToAddress(repeater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) chain := &testBlockChain{ config: params.MainnetChainConfig, @@ -847,7 +847,7 @@ func TestOpenIndex(t *testing.T) { // Create a blob pool out of the pre-seeded data statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) chain := &testBlockChain{ config: params.MainnetChainConfig, @@ -948,7 +948,7 @@ func TestOpenHeap(t *testing.T) { statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) chain := &testBlockChain{ config: params.MainnetChainConfig, @@ -1030,7 +1030,7 @@ func TestOpenCap(t *testing.T) { statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) chain := &testBlockChain{ config: params.MainnetChainConfig, @@ -1116,7 +1116,7 @@ func TestChangingSlotterSize(t *testing.T) { statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) // Make custom chain config where the max blob count changes based on the loop variable. cancunTime := uint64(0) @@ -1219,7 +1219,7 @@ func TestBillyMigration(t *testing.T) { statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) // Make custom chain config where the max blob count changes based on the loop variable. zero := uint64(0) @@ -1316,7 +1316,7 @@ func TestLegacyTxConversion(t *testing.T) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) chain := &testBlockChain{ config: params.MainnetChainConfig, @@ -1390,7 +1390,7 @@ func TestLegacyLimboConversion(t *testing.T) { store.Close() statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) chain := &testBlockChain{ config: params.MainnetChainConfig, basefee: uint256.NewInt(params.InitialBaseFee), @@ -1445,7 +1445,7 @@ func TestBlobCountLimit(t *testing.T) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) // Make Prague-enabled custom chain config. cancunTime := uint64(0) @@ -1901,7 +1901,7 @@ func TestAdd(t *testing.T) { store.Put(blob) } } - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) store.Close() // Create a blob pool out of the pre-seeded dats @@ -2023,7 +2023,7 @@ func TestGetBlobs(t *testing.T) { statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) // Make custom chain config where the max blob count changes based on the loop variable. cancunTime := uint64(0) @@ -2307,7 +2307,7 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) { pooledTx, _ := newBlobTxForPool(tx) pool.AddPooledTx(pooledTx) } - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) defer pool.Close() // Benchmark assembling the pending @@ -2350,7 +2350,7 @@ func TestGetCells(t *testing.T) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) chain := &testBlockChain{ config: params.MainnetChainConfig, diff --git a/core/txpool/blobpool/cache_test.go b/core/txpool/blobpool/cache_test.go index ac780b06ca..4ddaca34f2 100644 --- a/core/txpool/blobpool/cache_test.go +++ b/core/txpool/blobpool/cache_test.go @@ -84,7 +84,7 @@ func newTestCache(t *testing.T, txConfig []txSpec) *testCache { for _, a := range addrs { statedb.AddBalance(a, uint256.NewInt(1_000_000_000_000), tracing.BalanceChangeUnspecified) } - statedb.Commit(0, true, false) + statedb.Commit(params.Rules{IsEIP158: true}, 0) cancunTime := uint64(0) config := ¶ms.ChainConfig{ diff --git a/core/vm/eip8037_test.go b/core/vm/eip8037_test.go index b8acb4c85c..c88d9dbbae 100644 --- a/core/vm/eip8037_test.go +++ b/core/vm/eip8037_test.go @@ -77,7 +77,7 @@ func run8037(t *testing.T, code []byte, gas GasBudget, value *uint256.Int, setup if setup != nil { setup(statedb, self) } - statedb.Finalise(true) + statedb.Finalise(params.Rules{IsEIP158: true}) ret, result, err := amsterdam8037EVM(statedb).Call(common.Address{}, self, nil, gas, value) assertBudgetSane(t, gas, result) return ret, result, err diff --git a/core/vm/eip8038_test.go b/core/vm/eip8038_test.go index 675c44263e..4d077e8018 100644 --- a/core/vm/eip8038_test.go +++ b/core/vm/eip8038_test.go @@ -43,7 +43,7 @@ func run8038(t *testing.T, code []byte, gas GasBudget, value *uint256.Int, setup if setup != nil { setup(statedb, self) } - statedb.Finalise(true) + statedb.Finalise(params.Rules{IsEIP158: true}) _, result, err := amsterdam8037EVM(statedb).Call(common.Address{}, self, nil, gas, value) return result, statedb.GetRefund(), err } diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index 4bf936d07d..71e9f6c1d9 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -90,7 +90,7 @@ func TestEIP2200(t *testing.T) { statedb.CreateAccount(address) statedb.SetCode(address, hexutil.MustDecode(tt.input), tracing.CodeChangeUnspecified) statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original})) - statedb.Finalise(true) // Push the state into the "original" slot + statedb.Finalise(params.Rules{IsEIP158: true}) // Push the state into the "original" slot vmctx := BlockContext{ CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true }, @@ -141,7 +141,7 @@ func TestCreateGas(t *testing.T) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.CreateAccount(address) statedb.SetCode(address, hexutil.MustDecode(tt.code), tracing.CodeChangeUnspecified) - statedb.Finalise(true) + statedb.Finalise(params.Rules{IsEIP158: true}) vmctx := BlockContext{ CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true }, Transfer: func(StateDB, common.Address, common.Address, *uint256.Int, *params.Rules) {}, diff --git a/core/vm/interface.go b/core/vm/interface.go index 4adee2451f..6fd1b4dcfe 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -99,6 +99,6 @@ type StateDB interface { AccessEvents() *state.AccessEvents // Finalise must be invoked at the end of a transaction - Finalise(bool) *bal.ConstructionBlockAccessList + Finalise(rules params.Rules) *bal.ConstructionBlockAccessList SetTxContext(thash common.Hash, ti int, blockAccessIndex uint32) } diff --git a/core/vm/interpreter_test.go b/core/vm/interpreter_test.go index 42530b83b7..33012d3f7b 100644 --- a/core/vm/interpreter_test.go +++ b/core/vm/interpreter_test.go @@ -47,7 +47,7 @@ func TestLoopInterrupt(t *testing.T) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb.CreateAccount(address) statedb.SetCode(address, common.Hex2Bytes(tt), tracing.CodeChangeUnspecified) - statedb.Finalise(true) + statedb.Finalise(params.Rules{IsEIP158: true}) evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{}) diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index b207a339f2..c841728ffd 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -131,7 +131,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { var ( address = common.BytesToAddress([]byte("contract")) vmenv = NewEnv(cfg) - rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) + rules = cfg.ChainConfig.Rules(cfg.BlockNumber, cfg.Random != nil, cfg.Time) ) if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) @@ -173,7 +173,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { } var ( vmenv = NewEnv(cfg) - rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) + rules = cfg.ChainConfig.Rules(cfg.BlockNumber, cfg.Random != nil, cfg.Time) ) if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) diff --git a/eth/api_debug_replay.go b/eth/api_debug_replay.go index 22c7106164..74b649eaaf 100644 --- a/eth/api_debug_replay.go +++ b/eth/api_debug_replay.go @@ -194,7 +194,7 @@ func (api *DebugAPI) replayBuild(ctx context.Context, block *types.Block, stated Withdrawals: block.Withdrawals(), } bc.Engine().Finalize(bc, header, statedb, &body, uint32(tcount+1), blockAL) - root := statedb.IntermediateRoot(config.IsEIP158(header.Number)) + root := statedb.IntermediateRoot(evm.GetRules()) return blockAL.ToEncodingObj(), receipts, gp.Used(), root, nil } diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index a3bb11d0bf..02681b49dd 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -134,7 +134,7 @@ func TestAccountRange(t *testing.T) { m[addr] = true } } - root, _ := sdb.Commit(0, true, false) + root, _ := sdb.Commit(params.Rules{IsEIP158: true}, 0) sdb, _ = state.New(root, statedb) trie, err := statedb.OpenTrie(root) @@ -192,7 +192,7 @@ func TestEmptyAccountRange(t *testing.T) { st, _ = state.New(types.EmptyRootHash, statedb) ) // Commit(although nothing to flush) and re-init the statedb - st.Commit(0, true, false) + st.Commit(params.Rules{IsEIP158: true}, 0) st, _ = state.New(types.EmptyRootHash, statedb) results := st.RawDump(&state.DumpConfig{ @@ -235,7 +235,7 @@ func TestStorageRangeAt(t *testing.T) { for _, entry := range storage { sdb.SetState(addr, *entry.Key, entry.Value) } - root, _ := sdb.Commit(0, false, false) + root, _ := sdb.Commit(params.Rules{}, 0) sdb, _ = state.New(root, db) // Check a few combinations of limit and start/end. diff --git a/eth/state_accessor.go b/eth/state_accessor.go index de28fbee8f..b31d5718c1 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -156,7 +156,8 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, base *st return nil, nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) } // Finalize the state so any modifications are written to the trie - root, err := statedb.Commit(current.NumberU64(), eth.blockchain.Config().IsEIP158(current.Number()), eth.blockchain.Config().IsCancun(current.Number(), current.Time())) + rules := eth.blockchain.Config().Rules(current.Number(), current.Difficulty().Sign() == 0, current.Time()) + root, err := statedb.Commit(rules, current.NumberU64()) if err != nil { return nil, nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w", current.NumberU64(), current.Root().Hex(), err) @@ -270,8 +271,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } // Ensure any modifications are committed to the state - // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) + statedb.Finalise(evm.GetRules()) } return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index d103b8ef35..014ea223a7 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -514,12 +514,12 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config defer release() var ( - roots []common.Hash - signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) - chainConfig = api.backend.ChainConfig() - vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) - evm = vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) + roots []common.Hash + signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) + chainConfig = api.backend.ChainConfig() + rules = chainConfig.Rules(block.Number(), block.Difficulty().Sign() == 0, block.Time()) + vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + evm = vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) ) defer evm.Release() // Run pre-execution system calls @@ -543,7 +543,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config } // Calling IntermediateRoot will internally call Finalize on the state // so any modifications are written to the trie - roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects)) + roots = append(roots, statedb.IntermediateRoot(rules)) } return roots, nil } @@ -687,8 +687,7 @@ txloop: break txloop } // Finalize the state so any modifications are written to the trie - // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) + statedb.Finalise(evm.GetRules()) } close(jobs) @@ -766,8 +765,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block return dumps, err } // Finalize the state so any modifications are written to the trie - // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) + statedb.Finalise(evm.GetRules()) continue } // The transaction should be traced. @@ -810,8 +808,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block return dumps, err } // Finalize the state so any modifications are written to the trie - // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(chainConfig.IsEIP158(block.Number())) + statedb.Finalise(evm.GetRules()) // If we've traced the transaction we were looking for, abort if tx.Hash() == txHash { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 932719bbed..79888b4933 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -191,7 +191,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block if _, err := core.ApplyMessage(evm, msg, nil); err != nil { return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } - statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) + statedb.Finalise(evm.GetRules()) } return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) } diff --git a/internal/ethapi/override/override.go b/internal/ethapi/override/override.go index 96ba77ab0a..eea1754ef2 100644 --- a/internal/ethapi/override/override.go +++ b/internal/ethapi/override/override.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -121,7 +122,7 @@ func (diff *StateOverride) Apply(statedb *state.StateDB, precompiles vm.Precompi // Now finalize the changes. Finalize is normally performed between transactions. // By using finalize, the overrides are semantically behaving as // if they were created in a transaction just before the tracing occur. - statedb.Finalise(false) + statedb.Finalise(params.Rules{}) return nil } diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 0da2672756..7e174551be 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -353,9 +353,9 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, // Update the state with pending changes. var root []byte if sim.chainConfig.IsByzantium(blockContext.BlockNumber) { - blockAccessList.Merge(tracingStateDB.Finalise(true)) + blockAccessList.Merge(tracingStateDB.Finalise(evm.GetRules())) } else { - root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes() + root = sim.state.IntermediateRoot(evm.GetRules()).Bytes() } receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, blockContext.Time, tx, gp.CumulativeUsed(), root) blobGasUsed += receipts[i].BlobGasUsed diff --git a/tests/state_test.go b/tests/state_test.go index 9b8aa61bc6..7080192043 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/params" ) func initMatcher(st *testMatcher) { @@ -135,7 +136,7 @@ func execStateTest(t *testing.T, st *testMatcher, test *StateTest) { var result error test.Run(subtest, vmconfig, true, rawdb.HashScheme, func(err error, state *StateTestState) { if state.Snapshots != nil && state.StateDB != nil { - if _, err := state.Snapshots.Journal(state.StateDB.IntermediateRoot(false)); err != nil { + if _, err := state.Snapshots.Journal(state.StateDB.IntermediateRoot(params.Rules{})); err != nil { result = err return } @@ -165,7 +166,7 @@ func execStateTest(t *testing.T, st *testMatcher, test *StateTest) { var result error test.Run(subtest, vmconfig, true, rawdb.PathScheme, func(err error, state *StateTestState) { if state.TrieDB != nil && state.StateDB != nil { - if err := state.TrieDB.Journal(state.StateDB.IntermediateRoot(false)); err != nil { + if err := state.TrieDB.Journal(state.StateDB.IntermediateRoot(params.Rules{})); err != nil { result = err return } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 6e1fd1b634..c2c59c384c 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -245,7 +245,9 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bo if err != nil { return fmt.Errorf("failed to get chain config: %w", err) } - root = st.StateDB.IntermediateRoot(config.IsEIP158(new(big.Int).SetUint64(t.json.Env.Number))) + number := new(big.Int).SetUint64(t.json.Env.Number) + isMerge := config.IsLondon(new(big.Int)) && t.json.Env.Random != nil + root = st.StateDB.IntermediateRoot(config.Rules(number, isMerge, t.json.Env.Timestamp)) if root != common.Hash(post.Root) { return fmt.Errorf("post-state root does not match the pre-state root, indicates an error in the test: got %x, want %x", root, post.Root) } @@ -275,6 +277,10 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh vmconfig.ExtraEips = eips block := t.genesis(config).ToBlock() + // The env's random is what makes the block post-merge; it is mirrored into the + // block context below. + isMerge := config.IsLondon(new(big.Int)) && t.json.Env.Random != nil + rules := config.Rules(block.Number(), isMerge, block.Time()) st = MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter, scheme) var baseFee *big.Int @@ -324,7 +330,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh if t.json.Env.Difficulty != nil { context.Difficulty = new(big.Int).Set(t.json.Env.Difficulty) } - if config.IsLondon(new(big.Int)) && t.json.Env.Random != nil { + if isMerge { rnd := common.BigToHash(t.json.Env.Random) context.Random = &rnd context.Difficulty = big.NewInt(0) @@ -360,7 +366,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh st.StateDB.AddBalance(block.Coinbase(), new(uint256.Int), tracing.BalanceChangeUnspecified) // Commit state mutations into database. - root, _ = st.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number()), config.IsCancun(block.Number(), block.Time())) + root, _ = st.StateDB.Commit(rules, block.NumberU64()) if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil { receipt := &types.Receipt{GasUsed: vmRet.UsedGas} tracer.OnTxEnd(receipt, nil) @@ -544,7 +550,8 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bo } } // Commit and re-open to start with a clean state. - root, _ := statedb.Commit(0, false, false) + // Materialising the alloc is not a fork-governed state transition. + root, _ := statedb.Commit(params.Rules{}, 0) // If snapshot is requested, initialize the snapshotter and use it in state. var snaps *snapshot.Tree