From dd5ff823bdeac2efeb9d82fdc888ad178f86cdbb Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Fri, 10 Jan 2025 12:18:18 +0100 Subject: [PATCH] core/{.,state,vm},miner,ethr/tracers: implement 7709 Co-authored-by: Ignacio Hagopian Signed-off-by: Guillaume Ballet <3272758+gballet@users.noreply.github.com> --- core/chain_makers.go | 4 ++-- core/state/statedb_hooked.go | 4 ++++ core/state_processor.go | 17 ++++++++++++++--- core/verkle_witness_test.go | 17 ++++++++++------- core/vm/interface.go | 3 +++ eth/state_accessor.go | 2 +- eth/tracers/api.go | 8 ++++---- miner/worker.go | 2 +- 8 files changed, 39 insertions(+), 18 deletions(-) diff --git a/core/chain_makers.go b/core/chain_makers.go index 26714845ebc8..e74b5c2ea3e5 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -384,7 +384,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) blockContext.Random = &common.Hash{} // enable post-merge instruction set evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{}) - ProcessParentBlockHash(b.header.ParentHash, evm) + ProcessParentBlockHash(b.header.ParentHash, evm, false) } // Execute any user modifications to the block @@ -492,7 +492,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine // EIP-2935 blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase) evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{}) - ProcessParentBlockHash(b.header.ParentHash, evm) + ProcessParentBlockHash(b.header.ParentHash, evm, false) } // Execute any user modifications to the block. diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go index 31bdd06b462c..25d823cc8770 100644 --- a/core/state/statedb_hooked.go +++ b/core/state/statedb_hooked.go @@ -157,6 +157,10 @@ func (s *hookedStateDB) Witness() *stateless.Witness { return s.inner.Witness() } +func (s *hookedStateDB) AccessEvents() *AccessEvents { + return s.inner.AccessEvents() +} + func (s *hookedStateDB) SubBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int { prev := s.inner.SubBalance(addr, amount, reason) if s.hooks.OnBalanceChange != nil && !amount.IsZero() { diff --git a/core/state_processor.go b/core/state_processor.go index 3eb83a673a96..2fca17563060 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,6 +17,7 @@ package core import ( + "encoding/binary" "fmt" "math/big" @@ -86,7 +87,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg ProcessBeaconBlockRoot(*beaconRoot, evm) } if p.config.IsPrague(block.Number(), block.Time()) { - ProcessParentBlockHash(block.ParentHash(), evm) + ProcessParentBlockHash(block.ParentHash(), evm, p.config.IsVerkle(block.Number(), block.Time())) } // Iterate over and process the individual transactions @@ -234,14 +235,24 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) { } // ProcessParentBlockHash stores the parent block hash in the history storage contract -// as per EIP-2935. -func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { +// as per EIP-2935/7709. +func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM, is7709 bool) { if tracer := evm.Config.Tracer; tracer != nil { onSystemCallStart(tracer, evm.GetVMContext()) if tracer.OnSystemCallEnd != nil { defer tracer.OnSystemCallEnd() } } + if is7709 { + // currently 8192 for kautinen7, to be changed to 8 (and made a constant) for kaustinen8 + ringIndex := (evm.Context.BlockNumber.Uint64() - 1) % params.HistoryServeWindow + var key common.Hash + binary.BigEndian.PutUint64(key[24:], ringIndex) + evm.StateDB.SetState(params.SystemAddress, key, prevHash) + evm.StateDB.AccessEvents().SlotGas(params.SystemAddress, key, true) + evm.StateDB.Finalise(false) + return + } msg := &Message{ From: params.SystemAddress, GasLimit: 30_000_000, diff --git a/core/verkle_witness_test.go b/core/verkle_witness_test.go index 508823120749..c57eb73827f6 100644 --- a/core/verkle_witness_test.go +++ b/core/verkle_witness_test.go @@ -217,7 +217,7 @@ func TestProcessParentBlockHash(t *testing.T) { // block 1 parent hash is 0x0100.... // block 2 parent hash is 0x0200.... // etc - checkBlockHashes := func(statedb *state.StateDB) { + checkBlockHashes := func(statedb *state.StateDB, isVerkle bool) { statedb.SetNonce(params.HistoryStorageAddress, 1) statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) // Process n blocks, from 1 .. num @@ -226,19 +226,19 @@ func TestProcessParentBlockHash(t *testing.T) { header := &types.Header{ParentHash: common.Hash{byte(i)}, Number: big.NewInt(int64(i)), Difficulty: new(big.Int)} vmContext := NewEVMBlockContext(header, nil, new(common.Address)) evm := vm.NewEVM(vmContext, statedb, params.MergedTestChainConfig, vm.Config{}) - ProcessParentBlockHash(header.ParentHash, evm) + ProcessParentBlockHash(header.ParentHash, evm, isVerkle) } // Read block hashes for block 0 .. num-1 for i := 0; i < num; i++ { - have, want := getContractStoredBlockHash(statedb, uint64(i)), common.Hash{byte(i + 1)} + have, want := getContractStoredBlockHash(statedb, uint64(i), isVerkle), common.Hash{byte(i + 1)} if have != want { - t.Errorf("block %d, have parent hash %v, want %v", i, have, want) + t.Errorf("block %d, verkle=%v, have parent hash %v, want %v", i, isVerkle, have, want) } } } t.Run("MPT", func(t *testing.T) { statedb, _ := state.New(types.EmptyRootHash, state.NewDatabaseForTesting()) - checkBlockHashes(statedb) + checkBlockHashes(statedb, false) }) t.Run("Verkle", func(t *testing.T) { db := rawdb.NewMemoryDatabase() @@ -246,15 +246,18 @@ func TestProcessParentBlockHash(t *testing.T) { cacheConfig.SnapshotLimit = 0 triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true)) statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabase(triedb, nil)) - checkBlockHashes(statedb) + checkBlockHashes(statedb, true) }) } // getContractStoredBlockHash is a utility method which reads the stored parent blockhash for block 'number' -func getContractStoredBlockHash(statedb *state.StateDB, number uint64) common.Hash { +func getContractStoredBlockHash(statedb *state.StateDB, number uint64, isVerkle bool) common.Hash { ringIndex := number % params.HistoryServeWindow var key common.Hash binary.BigEndian.PutUint64(key[24:], ringIndex) + if isVerkle { + return statedb.GetState(params.SystemAddress, key) + } return statedb.GetState(params.HistoryStorageAddress, key) } diff --git a/core/vm/interface.go b/core/vm/interface.go index 011541dde301..3488526fc4dc 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -20,6 +20,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" @@ -98,6 +99,8 @@ type StateDB interface { Witness() *stateless.Witness + AccessEvents() *state.AccessEvents + // Finalise must be invoked at the end of a transaction Finalise(bool) } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 0749d7379115..35ec0829b65a 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -242,7 +242,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, } // If prague hardfork, insert parent block hash in the state as per EIP-2935. if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm) + core.ProcessParentBlockHash(block.ParentHash(), evm, eth.blockchain.Config().IsVerkle(block.Number(), block.Time())) } if txIndex == 0 && len(block.Transactions()) == 0 { return nil, vm.BlockContext{}, statedb, release, nil diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 22163030de0b..1bea4835d604 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -386,7 +386,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed } // Insert parent hash in history contract. if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) { - core.ProcessParentBlockHash(next.ParentHash(), evm) + core.ProcessParentBlockHash(next.ParentHash(), evm, api.backend.ChainConfig().IsVerkle(next.Number(), next.Time())) } // Clean out any pending release functions of trace state. Note this // step must be done after constructing tracing state, because the @@ -541,7 +541,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config core.ProcessBeaconBlockRoot(*beaconRoot, evm) } if chainConfig.IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm) + core.ProcessParentBlockHash(block.ParentHash(), evm, api.backend.ChainConfig().IsVerkle(block.Number(), block.Time())) } for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { @@ -605,7 +605,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac core.ProcessBeaconBlockRoot(*beaconRoot, evm) } if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm) + core.ProcessParentBlockHash(block.ParentHash(), evm, api.backend.ChainConfig().IsVerkle(block.Number(), block.Time())) } // JS tracers have high overhead. In this case run a parallel @@ -782,7 +782,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block core.ProcessBeaconBlockRoot(*beaconRoot, evm) } if chainConfig.IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm) + core.ProcessParentBlockHash(block.ParentHash(), evm, api.backend.ChainConfig().IsVerkle(block.Number(), block.Time())) } for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution diff --git a/miner/worker.go b/miner/worker.go index b5aa08002591..d4b7e0b39930 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -231,7 +231,7 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm) } if miner.chainConfig.IsPrague(header.Number, header.Time) { - core.ProcessParentBlockHash(header.ParentHash, env.evm) + core.ProcessParentBlockHash(header.ParentHash, env.evm, false) } return env, nil }