diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 44f15c322c..ecaccee0f6 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -144,17 +144,20 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, return h } var ( - isEIP4762 = chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp) - statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre, isEIP4762) - signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) - gaspool = new(core.GasPool) - blockHash = common.Hash{0x13, 0x37} - rejectedTxs []*rejectedTx - includedTxs types.Transactions - gasUsed = uint64(0) - blobGasUsed = uint64(0) - receipts = make(types.Receipts, 0) + isEIP4762 = chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number)), pre.Env.Timestamp) + parentIsVerkle = pre.Env.Number > 0 && chainConfig.IsVerkle(big.NewInt(int64(pre.Env.Number-1)), pre.Env.ParentTimestamp) + isForkBoundary = isEIP4762 && !parentIsVerkle + statedb *state.StateDB + signer = types.MakeSigner(chainConfig, new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) + gaspool = new(core.GasPool) + blockHash = common.Hash{0x13, 0x37} + rejectedTxs []*rejectedTx + includedTxs types.Transactions + gasUsed = uint64(0) + blobGasUsed = uint64(0) + receipts = make(types.Receipts, 0) ) + statedb = MakePreState(rawdb.NewMemoryDatabase(), pre.Pre, isEIP4762 && !isForkBoundary, isForkBoundary) gaspool.AddGas(pre.Env.GasLimit) vmContext := vm.BlockContext{ CanTransfer: core.CanTransfer, @@ -222,6 +225,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, ) core.ProcessParentBlockHash(prevHash, evm) } + if isEIP4762 { + core.InitializeBinaryTransitionRegistry(statedb) + } for i := 0; txIt.Next(); i++ { tx, err := txIt.Tx() if err != nil { @@ -377,7 +383,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, return statedb, execRs, body, nil } -func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, isBintrie bool) *state.StateDB { +func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, isBintrie bool, forkBoundary bool) *state.StateDB { tdb := triedb.NewDatabase(db, &triedb.Config{Preimages: true, IsVerkle: isBintrie}) sdb := state.NewDatabase(tdb, nil) @@ -406,6 +412,9 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, isBintrie bool if isBintrie { return statedb } + if forkBoundary { + sdb.SetForkBoundary(root) + } // For MPT mode, reopen the state with the committed root statedb, err = state.New(root, sdb) if err != nil { diff --git a/core/blockchain.go b/core/blockchain.go index a3776442d2..5c75c8ec15 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2085,7 +2085,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s parent := bc.GetHeader(block.ParentHash(), block.NumberU64()-1) if parent != nil && !bc.chainConfig.IsVerkle(parent.Number, parent.Time) { bc.SetForkBoundary(parentRoot) - defer bc.ClearForkBoundary() + defer bc.ClearForkBoundary(parentRoot) } } diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index de0ef360db..752169d5cf 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -420,8 +420,8 @@ func (bc *BlockChain) SetForkBoundary(root common.Hash) { bc.statedb.SetForkBoundary(root) } -func (bc *BlockChain) ClearForkBoundary() { - bc.statedb.ClearForkBoundary() +func (bc *BlockChain) ClearForkBoundary(root common.Hash) { + bc.statedb.ClearForkBoundary(root) } // HistoricState returns a historic state specified by the given root. diff --git a/core/state/database.go b/core/state/database.go index b7085467b0..9ffafa45ae 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -18,7 +18,7 @@ package state import ( "fmt" - "sync/atomic" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/lru" @@ -160,7 +160,7 @@ type CachingDB struct { // Transition-specific fields TransitionStatePerRoot *lru.Cache[common.Hash, *overlay.TransitionState] - forkBoundaryRoot atomic.Value // stores common.Hash; non-zero means fork boundary active for this root + forkBoundaryRoots sync.Map // map[common.Hash]struct{}; set of roots at fork boundary } // NewDatabase creates a state database with the provided data sources. @@ -182,20 +182,16 @@ func NewDatabaseForTesting() *CachingDB { } func (db *CachingDB) SetForkBoundary(root common.Hash) { - db.forkBoundaryRoot.Store(root) + db.forkBoundaryRoots.Store(root, struct{}{}) } -func (db *CachingDB) ClearForkBoundary() { - db.forkBoundaryRoot.Store(common.Hash{}) +func (db *CachingDB) ClearForkBoundary(root common.Hash) { + db.forkBoundaryRoots.Delete(root) } func (db *CachingDB) isForkBoundary(root common.Hash) bool { - v := db.forkBoundaryRoot.Load() - if v == nil { - return false - } - stored, ok := v.(common.Hash) - return ok && stored != (common.Hash{}) && stored == root + _, ok := db.forkBoundaryRoots.Load(root) + return ok } var ( diff --git a/core/state/fork_boundary_test.go b/core/state/fork_boundary_test.go index 3fba1d8030..8b5f5443a5 100644 --- a/core/state/fork_boundary_test.go +++ b/core/state/fork_boundary_test.go @@ -35,7 +35,7 @@ func TestForkBoundaryOpenTrie(t *testing.T) { } sdb.SetForkBoundary(root) - defer sdb.ClearForkBoundary() + defer sdb.ClearForkBoundary(root) tr, err := sdb.OpenTrie(root) if err != nil { @@ -80,7 +80,7 @@ func TestForkBoundaryStateReader(t *testing.T) { } sdb.SetForkBoundary(root) - defer sdb.ClearForkBoundary() + defer sdb.ClearForkBoundary(root) reader, err := sdb.StateReader(root) if err != nil { @@ -121,7 +121,7 @@ func TestForkBoundaryWrite(t *testing.T) { } sdb.SetForkBoundary(root) - defer sdb.ClearForkBoundary() + defer sdb.ClearForkBoundary(root) tr, err := sdb.OpenTrie(root) if err != nil { @@ -213,7 +213,7 @@ func TestForkBoundaryWrongRoot(t *testing.T) { otherRoot := common.HexToHash("0xdeadbeef") sdb.SetForkBoundary(otherRoot) - defer sdb.ClearForkBoundary() + defer sdb.ClearForkBoundary(otherRoot) tr, err := sdb.OpenTrie(root) if err != nil { diff --git a/miner/worker.go b/miner/worker.go index b74f44edca..029201c1bd 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -255,7 +255,7 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir if miner.chainConfig.IsVerkle(header.Number, header.Time) && !miner.chainConfig.IsVerkle(parent.Number, parent.Time) { miner.chain.SetForkBoundary(parent.Root) - defer miner.chain.ClearForkBoundary() + defer miner.chain.ClearForkBoundary(parent.Root) } // Could potentially happen if starting to mine in an odd state. // Note genParams.coinbase can be different with header.Coinbase