core/state: unset the block-level accessList in Finalise (#35498)
Some checks are pending
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Keeper Build (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run

This PR explicitly clears the referenced block access list at the end of
each transaction. This is essential because accounts are shadow-copied
into the global block access list, and it prevents accidental mutations
through stale references in StateDB.
This commit is contained in:
rjl493456442 2026-08-13 10:56:10 +08:00 committed by GitHub
parent 7924511bf6
commit 35fe1bf69c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
41 changed files with 196 additions and 168 deletions

View file

@ -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) isEIP4762 = chainConfig.IsUBT(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp)
isAmsterdam = chainConfig.IsAmsterdam(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 != "" { if pre.AllocPath != "" {
var err error var err error
@ -308,7 +309,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
receipts = append(receipts, receipt) receipts = append(receipts, receipt)
blockAccessList.Merge(bal) blockAccessList.Merge(bal)
} }
statedb.IntermediateRoot(chainConfig.IsEIP158(vmContext.BlockNumber)) statedb.IntermediateRoot(rules)
// TODO(rjl493456442) call engine.Finalize() instead // TODO(rjl493456442) call engine.Finalize() instead
// Add mining reward? (-1 means rewards are disabled) // 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) blockAccessList.Merge(bal)
// Commit block // 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 { if err != nil {
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not commit state: %v", err)) 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. // 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 { if err != nil {
panic(fmt.Errorf("failed to commit initial state: %v", err)) 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)) 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 { if err != nil {
return nil, NewError(ErrorEVM, fmt.Errorf("failed to commit initial state: %v", err)) return nil, NewError(ErrorEVM, fmt.Errorf("failed to commit initial state: %v", err))
} }

View file

@ -253,7 +253,7 @@ func Transition(ctx *cli.Context) error {
return NewError(ErrorEVM, errors.New("UBT alloc recorder was not enabled")) return NewError(ErrorEVM, errors.New("UBT alloc recorder was not enabled"))
} }
collector = Alloc(rec.Alloc()) 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)) return NewError(ErrorEVM, fmt.Errorf("failed to merge base MPT alloc: %v", err))
} }
} }

View file

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/params"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
// Force-load the tracer engines to trigger registration // 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. // dump returns a state dump for the most current trie.
func dump(s *state.StateDB) *state.Dump { 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()) cpy, _ := state.New(root, s.Database())
dump := cpy.RawDump(nil) dump := cpy.RawDump(nil)
return &dump return &dump

View file

@ -339,7 +339,7 @@ func runCmd(ctx *cli.Context) error {
output, stats, err := timedExec(bench, execFunc) output, stats, err := timedExec(bench, execFunc)
if ctx.Bool(DumpFlag.Name) { 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 { if err != nil {
fmt.Printf("Failed to commit changes %v\n", err) fmt.Printf("Failed to commit changes %v\n", err)
return err return err

View file

@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/internal/flags"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/tests" "github.com/ethereum/go-ethereum/tests"
"github.com/urfave/cli/v2" "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) { test.Run(st, cfg, false, rawdb.HashScheme, func(err error, state *tests.StateTestState) {
var root common.Hash var root common.Hash
if state.StateDB != nil { if state.StateDB != nil {
root = state.StateDB.IntermediateRoot(false) root = state.StateDB.IntermediateRoot(params.Rules{})
result.Root = &root result.Root = &root
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root) fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
// Dump any state to aid debugging. // Dump any state to aid debugging.

View file

@ -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 // Validate the state root against the received state root and throw
// an error if they don't match. // 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 fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error())
} }
return nil return nil

View file

@ -1665,12 +1665,11 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
var ( var (
err error err error
root common.Hash 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 hasStateHook = bc.logger != nil && bc.logger.OnStateUpdate != nil
rules = bc.chainConfig.Rules(block.Number(), block.Difficulty().Sign() == 0, block.Time())
) )
if hasStateHook { if hasStateHook {
r, update, err := statedb.CommitWithUpdate(block.NumberU64(), isEIP158, isCancun) r, update, err := statedb.CommitWithUpdate(rules, block.NumberU64())
if err != nil { if err != nil {
return err return err
} }
@ -1681,7 +1680,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
bc.logger.OnStateUpdate(trUpdate) bc.logger.OnStateUpdate(trUpdate)
root = r root = r
} else { } else {
root, err = statedb.Commit(block.NumberU64(), isEIP158, isCancun) root, err = statedb.Commit(rules, block.NumberU64())
if err != nil { if err != nil {
return err return err
} }

View file

@ -173,7 +173,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
blockchain.chainmu.MustLock() blockchain.chainmu.MustLock()
rawdb.WriteBlock(blockchain.db, block) rawdb.WriteBlock(blockchain.db, block)
statedb.Commit(block.NumberU64(), false, false) statedb.Commit(params.Rules{}, block.NumberU64())
blockchain.chainmu.Unlock() blockchain.chainmu.Unlock()
} }
return nil return nil

View file

@ -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) { 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 := &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() b.bal = bal.NewConstructionBlockAccessList()
// Set the difficulty for clique block. The chain maker doesn't have access // 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) block := AssembleBlock(cm, b.header, statedb, &body, b.receipts, b.bal)
// Write state changes to db // 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 { if err != nil {
panic(fmt.Sprintf("state write error: %v", err)) 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. // 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) { if config.IsUBT(config.ChainID, 0) {
triedbConfig = triedb.UBTDefaults triedbConfig = triedb.UBTDefaults
} }
@ -516,11 +517,10 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int,
return db, blocks, receipts 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 time := parent.Time() + 10 // block time is fixed at 10 seconds
parentHeader := parent.Header() parentHeader := parent.Header()
header := &types.Header{ header := &types.Header{
Root: state.IntermediateRoot(cm.config.IsEIP158(parent.Number())),
ParentHash: parent.Hash(), ParentHash: parent.Hash(),
Coinbase: parent.Coinbase(), Coinbase: parent.Coinbase(),
Difficulty: engine.CalcDifficulty(cm, time, parentHeader), 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), Number: new(big.Int).Add(parent.Number(), common.Big1),
Time: time, Time: time,
} }
if cm.config.IsLondon(header.Number) { if cm.config.IsLondon(header.Number) {
header.BaseFee = eip1559.CalcBaseFee(cm.config, parentHeader) header.BaseFee = eip1559.CalcBaseFee(cm.config, parentHeader)
if !cm.config.IsLondon(parent.Number()) { if !cm.config.IsLondon(parent.Number()) {

View file

@ -133,7 +133,7 @@ func assertParallelEquiv(t *testing.T, gspec *Genesis, engine consensus.Engine,
if err != nil { if err != nil {
t.Fatalf("parallel process: %v", err) 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. // Sequential path, forced explicitly via DisableParallelExecution.
seqState, err := bc.State() seqState, err := bc.State()

View file

@ -71,7 +71,7 @@ func mkState(alloc types.GenesisAlloc) *state.StateDB {
sdb.SetState(addr, k, v) sdb.SetState(addr, k, v)
} }
} }
sdb.Finalise(true) sdb.Finalise(params.Rules{IsEIP158: true})
return sdb return sdb
} }
@ -98,7 +98,7 @@ func mkCommittedState(t *testing.T, alloc types.GenesisAlloc) *state.StateDB {
sdb.SetState(addr, k, v) sdb.SetState(addr, k, v)
} }
} }
root, err := sdb.Commit(0, false, false) root, err := sdb.Commit(params.Rules{}, 0)
if err != nil { if err != nil {
t.Fatalf("commit prestate: %v", err) t.Fatalf("commit prestate: %v", err)
} }

View file

@ -148,6 +148,7 @@ func hashAlloc(ga *types.GenesisAlloc, isUBT bool) (common.Hash, error) {
emptyRoot = types.EmptyBinaryHash emptyRoot = types.EmptyBinaryHash
} }
db := rawdb.NewMemoryDatabase() db := rawdb.NewMemoryDatabase()
statedb, err := state.New(emptyRoot, state.NewDatabase(triedb.NewDatabase(db, config), nil)) statedb, err := state.New(emptyRoot, state.NewDatabase(triedb.NewDatabase(db, config), nil))
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
@ -162,7 +163,7 @@ func hashAlloc(ga *types.GenesisAlloc, isUBT bool) (common.Hash, error) {
statedb.SetState(addr, key, value) 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 // 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 var root common.Hash
if tracer != nil && tracer.OnStateUpdate != nil { 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 { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
@ -202,7 +203,7 @@ func flushAlloc(ga *types.GenesisAlloc, triedb *triedb.Database, tracer *tracing
tracer.OnStateUpdate(trUpdate) tracer.OnStateUpdate(trUpdate)
root = r root = r
} else { } else {
root, err = statedb.Commit(0, false, false) root, err = statedb.Commit(params.Rules{}, 0)
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }

View file

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb"
"github.com/holiman/uint256" "github.com/holiman/uint256"
) )
@ -54,7 +55,7 @@ func TestDump(t *testing.T) {
obj3.SetBalance(uint256.NewInt(44)) obj3.SetBalance(uint256.NewInt(44))
// write some of them to the trie // 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 // check that DumpToCollector contains the state objects that are in trie
s.state, _ = New(root, tdb) s.state, _ = New(root, tdb)
@ -112,7 +113,7 @@ func TestIterativeDump(t *testing.T) {
obj4.AddBalance(uint256.NewInt(1337)) obj4.AddBalance(uint256.NewInt(1337))
// write some of them to the trie // 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) s.state, _ = New(root, tdb)
b := &bytes.Buffer{} b := &bytes.Buffer{}
@ -138,7 +139,7 @@ func TestNull(t *testing.T) {
var value common.Hash var value common.Hash
s.state.SetState(address, common.Hash{}, value) 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{}) { if value := s.state.GetState(address, common.Hash{}); value != (common.Hash{}) {
t.Errorf("expected empty current value, got %x", value) t.Errorf("expected empty current value, got %x", value)

View file

@ -776,9 +776,9 @@ func (s *StateDB) GetRefund() uint64 {
// Finalise finalises the state by removing the destructed objects and clears // 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 // 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. // into the tries just yet. Only IntermediateRoot or Commit will do that.
func (s *StateDB) Finalise(deleteEmptyObjects bool) *bal.ConstructionBlockAccessList { func (s *StateDB) Finalise(rules params.Rules) *bal.ConstructionBlockAccessList {
if s.stateAccessList != nil { if rules.IsAmsterdam {
return s.finaliseAmsterdam(deleteEmptyObjects) return s.finaliseAmsterdam(rules)
} }
addressesToPrefetch := make([]common.Address, 0, len(s.journal.mutations)) addressesToPrefetch := make([]common.Address, 0, len(s.journal.mutations))
for addr := range 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. // finalise or delete, so ignore it here.
continue continue
} }
if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) { if obj.selfDestructed || (rules.IsEIP158 && obj.empty()) {
delete(s.stateObjects, obj.address) delete(s.stateObjects, obj.address)
s.markDelete(addr) s.markDelete(addr)
@ -817,12 +817,17 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) *bal.ConstructionBlockAccess
} }
} }
// Invalidate journal because reverting across transactions is not allowed. // Invalidate journal because reverting across transactions is not allowed.
s.clearJournalAndRefund() s.clearInternal()
return nil return nil
} }
func (s *StateDB) recordAccessListChanges(addr common.Address, state *journalMutationState) { 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 ( var (
balance = uint256.NewInt(0) balance = uint256.NewInt(0)
nonce uint64 nonce uint64
@ -849,7 +854,7 @@ func (s *StateDB) recordAccessListChanges(addr common.Address, state *journalMut
} }
// finaliseAmsterdam is the Amsterdam-and-later variant of Finalise. // 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)) addressesToPrefetch := make([]common.Address, 0, len(s.journal.mutations))
for addr, state := range s.journal.mutations { for addr, state := range s.journal.mutations {
obj, exist := s.stateObjects[addr] 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. // EIP-161: a touched, empty account is removed.
delete(s.stateObjects, obj.address) delete(s.stateObjects, obj.address)
s.markDelete(addr) s.markDelete(addr)
@ -913,17 +918,17 @@ func (s *StateDB) finaliseAmsterdam(deleteEmptyObjects bool) *bal.ConstructionBl
} }
} }
// Invalidate journal because reverting across transactions is not allowed. // Invalidate journal because reverting across transactions is not allowed.
s.clearJournalAndRefund() bal := s.stateAccessList
s.clearInternal()
return s.stateAccessList return bal
} }
// IntermediateRoot computes the current root hash of the state trie. // IntermediateRoot computes the current root hash of the state trie.
// It is called in between transactions to get the root hash that // It is called in between transactions to get the root hash that
// goes into transaction receipts. // 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 // 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 // Initialize the trie if it's not constructed yet. If the prefetch
// is enabled, the trie constructed below will be replaced by the // 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 s.blockAccessIndex = blockAccessIndex
} }
func (s *StateDB) clearJournalAndRefund() { func (s *StateDB) clearInternal() {
s.journal.reset() s.journal.reset()
s.refund = 0 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. // 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. // with their values be tracked as original value.
// In case (d), **original** account along with its storages should be deleted, // In case (d), **original** account along with its storages should be deleted,
// with their values be tracked as original value. // 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 ( var (
nodes []*trienode.NodeSet nodes []*trienode.NodeSet
deletes = make(map[common.Hash]*AccountDelete) 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) { if prev.Root == types.EmptyRootHash || s.db.Type().Is(TypeUBT) {
continue continue
} }
if noStorageWiping { if rules.IsCancun {
return nil, nil, fmt.Errorf("unexpected storage wiping, %x", addr) return nil, nil, fmt.Errorf("unexpected storage wiping, %x", addr)
} }
// Remove storage slots belonging to the account. // 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 // commit gathers the state mutations accumulated along with the associated
// trie changes, resetting all internal flags with the new state as the base. // 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. // Short circuit in case any database failure occurred earlier.
if s.dbErr != nil { if s.dbErr != nil {
return nil, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) return nil, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr)
} }
// Finalize any pending changes and merge everything into the tries // 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. // Short circuit if any error occurs within the IntermediateRoot.
if s.dbErr != nil { 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 // the same block, account deletions must be processed first. This ensures
// that the storage trie nodes deleted during destruction and recreated // that the storage trie nodes deleted during destruction and recreated
// during subsequent resurrection can be combined correctly. // during subsequent resurrection can be combined correctly.
deletes, delNodes, err := s.handleDestruction(noStorageWiping) deletes, delNodes, err := s.handleDestruction(rules)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1406,7 +1419,7 @@ func (s *StateDB) commit(deleteEmptyObjects bool, noStorageWiping bool, blockNum
s.originalRoot = root s.originalRoot = root
typ := StorageKeyHashed typ := StorageKeyHashed
if noStorageWiping { if rules.IsCancun {
typ = StorageKeyPlain typ = StorageKeyPlain
} }
return NewStateUpdate(typ, origin, root, blockNumber, deletes, updates, nodes), nil 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 // commitAndFlush is a wrapper of commit which also commits the state mutations
// to the configured data stores. // to the configured data stores.
func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool, noStorageWiping bool, deriveCodeFields bool) (*StateUpdate, error) { func (s *StateDB) commitAndFlush(rules params.Rules, block uint64, deriveCodeFields bool) (*StateUpdate, error) {
ret, err := s.commit(deleteEmptyObjects, noStorageWiping, block) ret, err := s.commit(rules, block)
if err != nil { if err != nil {
return nil, err 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 // The associated block number of the state transition is also provided
// for more chain context. // for more chain context.
// //
// noStorageWiping is a flag indicating whether storage wiping is permitted. // Whether empty accounts are deleted and whether storage wiping is permitted
// Since self-destruction was deprecated with the Cancun fork and there are // both follow from the fork rules this state was created with.
// no empty accounts left that could be deleted by EIP-158, storage wiping func (s *StateDB) Commit(rules params.Rules, block uint64) (common.Hash, error) {
// should not occur. ret, err := s.commitAndFlush(rules, block, false)
func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (common.Hash, error) {
ret, err := s.commitAndFlush(block, deleteEmptyObjects, noStorageWiping, false)
if err != nil { if err != nil {
return common.Hash{}, err 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 // CommitWithUpdate writes the state mutations and returns the state update for
// external processing (e.g., live tracing hooks). // external processing (e.g., live tracing hooks or size tracker).
func (s *StateDB) CommitWithUpdate(block uint64, deleteEmptyObjects bool, noStorageWiping bool) (common.Hash, *StateUpdate, error) { func (s *StateDB) CommitWithUpdate(rules params.Rules, block uint64) (common.Hash, *StateUpdate, error) {
ret, err := s.commitAndFlush(block, deleteEmptyObjects, noStorageWiping, true) ret, err := s.commitAndFlush(rules, block, true)
if err != nil { if err != nil {
return common.Hash{}, nil, err return common.Hash{}, nil, err
} }

View file

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types/bal" "github.com/ethereum/go-ethereum/core/types/bal"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256" "github.com/holiman/uint256"
) )
@ -49,7 +50,7 @@ func TestApplyBlockAccessListConcurrentPrefetch(t *testing.T) {
base.SetCode(addr, code, tracing.CodeChangeUnspecified) base.SetCode(addr, code, tracing.CodeChangeUnspecified)
base.SetState(addr, slot, common.HexToHash("0xaa")) base.SetState(addr, slot, common.HexToHash("0xaa"))
} }
root0, err := base.Commit(0, false, false) root0, err := base.Commit(params.Rules{}, 0)
if err != nil { if err != nil {
t.Fatalf("commit base: %v", err) t.Fatalf("commit base: %v", err)
} }
@ -63,7 +64,7 @@ func TestApplyBlockAccessListConcurrentPrefetch(t *testing.T) {
} }
seq, _ := New(root0, db) seq, _ := New(root0, db)
mutate(seq) mutate(seq)
wantRoot := seq.IntermediateRoot(true) wantRoot := seq.IntermediateRoot(params.Rules{IsEIP158: true})
cb := bal.NewConstructionBlockAccessList() cb := bal.NewConstructionBlockAccessList()
for i := range n { for i := range n {
@ -77,7 +78,7 @@ func TestApplyBlockAccessListConcurrentPrefetch(t *testing.T) {
balState.StopPrefetcher() balState.StopPrefetcher()
t.Fatalf("apply block access list: %v", err) t.Fatalf("apply block access list: %v", err)
} }
gotRoot := balState.IntermediateRoot(true) gotRoot := balState.IntermediateRoot(params.Rules{IsEIP158: true})
balState.StopPrefetcher() balState.StopPrefetcher()
if gotRoot != wantRoot { if gotRoot != wantRoot {
@ -113,7 +114,7 @@ func TestApplyBlockAccessListMatchesSequential(t *testing.T) {
base.SetCode(contract, code, tracing.CodeChangeUnspecified) base.SetCode(contract, code, tracing.CodeChangeUnspecified)
base.SetState(contract, slotA, common.HexToHash("0xaa")) base.SetState(contract, slotA, common.HexToHash("0xaa"))
base.SetState(contract, slotB, common.HexToHash("0xbb")) base.SetState(contract, slotB, common.HexToHash("0xbb"))
root0, err := base.Commit(0, false, false) root0, err := base.Commit(params.Rules{}, 0)
if err != nil { if err != nil {
t.Fatalf("commit base: %v", err) t.Fatalf("commit base: %v", err)
} }
@ -131,7 +132,7 @@ func TestApplyBlockAccessListMatchesSequential(t *testing.T) {
// Sequential reference root. // Sequential reference root.
seq, _ := New(root0, db) seq, _ := New(root0, db)
mutate(seq) mutate(seq)
wantRoot := seq.IntermediateRoot(true) wantRoot := seq.IntermediateRoot(params.Rules{IsEIP158: true})
if wantRoot == root0 { if wantRoot == root0 {
t.Fatal("mutations did not change the state root") t.Fatal("mutations did not change the state root")
} }
@ -152,7 +153,7 @@ func TestApplyBlockAccessListMatchesSequential(t *testing.T) {
balState.StopPrefetcher() balState.StopPrefetcher()
t.Fatalf("apply block access list: %v", err) t.Fatalf("apply block access list: %v", err)
} }
gotRoot := balState.IntermediateRoot(true) gotRoot := balState.IntermediateRoot(params.Rules{IsEIP158: true})
balState.StopPrefetcher() balState.StopPrefetcher()
if gotRoot != wantRoot { if gotRoot != wantRoot {

View file

@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb"
@ -217,19 +218,19 @@ func (test *stateTest) run() bool {
for i, action := range actions { for i, action := range actions {
if i%test.chunk == 0 && i != 0 { if i%test.chunk == 0 && i != 0 {
if byzantium { if byzantium {
state.Finalise(true) // call finalise at the transaction boundary state.Finalise(params.Rules{IsEIP158: true}) // call finalise at the transaction boundary
} else { } 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) action.fn(action, state)
} }
if byzantium { if byzantium {
state.Finalise(true) // call finalise at the transaction boundary state.Finalise(params.Rules{IsEIP158: true}) // call finalise at the transaction boundary
} else { } 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 { if err != nil {
panic(err) panic(err)
} }

View file

@ -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 { 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. // 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 // 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 // EIP-8246 (Amsterdam) removes the SELFDESTRUCT burn: a self-destructed
// account that retains a non-zero balance is preserved as a balance-only // account that retains a non-zero balance is preserved as a balance-only
// account rather than removed, so its balance is no longer burnt. // account rather than removed, so its balance is no longer burnt.
burnsBalance := s.inner.stateAccessList == nil burnsBalance := !rules.IsAmsterdam
for _, addr := range selfDestructedAddrs { for _, addr := range selfDestructedAddrs {
obj := s.inner.stateObjects[addr] 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) 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) { func (s *hookedStateDB) SetTxContext(thash common.Hash, ti int, blockAccessIndex uint32) {

View file

@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256" "github.com/holiman/uint256"
) )
@ -66,14 +67,14 @@ func TestBurn(t *testing.T) {
createAndDestroy(addB) createAndDestroy(addB)
hooked.AddBalance(addA, uint256.NewInt(200), tracing.BalanceChangeUnspecified) hooked.AddBalance(addA, uint256.NewInt(200), tracing.BalanceChangeUnspecified)
hooked.AddBalance(addB, 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 // Tx 2: create and destroy address C, then commit
createAndDestroy(addC) createAndDestroy(addC)
hooked.AddBalance(addC, uint256.NewInt(200), tracing.BalanceChangeUnspecified) 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) { if have, want := burned, uint256.NewInt(600); !have.Eq(want) {
t.Fatalf("burn-count wrong, have %v want %v", have, 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.SetCode(common.Address{0xbb}, []byte{0x13, 38}, tracing.CodeChangeContractCreation)
sdb.CreateContract(common.Address{0xbb}) sdb.CreateContract(common.Address{0xbb})
sdb.SelfDestruct(common.Address{0xbb}) sdb.SelfDestruct(common.Address{0xbb})
sdb.Finalise(true) sdb.Finalise(params.Rules{IsEIP158: true})
if len(result) != len(wants) { if len(result) != len(wants) {
t.Fatalf("number of tracing events wrong, have %d want %d", len(result), len(wants)) t.Fatalf("number of tracing events wrong, have %d want %d", len(result), len(wants))

View file

@ -37,6 +37,7 @@ import (
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/trie/trienode" "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 { if err := tdb.Commit(root, false); err != nil {
t.Errorf("can not commit trie %v to persistent database", root.Hex()) 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) modify(transState, common.Address{i}, i, 0)
} }
// Write modifications to trie. // Write modifications to trie.
transState.IntermediateRoot(false) transState.IntermediateRoot(params.Rules{})
// Overwrite all the data with new values in the transient database. // Overwrite all the data with new values in the transient database.
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
@ -120,7 +121,7 @@ func TestIntermediateLeaks(t *testing.T) {
} }
// Commit and cross check the databases. // Commit and cross check the databases.
transRoot, err := transState.Commit(0, false, false) transRoot, err := transState.Commit(params.Rules{}, 0)
if err != nil { if err != nil {
t.Fatalf("failed to commit transition state: %v", err) 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()) 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 { if err != nil {
t.Fatalf("failed to commit final state: %v", err) 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 := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
obj.AddBalance(uint256.NewInt(uint64(i))) obj.AddBalance(uint256.NewInt(uint64(i)))
} }
orig.Finalise(false) orig.Finalise(params.Rules{})
// Copy the state // Copy the state
copy := orig.Copy() copy := orig.Copy()
@ -195,7 +196,7 @@ func TestCopy(t *testing.T) {
// Finalise the changes on all concurrently // Finalise the changes on all concurrently
finalise := func(wg *sync.WaitGroup, db *StateDB) { finalise := func(wg *sync.WaitGroup, db *StateDB) {
defer wg.Done() defer wg.Done()
db.Finalise(true) db.Finalise(params.Rules{IsEIP158: true})
} }
var wg sync.WaitGroup var wg sync.WaitGroup
@ -235,7 +236,7 @@ func TestCopyWithDirtyJournal(t *testing.T) {
obj.AddBalance(uint256.NewInt(uint64(i))) obj.AddBalance(uint256.NewInt(uint64(i)))
obj.data.Root = common.HexToHash("0xdeadbeef") obj.data.Root = common.HexToHash("0xdeadbeef")
} }
root, _ := orig.Commit(0, true, false) root, _ := orig.Commit(params.Rules{IsEIP158: true}, 0)
orig, _ = New(root, db) orig, _ = New(root, db)
// modify all in memory without finalizing // modify all in memory without finalizing
@ -246,21 +247,21 @@ func TestCopyWithDirtyJournal(t *testing.T) {
} }
cpy := orig.Copy() cpy := orig.Copy()
orig.Finalise(true) orig.Finalise(params.Rules{IsEIP158: true})
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
balance := orig.GetBalance(common.BytesToAddress([]byte{i})) balance := orig.GetBalance(common.BytesToAddress([]byte{i}))
if !balance.IsZero() { if !balance.IsZero() {
t.Errorf("Unexpected balance %x", root) t.Errorf("Unexpected balance %x", root)
} }
} }
cpy.Finalise(true) cpy.Finalise(params.Rules{IsEIP158: true})
for i := byte(0); i < 255; i++ { for i := byte(0); i < 255; i++ {
balance := cpy.GetBalance(common.BytesToAddress([]byte{i})) balance := cpy.GetBalance(common.BytesToAddress([]byte{i}))
if !balance.IsZero() { if !balance.IsZero() {
t.Errorf("Unexpected balance %x", root) 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") t.Error("State is not equal after copy")
} }
} }
@ -278,14 +279,14 @@ func TestCopyObjectState(t *testing.T) {
obj.AddBalance(uint256.NewInt(uint64(i))) obj.AddBalance(uint256.NewInt(uint64(i)))
obj.data.Root = common.HexToHash("0xdeadbeef") obj.data.Root = common.HexToHash("0xdeadbeef")
} }
orig.Finalise(true) orig.Finalise(params.Rules{IsEIP158: true})
cpy := orig.Copy() cpy := orig.Copy()
for _, op := range cpy.mutations { for _, op := range cpy.mutations {
if have, want := op.applied, false; have != want { 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) 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 { for _, op := range cpy.mutations {
if have, want := op.applied, false; have != want { if have, want := op.applied, false; have != want {
t.Fatalf("Error: original state affected copy, have %v want %v", 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) { func TestTouchDelete(t *testing.T) {
s := newStateEnv() s := newStateEnv()
s.state.getOrNewStateObject(common.Address{}) 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) s.state, _ = New(root, s.state.db)
snapshot := s.state.Snapshot() 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{}) t.Fatalf("second copy committed storage slot mismatch: have %x, want %x", val, common.Hash{})
} }
// Commit state, ensure states can be loaded from disk // 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) state, _ = New(root, tdb)
if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 { if balance := state.GetBalance(addr); balance.Cmp(uint256.NewInt(42)) != 0 {
t.Fatalf("state post-commit balance mismatch: have %v, want %v", balance, 42) 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{}) { if val := state.GetCommittedState(addr, skey1); val != (common.Hash{}) {
t.Fatalf("initial committed storage slot mismatch: have %x, want %x", 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, _ = New(root, db)
state.SetState(addr, skey2, sval2) 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. // Copy the committed state database, the copied one is not fully functional.
copied := state.Copy() copied := state.Copy()
@ -979,19 +980,19 @@ func TestDeleteCreateRevert(t *testing.T) {
addr := common.BytesToAddress([]byte("so")) addr := common.BytesToAddress([]byte("so"))
state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified) 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) state, _ = New(root, state.db)
// Simulate self-destructing in one transaction, then create-reverting in another // Simulate self-destructing in one transaction, then create-reverting in another
state.SelfDestruct(addr) state.SelfDestruct(addr)
state.Finalise(true) state.Finalise(params.Rules{IsEIP158: true})
id := state.Snapshot() id := state.Snapshot()
state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified) state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified)
state.RevertToSnapshot(id) state.RevertToSnapshot(id)
// Commit the entire state and make sure we don't crash and have the correct state // 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) state, _ = New(root, state.db)
if state.getStateObject(addr) != nil { if state.getStateObject(addr) != nil {
@ -1006,7 +1007,7 @@ func TestWitnessIncludesAbsentAccountReads(t *testing.T) {
addr := common.Address{i + 1} addr := common.Address{i + 1}
state.SetBalance(addr, uint256.NewInt(uint64(i+1)), tracing.BalanceChangeUnspecified) 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 { if err != nil {
t.Fatalf("failed to commit initial state: %v", err) t.Fatalf("failed to commit initial state: %v", err)
} }
@ -1027,7 +1028,7 @@ func TestWitnessIncludesAbsentAccountReads(t *testing.T) {
if err := state.Error(); err != nil { if err := state.Error(); err != nil {
t.Fatalf("unexpected state error after read: %v", err) 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) t.Fatalf("unexpected root after read-only access: have %x want %x", got, root)
} }
if err := state.Error(); err != nil { if err := state.Error(); err != nil {
@ -1075,7 +1076,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
a2 := common.BytesToAddress([]byte("another")) a2 := common.BytesToAddress([]byte("another"))
state.SetBalance(a2, uint256.NewInt(100), tracing.BalanceChangeUnspecified) state.SetBalance(a2, uint256.NewInt(100), tracing.BalanceChangeUnspecified)
state.SetCode(a2, []byte{1, 2, 4}, tracing.CodeChangeUnspecified) 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) t.Logf("root: %x", root)
// force-flush // force-flush
tdb.Commit(root, false) tdb.Commit(root, false)
@ -1106,7 +1107,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
} }
// Modify the state // Modify the state
state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified) 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 { if err == nil {
t.Fatalf("expected error, got root :%x", root) 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}) 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 { if err != nil {
t.Fatalf("failed to commit state trie: %v", err) 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()) value := common.Hash(uint256.NewInt(uint64(10 * i)).Bytes32())
state.SetState(addr, slot, value) 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 // Init phase done, create two states, one with snap and one without
fastState, _ := New(root, NewMPTDatabase(tdb, nil).WithSnapshot(snaps)) fastState, _ := New(root, NewMPTDatabase(tdb, nil).WithSnapshot(snaps))
slowState, _ := New(root, NewMPTDatabase(tdb, nil)) slowState, _ := New(root, NewMPTDatabase(tdb, nil))

View file

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb"
@ -81,7 +82,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *triedb.Database, c
} }
accounts = append(accounts, acc) accounts = append(accounts, acc)
} }
root, _ := state.Commit(0, false, false) root, _ := state.Commit(params.Rules{}, 0)
// Return the generated state // Return the generated state
return db, sdb, nodeDb, root, accounts return db, sdb, nodeDb, root, accounts

View file

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/internal/testrand" "github.com/ethereum/go-ethereum/internal/testrand"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/triedb" "github.com/ethereum/go-ethereum/triedb"
"github.com/holiman/uint256" "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.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie
state.SetCode(addr, []byte("hello"), tracing.CodeChangeUnspecified) // Change an external metadata state.SetCode(addr, []byte("hello"), tracing.CodeChangeUnspecified) // Change an external metadata
state.SetState(addr, skey, sval) // Change the storage trie 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) state, _ = New(root, sdb)
fetcher := newTriePrefetcher(sdb, root, "", false) fetcher := newTriePrefetcher(sdb, root, "", false)

View file

@ -232,9 +232,9 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
// Update the state with pending changes. // Update the state with pending changes.
var root []byte var root []byte
if evm.ChainConfig().IsByzantium(blockNumber) { if evm.ChainConfig().IsByzantium(blockNumber) {
bal = evm.StateDB.Finalise(true) bal = evm.StateDB.Finalise(evm.GetRules())
} else { } 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 // Merge the tx-local access event into the "block-local" one, in order to collect
// all values, so that the witness can be built. // 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 { if evm.StateDB.AccessEvents() != nil {
evm.StateDB.AccessEvents().Merge(evm.AccessEvents) 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 // 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 { if evm.StateDB.AccessEvents() != nil {
evm.StateDB.AccessEvents().Merge(evm.AccessEvents) 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. // ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract.
@ -414,14 +414,14 @@ func processRequestsSystemCall(requests *[][]byte, rules params.Rules, evm *vm.E
To: &addr, To: &addr,
} }
evm.SetTxContext(NewEVMTxContext(msg)) 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.SetTxContext(common.Hash{}, 0, blockAccessIndex)
evm.StateDB.AddAddressToAccessList(addr) evm.StateDB.AddAddressToAccessList(addr)
ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, gasBudget, common.U2560) ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, gasBudget, common.U2560)
if evm.StateDB.AccessEvents() != nil { if evm.StateDB.AccessEvents() != nil {
evm.StateDB.AccessEvents().Merge(evm.AccessEvents) evm.StateDB.AccessEvents().Merge(evm.AccessEvents)
} }
bal := evm.StateDB.Finalise(true) bal := evm.StateDB.Finalise(evm.GetRules())
if err != nil { if err != nil {
return fmt.Errorf("system call failed to execute: %v", err) 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. // 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 { 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 // 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)) return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil))
} }
// Assign the BlockAccessListHash if Amsterdam has been enabled // Assign the BlockAccessListHash if Amsterdam has been enabled

View file

@ -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 is the access list rebuilt from the actual execution.
blockAccessList = bal.NewConstructionBlockAccessList() blockAccessList = bal.NewConstructionBlockAccessList()
) )
// Resolve the parent state root, the point all execution reads from. // Resolve the parent state root, the point all execution reads from.
parent := p.chain.GetHeader(block.ParentHash(), block.NumberU64()-1) parent := p.chain.GetHeader(block.ParentHash(), block.NumberU64()-1)
if parent == nil { if parent == nil {
@ -135,7 +134,7 @@ func (p *StateProcessor) processParallel(ctx context.Context, block *types.Block
stateApply = time.Since(start) stateApply = time.Since(start)
start = time.Now() 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) stateHash = time.Since(start)
return statedb.Error() return statedb.Error()
}) })

View file

@ -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 // Almost everything validated, but receipt and state root needs to be returned
receiptRoot := types.DeriveSha(res.Receipts, trie.NewStackTrie(nil)) 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 return stateRoot, receiptRoot, nil
} }

View file

@ -727,7 +727,7 @@ func TestOpenDrops(t *testing.T) {
statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000), tracing.BalanceChangeUnspecified) 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(duplicater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(crypto.PubkeyToAddress(repeater.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{ chain := &testBlockChain{
config: params.MainnetChainConfig, config: params.MainnetChainConfig,
@ -847,7 +847,7 @@ func TestOpenIndex(t *testing.T) {
// Create a blob pool out of the pre-seeded data // Create a blob pool out of the pre-seeded data
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) 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{ chain := &testBlockChain{
config: params.MainnetChainConfig, 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(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr2, 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.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true, false) statedb.Commit(params.Rules{IsEIP158: true}, 0)
chain := &testBlockChain{ chain := &testBlockChain{
config: params.MainnetChainConfig, 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(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr2, 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.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true, false) statedb.Commit(params.Rules{IsEIP158: true}, 0)
chain := &testBlockChain{ chain := &testBlockChain{
config: params.MainnetChainConfig, 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(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr2, 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.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. // Make custom chain config where the max blob count changes based on the loop variable.
cancunTime := uint64(0) 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(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr2, 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.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. // Make custom chain config where the max blob count changes based on the loop variable.
zero := uint64(0) zero := uint64(0)
@ -1316,7 +1316,7 @@ func TestLegacyTxConversion(t *testing.T) {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr2, 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{ chain := &testBlockChain{
config: params.MainnetChainConfig, config: params.MainnetChainConfig,
@ -1390,7 +1390,7 @@ func TestLegacyLimboConversion(t *testing.T) {
store.Close() store.Close()
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.Commit(0, true, false) statedb.Commit(params.Rules{IsEIP158: true}, 0)
chain := &testBlockChain{ chain := &testBlockChain{
config: params.MainnetChainConfig, config: params.MainnetChainConfig,
basefee: uint256.NewInt(params.InitialBaseFee), basefee: uint256.NewInt(params.InitialBaseFee),
@ -1445,7 +1445,7 @@ func TestBlobCountLimit(t *testing.T) {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr2, 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. // Make Prague-enabled custom chain config.
cancunTime := uint64(0) cancunTime := uint64(0)
@ -1901,7 +1901,7 @@ func TestAdd(t *testing.T) {
store.Put(blob) store.Put(blob)
} }
} }
statedb.Commit(0, true, false) statedb.Commit(params.Rules{IsEIP158: true}, 0)
store.Close() store.Close()
// Create a blob pool out of the pre-seeded dats // 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(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.AddBalance(addr2, 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.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. // Make custom chain config where the max blob count changes based on the loop variable.
cancunTime := uint64(0) cancunTime := uint64(0)
@ -2307,7 +2307,7 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) {
pooledTx, _ := newBlobTxForPool(tx) pooledTx, _ := newBlobTxForPool(tx)
pool.AddPooledTx(pooledTx) pool.AddPooledTx(pooledTx)
} }
statedb.Commit(0, true, false) statedb.Commit(params.Rules{IsEIP158: true}, 0)
defer pool.Close() defer pool.Close()
// Benchmark assembling the pending // Benchmark assembling the pending
@ -2350,7 +2350,7 @@ func TestGetCells(t *testing.T) {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified) 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{ chain := &testBlockChain{
config: params.MainnetChainConfig, config: params.MainnetChainConfig,

View file

@ -84,7 +84,7 @@ func newTestCache(t *testing.T, txConfig []txSpec) *testCache {
for _, a := range addrs { for _, a := range addrs {
statedb.AddBalance(a, uint256.NewInt(1_000_000_000_000), tracing.BalanceChangeUnspecified) 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) cancunTime := uint64(0)
config := &params.ChainConfig{ config := &params.ChainConfig{

View file

@ -77,7 +77,7 @@ func run8037(t *testing.T, code []byte, gas GasBudget, value *uint256.Int, setup
if setup != nil { if setup != nil {
setup(statedb, self) setup(statedb, self)
} }
statedb.Finalise(true) statedb.Finalise(params.Rules{IsEIP158: true})
ret, result, err := amsterdam8037EVM(statedb).Call(common.Address{}, self, nil, gas, value) ret, result, err := amsterdam8037EVM(statedb).Call(common.Address{}, self, nil, gas, value)
assertBudgetSane(t, gas, result) assertBudgetSane(t, gas, result)
return ret, result, err return ret, result, err

View file

@ -43,7 +43,7 @@ func run8038(t *testing.T, code []byte, gas GasBudget, value *uint256.Int, setup
if setup != nil { if setup != nil {
setup(statedb, self) setup(statedb, self)
} }
statedb.Finalise(true) statedb.Finalise(params.Rules{IsEIP158: true})
_, result, err := amsterdam8037EVM(statedb).Call(common.Address{}, self, nil, gas, value) _, result, err := amsterdam8037EVM(statedb).Call(common.Address{}, self, nil, gas, value)
return result, statedb.GetRefund(), err return result, statedb.GetRefund(), err
} }

View file

@ -90,7 +90,7 @@ func TestEIP2200(t *testing.T) {
statedb.CreateAccount(address) statedb.CreateAccount(address)
statedb.SetCode(address, hexutil.MustDecode(tt.input), tracing.CodeChangeUnspecified) statedb.SetCode(address, hexutil.MustDecode(tt.input), tracing.CodeChangeUnspecified)
statedb.SetState(address, common.Hash{}, common.BytesToHash([]byte{tt.original})) 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{ vmctx := BlockContext{
CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true }, 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, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.CreateAccount(address) statedb.CreateAccount(address)
statedb.SetCode(address, hexutil.MustDecode(tt.code), tracing.CodeChangeUnspecified) statedb.SetCode(address, hexutil.MustDecode(tt.code), tracing.CodeChangeUnspecified)
statedb.Finalise(true) statedb.Finalise(params.Rules{IsEIP158: true})
vmctx := BlockContext{ vmctx := BlockContext{
CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true }, CanTransfer: func(StateDB, common.Address, *uint256.Int) bool { return true },
Transfer: func(StateDB, common.Address, common.Address, *uint256.Int, *params.Rules) {}, Transfer: func(StateDB, common.Address, common.Address, *uint256.Int, *params.Rules) {},

View file

@ -99,6 +99,6 @@ type StateDB interface {
AccessEvents() *state.AccessEvents AccessEvents() *state.AccessEvents
// Finalise must be invoked at the end of a transaction // 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) SetTxContext(thash common.Hash, ti int, blockAccessIndex uint32)
} }

View file

@ -47,7 +47,7 @@ func TestLoopInterrupt(t *testing.T) {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting())
statedb.CreateAccount(address) statedb.CreateAccount(address)
statedb.SetCode(address, common.Hex2Bytes(tt), tracing.CodeChangeUnspecified) statedb.SetCode(address, common.Hex2Bytes(tt), tracing.CodeChangeUnspecified)
statedb.Finalise(true) statedb.Finalise(params.Rules{IsEIP158: true})
evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{}) evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{})

View file

@ -131,7 +131,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
var ( var (
address = common.BytesToAddress([]byte("contract")) address = common.BytesToAddress([]byte("contract"))
vmenv = NewEnv(cfg) 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 { 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) 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 ( var (
vmenv = NewEnv(cfg) 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 { 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) cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)

View file

@ -194,7 +194,7 @@ func (api *DebugAPI) replayBuild(ctx context.Context, block *types.Block, stated
Withdrawals: block.Withdrawals(), Withdrawals: block.Withdrawals(),
} }
bc.Engine().Finalize(bc, header, statedb, &body, uint32(tcount+1), blockAL) 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 return blockAL.ToEncodingObj(), receipts, gp.Used(), root, nil
} }

View file

@ -134,7 +134,7 @@ func TestAccountRange(t *testing.T) {
m[addr] = true m[addr] = true
} }
} }
root, _ := sdb.Commit(0, true, false) root, _ := sdb.Commit(params.Rules{IsEIP158: true}, 0)
sdb, _ = state.New(root, statedb) sdb, _ = state.New(root, statedb)
trie, err := statedb.OpenTrie(root) trie, err := statedb.OpenTrie(root)
@ -192,7 +192,7 @@ func TestEmptyAccountRange(t *testing.T) {
st, _ = state.New(types.EmptyRootHash, statedb) st, _ = state.New(types.EmptyRootHash, statedb)
) )
// Commit(although nothing to flush) and re-init the 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) st, _ = state.New(types.EmptyRootHash, statedb)
results := st.RawDump(&state.DumpConfig{ results := st.RawDump(&state.DumpConfig{
@ -235,7 +235,7 @@ func TestStorageRangeAt(t *testing.T) {
for _, entry := range storage { for _, entry := range storage {
sdb.SetState(addr, *entry.Key, entry.Value) sdb.SetState(addr, *entry.Key, entry.Value)
} }
root, _ := sdb.Commit(0, false, false) root, _ := sdb.Commit(params.Rules{}, 0)
sdb, _ = state.New(root, db) sdb, _ = state.New(root, db)
// Check a few combinations of limit and start/end. // Check a few combinations of limit and start/end.

View file

@ -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) return nil, nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err)
} }
// Finalize the state so any modifications are written to the trie // 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 { if err != nil {
return nil, nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w", return nil, nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w",
current.NumberU64(), current.Root().Hex(), err) 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) return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
} }
// Ensure any modifications are committed to the state // 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.GetRules())
statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number()))
} }
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash()) return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
} }

View file

@ -514,12 +514,12 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
defer release() defer release()
var ( var (
roots []common.Hash roots []common.Hash
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
chainConfig = api.backend.ChainConfig() chainConfig = api.backend.ChainConfig()
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) rules = chainConfig.Rules(block.Number(), block.Difficulty().Sign() == 0, block.Time())
deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
evm = vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) evm = vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{})
) )
defer evm.Release() defer evm.Release()
// Run pre-execution system calls // 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 // Calling IntermediateRoot will internally call Finalize on the state
// so any modifications are written to the trie // so any modifications are written to the trie
roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects)) roots = append(roots, statedb.IntermediateRoot(rules))
} }
return roots, nil return roots, nil
} }
@ -687,8 +687,7 @@ txloop:
break txloop break txloop
} }
// Finalize the state so any modifications are written to the trie // 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.GetRules())
statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number()))
} }
close(jobs) close(jobs)
@ -766,8 +765,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
return dumps, err return dumps, err
} }
// Finalize the state so any modifications are written to the trie // 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.GetRules())
statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number()))
continue continue
} }
// The transaction should be traced. // The transaction should be traced.
@ -810,8 +808,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
return dumps, err return dumps, err
} }
// Finalize the state so any modifications are written to the trie // 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.GetRules())
statedb.Finalise(chainConfig.IsEIP158(block.Number()))
// If we've traced the transaction we were looking for, abort // If we've traced the transaction we were looking for, abort
if tx.Hash() == txHash { if tx.Hash() == txHash {

View file

@ -191,7 +191,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
if _, err := core.ApplyMessage(evm, msg, nil); err != nil { if _, err := core.ApplyMessage(evm, msg, nil); err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) 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()) return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
} }

View file

@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256" "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. // Now finalize the changes. Finalize is normally performed between transactions.
// By using finalize, the overrides are semantically behaving as // By using finalize, the overrides are semantically behaving as
// if they were created in a transaction just before the tracing occur. // if they were created in a transaction just before the tracing occur.
statedb.Finalise(false) statedb.Finalise(params.Rules{})
return nil return nil
} }

View file

@ -353,9 +353,9 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
// Update the state with pending changes. // Update the state with pending changes.
var root []byte var root []byte
if sim.chainConfig.IsByzantium(blockContext.BlockNumber) { if sim.chainConfig.IsByzantium(blockContext.BlockNumber) {
blockAccessList.Merge(tracingStateDB.Finalise(true)) blockAccessList.Merge(tracingStateDB.Finalise(evm.GetRules()))
} else { } 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) receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, blockContext.Time, tx, gp.CumulativeUsed(), root)
blobGasUsed += receipts[i].BlobGasUsed blobGasUsed += receipts[i].BlobGasUsed

View file

@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers/logger" "github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/params"
) )
func initMatcher(st *testMatcher) { func initMatcher(st *testMatcher) {
@ -135,7 +136,7 @@ func execStateTest(t *testing.T, st *testMatcher, test *StateTest) {
var result error var result error
test.Run(subtest, vmconfig, true, rawdb.HashScheme, func(err error, state *StateTestState) { test.Run(subtest, vmconfig, true, rawdb.HashScheme, func(err error, state *StateTestState) {
if state.Snapshots != nil && state.StateDB != nil { 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 result = err
return return
} }
@ -165,7 +166,7 @@ func execStateTest(t *testing.T, st *testMatcher, test *StateTest) {
var result error var result error
test.Run(subtest, vmconfig, true, rawdb.PathScheme, func(err error, state *StateTestState) { test.Run(subtest, vmconfig, true, rawdb.PathScheme, func(err error, state *StateTestState) {
if state.TrieDB != nil && state.StateDB != nil { 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 result = err
return return
} }

View file

@ -245,7 +245,9 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bo
if err != nil { if err != nil {
return fmt.Errorf("failed to get chain config: %w", err) 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) { 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) 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 vmconfig.ExtraEips = eips
block := t.genesis(config).ToBlock() 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) st = MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter, scheme)
var baseFee *big.Int var baseFee *big.Int
@ -324,7 +330,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
if t.json.Env.Difficulty != nil { if t.json.Env.Difficulty != nil {
context.Difficulty = new(big.Int).Set(t.json.Env.Difficulty) 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) rnd := common.BigToHash(t.json.Env.Random)
context.Random = &rnd context.Random = &rnd
context.Difficulty = big.NewInt(0) 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) st.StateDB.AddBalance(block.Coinbase(), new(uint256.Int), tracing.BalanceChangeUnspecified)
// Commit state mutations into database. // 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 { if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil {
receipt := &types.Receipt{GasUsed: vmRet.UsedGas} receipt := &types.Receipt{GasUsed: vmRet.UsedGas}
tracer.OnTxEnd(receipt, nil) 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. // 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. // If snapshot is requested, initialize the snapshotter and use it in state.
var snaps *snapshot.Tree var snaps *snapshot.Tree