From 20f1d2ceed9006276f06ea0d7725169a115bc39e Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 4 Apr 2024 06:30:52 +0200 Subject: [PATCH 01/18] core: implement eip-2935 Co-authored-by: Guillaume Ballet Co-authored-by: Ignacio Hagopian --- cmd/evm/internal/t8ntool/execution.go | 10 +++++ core/genesis.go | 2 + core/state_processor.go | 38 ++++++++++++++++++ core/state_processor_test.go | 55 +++++++++++++++++++++++++++ core/vm/instructions.go | 20 ++++++++-- core/vm/jump_table.go | 5 +++ miner/worker.go | 3 ++ params/protocol_params.go | 9 +++++ 8 files changed, 138 insertions(+), 4 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 3c09229e1c5c..bf6b6ef3c789 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -196,6 +196,16 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } + if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) { + // insert all parent hashes in the contract + for i, h := range pre.Env.BlockHashes { + n := uint64(i) + if n >= pre.Env.Number || pre.Env.Number > (n+params.HistoryServeWindow) { + continue + } + core.ProcessParentBlockHash(statedb, n, h) + } + } for i := 0; txIt.Next(); i++ { tx, err := txIt.Tx() diff --git a/core/genesis.go b/core/genesis.go index 42836e026993..038477bf9fa6 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -593,6 +593,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b + // Pre-deploy EIP-2935 history contract. + params.HistoryStorageAddress: types.Account{Nonce: 1, Code: params.HistoryStorageCode}, }, } if faucet != nil { diff --git a/core/state_processor.go b/core/state_processor.go index 7166ed8bd872..5bc24c638637 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,6 +17,7 @@ package core import ( + "encoding/binary" "errors" "fmt" "math/big" @@ -80,6 +81,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if beaconRoot := block.BeaconRoot(); beaconRoot != nil { ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + if p.config.IsPrague(block.Number(), block.Time()) { + ProcessBlockHashHistory(statedb, block.Header(), p.config, p.bc) + } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { msg, err := TransactionToMessage(tx, signer, header.BaseFee) @@ -209,3 +213,37 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) statedb.Finalise(true) } + +// ProcessBlockHashHistory is called at every block to insert the parent block hash +// in the history storage contract as per EIP-2935. At the EIP-2935 fork block, it +// populates the whole buffer with block hashes. +func ProcessBlockHashHistory(statedb *state.StateDB, header *types.Header, chainConfig *params.ChainConfig, chain consensus.ChainHeaderReader) { + var ( + prevHash = header.ParentHash + parent = chain.GetHeaderByHash(prevHash) + number = header.Number.Uint64() + prevNumber = parent.Number.Uint64() + ) + ProcessParentBlockHash(statedb, prevNumber, prevHash) + // History already inserted. + if chainConfig.IsPrague(parent.Number, parent.Time) || prevNumber == 0 { + return + } + var low uint64 + if number > params.HistoryServeWindow { + low = number - params.HistoryServeWindow + } + for i := prevNumber; i > low; i-- { + ProcessParentBlockHash(statedb, i-1, parent.ParentHash) + parent = chain.GetHeader(parent.ParentHash, i-1) + } +} + +// ProcessParentBlockHash stores the parent block hash in the history storage contract +// as per EIP-2935. +func ProcessParentBlockHash(statedb *state.StateDB, prevNumber uint64, prevHash common.Hash) { + ringIndex := prevNumber % params.HistoryServeWindow + var key common.Hash + binary.BigEndian.PutUint64(key[24:], ringIndex) + statedb.SetState(params.HistoryStorageAddress, key, prevHash) +} diff --git a/core/state_processor_test.go b/core/state_processor_test.go index af4d29b604da..2caea37ecd82 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -18,6 +18,7 @@ package core import ( "crypto/ecdsa" + "encoding/binary" "math/big" "testing" @@ -29,9 +30,11 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip1559" "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" "github.com/holiman/uint256" @@ -528,3 +531,55 @@ func TestProcessVerkle(t *testing.T) { } } } + +type MockChain struct { + chain map[common.Hash]*types.Header +} + +func (m *MockChain) Config() *params.ChainConfig { return nil } + +func (m *MockChain) CurrentHeader() *types.Header { return nil } + +func (m *MockChain) GetHeaderByNumber(number uint64) *types.Header { return nil } + +func (m *MockChain) GetTd(hash common.Hash, number uint64) *big.Int { return nil } + +func (m *MockChain) GetHeaderByHash(hash common.Hash) *types.Header { + return m.chain[hash] +} + +func (m *MockChain) GetHeader(hash common.Hash, number uint64) *types.Header { + return m.chain[hash] +} + +func TestProcessBlockHashHistory(t *testing.T) { + hashA := common.Hash{0x01} + hashB := common.Hash{0x02} + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + header := &types.Header{ParentHash: hashA, Number: big.NewInt(2)} + parent := &types.Header{ParentHash: hashB, Number: big.NewInt(1)} + parentParent := &types.Header{ParentHash: common.Hash{}, Number: big.NewInt(0)} + chainConfig := params.AllDevChainProtocolChanges + chainConfig.PragueTime = nil + chain := new(MockChain) + chain.chain = make(map[common.Hash]*types.Header) + chain.chain[hashA] = parent + chain.chain[hashB] = parentParent + + ProcessBlockHashHistory(statedb, header, chainConfig, chain) + + // make sure that the state is correct + if have := getParentBlockHash(statedb, 1); have != hashA { + t.Fail() + } + if have := getParentBlockHash(statedb, 0); have != hashB { + t.Fail() + } +} + +func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash { + ringIndex := number % params.HistoryServeWindow + var key common.Hash + binary.BigEndian.PutUint64(key[24:], ringIndex) + return statedb.GetState(params.HistoryStorageAddress, key) +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 10cdd72e0c57..fb82dc1509ea 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,6 +17,7 @@ package vm import ( + "encoding/binary" "math" "github.com/ethereum/go-ethereum/common" @@ -434,16 +435,27 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( num.Clear() return nil, nil } - + historySize := uint64(256) + isPrague := interpreter.evm.ChainConfig().IsPrague(interpreter.evm.Context.BlockNumber, interpreter.evm.Context.Time) + // EIP-2935 extends the observable history window. + if isPrague { + historySize = params.HistoryServeWindow + } var upper, lower uint64 upper = interpreter.evm.Context.BlockNumber.Uint64() - if upper < 257 { + if upper < historySize+1 { lower = 0 } else { - lower = upper - 256 + lower = upper - historySize } if num64 >= lower && num64 < upper { - num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes()) + if isPrague { + var key common.Hash + binary.BigEndian.PutUint64(key[24:], num64 % params.HistoryServeWindow) + num.SetBytes(interpreter.evm.StateDB.GetState(params.HistoryStorageAddress, key).Bytes()) + } else { + num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes()) + } } else { num.Clear() } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 5624f47ba72c..229d765847f0 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -87,6 +87,11 @@ func newVerkleInstructionSet() JumpTable { return validate(instructionSet) } +func newPraugeInstructionSet() JumpTable { + instructionSet := newCancunInstructionSet() + return validate(instructionSet) +} + func newCancunInstructionSet() JumpTable { instructionSet := newShanghaiInstructionSet() enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode) diff --git a/miner/worker.go b/miner/worker.go index 5dc3e2056b81..91c4836e53dc 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -200,6 +200,9 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) } + if miner.chainConfig.IsPrague(header.Number, header.Time) { + core.ProcessBlockHashHistory(env.state, header, miner.chainConfig, miner.chain) + } return env, nil } diff --git a/params/protocol_params.go b/params/protocol_params.go index d375a9664273..a07efe48bcba 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -174,6 +174,8 @@ const ( BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing) MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block + + HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935. ) // Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations @@ -189,4 +191,11 @@ var ( BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02") // SystemAddress is where the system-transaction is sent from as per EIP-4788 SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe") + // HistoryStorageAddress is where the historical block hashes are stored. + HistoryStorageAddress = common.HexToAddress("0x25a219378dad9b3503c8268c9ca836a52427a4fb") + // HistoryStorageCode is the code with getters for historical block hashes. + HistoryStorageCode = common.FromHex("60203611603157600143035f35116029575f356120000143116029576120005f3506545f5260205ff35b5f5f5260205ff35b5f5ffd00") + + // Magic prefix for EIP-3074 AUTH messages. + AuthMagic = byte(0x04) ) From 83ceaacf2e1e455af4fa4945d7adb921214cebff Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 29 May 2024 15:03:32 +0200 Subject: [PATCH 02/18] Update to devnet-1 spec --- cmd/evm/internal/t8ntool/execution.go | 14 +++++-------- core/state_processor.go | 30 +++------------------------ core/state_processor_test.go | 27 +++++++++++------------- core/vm/instructions.go | 19 +++-------------- miner/worker.go | 2 +- tests/testdata | 2 +- 6 files changed, 25 insertions(+), 69 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index bf6b6ef3c789..bc807f7af69f 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -197,16 +197,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) } if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) { - // insert all parent hashes in the contract - for i, h := range pre.Env.BlockHashes { - n := uint64(i) - if n >= pre.Env.Number || pre.Env.Number > (n+params.HistoryServeWindow) { - continue - } - core.ProcessParentBlockHash(statedb, n, h) - } + var ( + prevNumber = pre.Env.Number - 1 + prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)] + ) + core.ProcessParentBlockHash(statedb, prevHash, prevNumber) } - for i := 0; txIt.Next(); i++ { tx, err := txIt.Tx() if err != nil { diff --git a/core/state_processor.go b/core/state_processor.go index 5bc24c638637..66c10c627cf6 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -82,7 +82,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } if p.config.IsPrague(block.Number(), block.Time()) { - ProcessBlockHashHistory(statedb, block.Header(), p.config, p.bc) + // This should not underflow as genesis block is not processed. + ProcessParentBlockHash(statedb, block.ParentHash(), block.NumberU64()-1) } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { @@ -214,34 +215,9 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat statedb.Finalise(true) } -// ProcessBlockHashHistory is called at every block to insert the parent block hash -// in the history storage contract as per EIP-2935. At the EIP-2935 fork block, it -// populates the whole buffer with block hashes. -func ProcessBlockHashHistory(statedb *state.StateDB, header *types.Header, chainConfig *params.ChainConfig, chain consensus.ChainHeaderReader) { - var ( - prevHash = header.ParentHash - parent = chain.GetHeaderByHash(prevHash) - number = header.Number.Uint64() - prevNumber = parent.Number.Uint64() - ) - ProcessParentBlockHash(statedb, prevNumber, prevHash) - // History already inserted. - if chainConfig.IsPrague(parent.Number, parent.Time) || prevNumber == 0 { - return - } - var low uint64 - if number > params.HistoryServeWindow { - low = number - params.HistoryServeWindow - } - for i := prevNumber; i > low; i-- { - ProcessParentBlockHash(statedb, i-1, parent.ParentHash) - parent = chain.GetHeader(parent.ParentHash, i-1) - } -} - // ProcessParentBlockHash stores the parent block hash in the history storage contract // as per EIP-2935. -func ProcessParentBlockHash(statedb *state.StateDB, prevNumber uint64, prevHash common.Hash) { +func ProcessParentBlockHash(statedb *state.StateDB, prevHash common.Hash, prevNumber uint64) { ringIndex := prevNumber % params.HistoryServeWindow var key common.Hash binary.BigEndian.PutUint64(key[24:], ringIndex) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 2caea37ecd82..e8da52498274 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -552,21 +552,18 @@ func (m *MockChain) GetHeader(hash common.Hash, number uint64) *types.Header { return m.chain[hash] } -func TestProcessBlockHashHistory(t *testing.T) { - hashA := common.Hash{0x01} - hashB := common.Hash{0x02} - statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - header := &types.Header{ParentHash: hashA, Number: big.NewInt(2)} - parent := &types.Header{ParentHash: hashB, Number: big.NewInt(1)} - parentParent := &types.Header{ParentHash: common.Hash{}, Number: big.NewInt(0)} - chainConfig := params.AllDevChainProtocolChanges - chainConfig.PragueTime = nil - chain := new(MockChain) - chain.chain = make(map[common.Hash]*types.Header) - chain.chain[hashA] = parent - chain.chain[hashB] = parentParent - - ProcessBlockHashHistory(statedb, header, chainConfig, chain) +func TestProcessParentBlockHash(t *testing.T) { + var ( + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + hashA = common.Hash{0x01} + hashB = common.Hash{0x02} + header = &types.Header{ParentHash: hashA, Number: big.NewInt(2)} + parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1)} + genesis = &types.Header{ParentHash: common.Hash{}, Number: big.NewInt(0)} + ) + + ProcessParentBlockHash(statedb, header.ParentHash, parent.Number.Uint64()) + ProcessParentBlockHash(statedb, parent.ParentHash, genesis.Number.Uint64()) // make sure that the state is correct if have := getParentBlockHash(statedb, 1); have != hashA { diff --git a/core/vm/instructions.go b/core/vm/instructions.go index fb82dc1509ea..9330c5f2e58e 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,7 +17,6 @@ package vm import ( - "encoding/binary" "math" "github.com/ethereum/go-ethereum/common" @@ -435,27 +434,15 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( num.Clear() return nil, nil } - historySize := uint64(256) - isPrague := interpreter.evm.ChainConfig().IsPrague(interpreter.evm.Context.BlockNumber, interpreter.evm.Context.Time) - // EIP-2935 extends the observable history window. - if isPrague { - historySize = params.HistoryServeWindow - } var upper, lower uint64 upper = interpreter.evm.Context.BlockNumber.Uint64() - if upper < historySize+1 { + if upper < 257 { lower = 0 } else { - lower = upper - historySize + lower = upper - 256 } if num64 >= lower && num64 < upper { - if isPrague { - var key common.Hash - binary.BigEndian.PutUint64(key[24:], num64 % params.HistoryServeWindow) - num.SetBytes(interpreter.evm.StateDB.GetState(params.HistoryStorageAddress, key).Bytes()) - } else { - num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes()) - } + num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes()) } else { num.Clear() } diff --git a/miner/worker.go b/miner/worker.go index 91c4836e53dc..da72685422b5 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -201,7 +201,7 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) } if miner.chainConfig.IsPrague(header.Number, header.Time) { - core.ProcessBlockHashHistory(env.state, header, miner.chainConfig, miner.chain) + core.ProcessParentBlockHash(env.state, header.ParentHash, header.Number.Uint64()-1) } return env, nil } diff --git a/tests/testdata b/tests/testdata index fa51c5c164f7..faf33b471465 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit fa51c5c164f79140730ccb8fe26a46c3d3994338 +Subproject commit faf33b471465d3c6cdc3d04fbd690895f78d33f2 From 7ab6a20938bf65ede781415bceec88ceaedc8a75 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 29 May 2024 15:06:59 +0200 Subject: [PATCH 03/18] rm mockchain --- core/state_processor_test.go | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index e8da52498274..7beda2764bfb 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -532,26 +532,6 @@ func TestProcessVerkle(t *testing.T) { } } -type MockChain struct { - chain map[common.Hash]*types.Header -} - -func (m *MockChain) Config() *params.ChainConfig { return nil } - -func (m *MockChain) CurrentHeader() *types.Header { return nil } - -func (m *MockChain) GetHeaderByNumber(number uint64) *types.Header { return nil } - -func (m *MockChain) GetTd(hash common.Hash, number uint64) *big.Int { return nil } - -func (m *MockChain) GetHeaderByHash(hash common.Hash) *types.Header { - return m.chain[hash] -} - -func (m *MockChain) GetHeader(hash common.Hash, number uint64) *types.Header { - return m.chain[hash] -} - func TestProcessParentBlockHash(t *testing.T) { var ( statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) From a79c2187cccae3d8a01ec15c5b31115740d735fb Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Wed, 29 May 2024 15:09:27 +0200 Subject: [PATCH 04/18] minor --- core/vm/instructions.go | 1 + core/vm/jump_table.go | 5 ----- params/protocol_params.go | 3 --- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 9330c5f2e58e..10cdd72e0c57 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -434,6 +434,7 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( num.Clear() return nil, nil } + var upper, lower uint64 upper = interpreter.evm.Context.BlockNumber.Uint64() if upper < 257 { diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 229d765847f0..5624f47ba72c 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -87,11 +87,6 @@ func newVerkleInstructionSet() JumpTable { return validate(instructionSet) } -func newPraugeInstructionSet() JumpTable { - instructionSet := newCancunInstructionSet() - return validate(instructionSet) -} - func newCancunInstructionSet() JumpTable { instructionSet := newShanghaiInstructionSet() enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode) diff --git a/params/protocol_params.go b/params/protocol_params.go index a07efe48bcba..7aeb5a89e33d 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -195,7 +195,4 @@ var ( HistoryStorageAddress = common.HexToAddress("0x25a219378dad9b3503c8268c9ca836a52427a4fb") // HistoryStorageCode is the code with getters for historical block hashes. HistoryStorageCode = common.FromHex("60203611603157600143035f35116029575f356120000143116029576120005f3506545f5260205ff35b5f5f5260205ff35b5f5ffd00") - - // Magic prefix for EIP-3074 AUTH messages. - AuthMagic = byte(0x04) ) From 84d9e40ac5bda8188378d790cbafa746b4d251a3 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 13 Jun 2024 14:24:05 +0200 Subject: [PATCH 05/18] update contract code & addr --- params/protocol_params.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/params/protocol_params.go b/params/protocol_params.go index 2a4ecdc4f210..638f58a33992 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -196,7 +196,7 @@ var ( // SystemAddress is where the system-transaction is sent from as per EIP-4788 SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe") // HistoryStorageAddress is where the historical block hashes are stored. - HistoryStorageAddress = common.HexToAddress("0x25a219378dad9b3503c8268c9ca836a52427a4fb") + HistoryStorageAddress = common.HexToAddress("0x0aae40965e6800cd9b1f4b05ff21581047e3f91e") // HistoryStorageCode is the code with getters for historical block hashes. - HistoryStorageCode = common.FromHex("60203611603157600143035f35116029575f356120000143116029576120005f3506545f5260205ff35b5f5f5260205ff35b5f5ffd00") + HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500") ) From e273b68321125ab04e5ee74f58f29f1adeb60b4c Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 13 Jun 2024 14:27:00 +0200 Subject: [PATCH 06/18] minor: --- core/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index 3329e7da9eb3..385a7b74b92a 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -594,7 +594,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b // Pre-deploy EIP-4788 system contract - params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode}, + params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, // Pre-deploy EIP-2935 history contract. params.HistoryStorageAddress: types.Account{Nonce: 1, Code: params.HistoryStorageCode}, }, From 6fbfc05b205700549fa44e68c380b3c900941da6 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 8 Jul 2024 16:59:53 +0200 Subject: [PATCH 07/18] review comment --- core/genesis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index 385a7b74b92a..c1d3f69fc498 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -596,7 +596,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis { // Pre-deploy EIP-4788 system contract params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0}, // Pre-deploy EIP-2935 history contract. - params.HistoryStorageAddress: types.Account{Nonce: 1, Code: params.HistoryStorageCode}, + params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode}, }, } if faucet != nil { From dddd593c7764195ecc03207ed2d95bc1a867626b Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 8 Jul 2024 21:43:16 +0200 Subject: [PATCH 08/18] Call evm code for setting parent hash --- cmd/evm/internal/t8ntool/execution.go | 3 ++- core/state_processor.go | 29 +++++++++++++++++++------- core/state_processor_test.go | 30 ++++++++++++++++++--------- 3 files changed, 44 insertions(+), 18 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index bc807f7af69f..b166d3ff88e4 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -200,8 +200,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, var ( prevNumber = pre.Env.Number - 1 prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)] + evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) ) - core.ProcessParentBlockHash(statedb, prevHash, prevNumber) + core.ProcessParentBlockHash(statedb, evm, prevHash, prevNumber) } for i := 0; txIt.Next(); i++ { tx, err := txIt.Tx() diff --git a/core/state_processor.go b/core/state_processor.go index 66c10c627cf6..b2f97ca5ce73 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,7 +17,6 @@ package core import ( - "encoding/binary" "errors" "fmt" "math/big" @@ -83,7 +82,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } if p.config.IsPrague(block.Number(), block.Time()) { // This should not underflow as genesis block is not processed. - ProcessParentBlockHash(statedb, block.ParentHash(), block.NumberU64()-1) + ProcessParentBlockHash(statedb, vmenv, block.ParentHash(), block.NumberU64()-1) } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { @@ -217,9 +216,25 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat // ProcessParentBlockHash stores the parent block hash in the history storage contract // as per EIP-2935. -func ProcessParentBlockHash(statedb *state.StateDB, prevHash common.Hash, prevNumber uint64) { - ringIndex := prevNumber % params.HistoryServeWindow - var key common.Hash - binary.BigEndian.PutUint64(key[24:], ringIndex) - statedb.SetState(params.HistoryStorageAddress, key, prevHash) +func ProcessParentBlockHash(statedb *state.StateDB, vmenv *vm.EVM, prevHash common.Hash) { + if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil { + vmenv.Config.Tracer.OnSystemCallStart() + } + if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil { + defer vmenv.Config.Tracer.OnSystemCallEnd() + } + + msg := &Message{ + From: params.SystemAddress, + GasLimit: 30_000_000, + GasPrice: common.Big0, + GasFeeCap: common.Big0, + GasTipCap: common.Big0, + To: ¶ms.HistoryStorageAddress, + Data: prevHash.Bytes(), + } + vmenv.Reset(NewEVMTxContext(msg), statedb) + statedb.AddAddressToAccessList(params.HistoryStorageAddress) + _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) + statedb.Finalise(true) } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 7beda2764bfb..2ce46989669e 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -534,23 +534,33 @@ func TestProcessVerkle(t *testing.T) { func TestProcessParentBlockHash(t *testing.T) { var ( - statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) - hashA = common.Hash{0x01} - hashB = common.Hash{0x02} - header = &types.Header{ParentHash: hashA, Number: big.NewInt(2)} - parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1)} - genesis = &types.Header{ParentHash: common.Hash{}, Number: big.NewInt(0)} + chainConfig = params.MergedTestChainConfig + statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + hashA = common.Hash{0x01} + hashB = common.Hash{0x02} + header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)} + parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)} + genesis = &types.Header{ParentHash: common.Hash{}, Number: big.NewInt(0)} + coinbase = common.Address{} ) + statedb.SetNonce(params.HistoryStorageAddress, 1) + statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) + statedb.IntermediateRoot(true) - ProcessParentBlockHash(statedb, header.ParentHash, parent.Number.Uint64()) - ProcessParentBlockHash(statedb, parent.ParentHash, genesis.Number.Uint64()) + vmContext := NewEVMBlockContext(header, nil, &coinbase) + evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + ProcessParentBlockHash(statedb, evm, header.ParentHash, parent.Number.Uint64()) + + vmContext = NewEVMBlockContext(parent, nil, &coinbase) + evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + ProcessParentBlockHash(statedb, evm, parent.ParentHash, genesis.Number.Uint64()) // make sure that the state is correct if have := getParentBlockHash(statedb, 1); have != hashA { - t.Fail() + t.Errorf("expected parent hash %v, got %v", hashA, have) } if have := getParentBlockHash(statedb, 0); have != hashB { - t.Fail() + t.Errorf("expected parent hash %v, got %v", hashB, have) } } From 3d12e68d247c3b8d170d4d1311dd85a02f27b7c7 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 8 Jul 2024 21:49:19 +0200 Subject: [PATCH 09/18] Fix block num --- cmd/evm/internal/t8ntool/execution.go | 2 +- core/state_processor.go | 2 +- core/state_processor_test.go | 4 ++-- miner/worker.go | 11 ++++++++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index b166d3ff88e4..d39d3641f5c2 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -202,7 +202,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)] evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) ) - core.ProcessParentBlockHash(statedb, evm, prevHash, prevNumber) + core.ProcessParentBlockHash(statedb, evm, prevHash) } for i := 0; txIt.Next(); i++ { tx, err := txIt.Tx() diff --git a/core/state_processor.go b/core/state_processor.go index b2f97ca5ce73..09feb7996550 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -82,7 +82,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } if p.config.IsPrague(block.Number(), block.Time()) { // This should not underflow as genesis block is not processed. - ProcessParentBlockHash(statedb, vmenv, block.ParentHash(), block.NumberU64()-1) + ProcessParentBlockHash(statedb, vmenv, block.ParentHash()) } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 2ce46989669e..a4d6b47e9646 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -549,11 +549,11 @@ func TestProcessParentBlockHash(t *testing.T) { vmContext := NewEVMBlockContext(header, nil, &coinbase) evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) - ProcessParentBlockHash(statedb, evm, header.ParentHash, parent.Number.Uint64()) + ProcessParentBlockHash(statedb, evm, header.ParentHash) vmContext = NewEVMBlockContext(parent, nil, &coinbase) evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) - ProcessParentBlockHash(statedb, evm, parent.ParentHash, genesis.Number.Uint64()) + ProcessParentBlockHash(statedb, evm, parent.ParentHash) // make sure that the state is correct if have := getParentBlockHash(statedb, 1); have != hashA { diff --git a/miner/worker.go b/miner/worker.go index da72685422b5..9653a4a82695 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -195,13 +195,18 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) log.Error("Failed to create sealing context", "err", err) return nil, err } + var ( + context vm.BlockContext + vmenv *vm.EVM + ) if header.ParentBeaconRoot != nil { - context := core.NewEVMBlockContext(header, miner.chain, nil) - vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) + context = core.NewEVMBlockContext(header, miner.chain, nil) + vmenv = vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) } if miner.chainConfig.IsPrague(header.Number, header.Time) { - core.ProcessParentBlockHash(env.state, header.ParentHash, header.Number.Uint64()-1) + // Prague is enabled after Cancun so vmenv should be initalized. + core.ProcessParentBlockHash(env.state, vmenv, header.ParentHash) } return env, nil } From 0853d74b4078bc09ed88c1e3e10c472d7f7b2aa5 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 9 Jul 2024 14:19:50 +0200 Subject: [PATCH 10/18] fix lint err --- core/state_processor_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index a4d6b47e9646..fd209576a3c2 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -540,7 +540,6 @@ func TestProcessParentBlockHash(t *testing.T) { hashB = common.Hash{0x02} header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)} parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)} - genesis = &types.Header{ParentHash: common.Hash{}, Number: big.NewInt(0)} coinbase = common.Address{} ) statedb.SetNonce(params.HistoryStorageAddress, 1) From 03c410d0bfc63edbab0e081a65a90f2ec2db72a4 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 9 Jul 2024 17:20:19 +0200 Subject: [PATCH 11/18] fix typo --- miner/worker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miner/worker.go b/miner/worker.go index 9653a4a82695..0bc822dc6d9f 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -205,7 +205,7 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) } if miner.chainConfig.IsPrague(header.Number, header.Time) { - // Prague is enabled after Cancun so vmenv should be initalized. + // Prague is enabled after Cancun so vmenv should be initialized. core.ProcessParentBlockHash(env.state, vmenv, header.ParentHash) } return env, nil From 36933e02e04770c7a93373998f51e72bac4ff093 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 9 Jul 2024 17:36:02 +0200 Subject: [PATCH 12/18] add verkle to test --- core/state_processor_test.go | 46 +++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index fd209576a3c2..510cb5723a95 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -37,6 +37,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" + "github.com/ethereum/go-ethereum/triedb" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) @@ -535,32 +536,45 @@ func TestProcessVerkle(t *testing.T) { func TestProcessParentBlockHash(t *testing.T) { var ( chainConfig = params.MergedTestChainConfig - statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) hashA = common.Hash{0x01} hashB = common.Hash{0x02} header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)} parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)} coinbase = common.Address{} ) - statedb.SetNonce(params.HistoryStorageAddress, 1) - statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) - statedb.IntermediateRoot(true) + test := func(statedb *state.StateDB) { + statedb.SetNonce(params.HistoryStorageAddress, 1) + statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode) + statedb.IntermediateRoot(true) - vmContext := NewEVMBlockContext(header, nil, &coinbase) - evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) - ProcessParentBlockHash(statedb, evm, header.ParentHash) + vmContext := NewEVMBlockContext(header, nil, &coinbase) + evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + ProcessParentBlockHash(statedb, evm, header.ParentHash) - vmContext = NewEVMBlockContext(parent, nil, &coinbase) - evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) - ProcessParentBlockHash(statedb, evm, parent.ParentHash) + vmContext = NewEVMBlockContext(parent, nil, &coinbase) + evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + ProcessParentBlockHash(statedb, evm, parent.ParentHash) - // make sure that the state is correct - if have := getParentBlockHash(statedb, 1); have != hashA { - t.Errorf("expected parent hash %v, got %v", hashA, have) - } - if have := getParentBlockHash(statedb, 0); have != hashB { - t.Errorf("expected parent hash %v, got %v", hashB, have) + // make sure that the state is correct + if have := getParentBlockHash(statedb, 1); have != hashA { + t.Errorf("expected parent hash %v, got %v", hashA, have) + } + if have := getParentBlockHash(statedb, 0); have != hashB { + t.Errorf("expected parent hash %v, got %v", hashB, have) + } } + t.Run("MPT", func(t *testing.T) { + statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil) + test(statedb) + }) + t.Run("Verkle", func(t *testing.T) { + db := rawdb.NewMemoryDatabase() + cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme) + cacheConfig.SnapshotLimit = 0 + triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true)) + statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabaseWithNodeDB(db, triedb), nil) + test(statedb) + }) } func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash { From dd282c5a64827e627506f07192bcb23739bb55a1 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 9 Jul 2024 18:26:02 +0200 Subject: [PATCH 13/18] process history contract in tracing API --- eth/tracers/api.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 51b55ffdbb1b..d7155d00f766 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -382,6 +382,12 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + // Insert parent hash in history contract. + if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) { + context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) + core.ProcessParentBlockHash(statedb, vmenv, next.ParentHash()) + } // Clean out any pending release functions of trace state. Note this // step must be done after constructing tracing state, because the // tracing state of block next depends on the parent state and construction @@ -534,6 +540,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + if chainConfig.IsPrague(block.Number(), block.Time()) { + core.ProcessParentBlockHash(statedb, vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}), block.ParentHash()) + } for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { return nil, err @@ -613,6 +622,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) { + vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) + core.ProcessParentBlockHash(statedb, vmenv, block.ParentHash()) + } for i, tx := range txs { // Generate the next state snapshot fast without tracing msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) @@ -771,6 +784,10 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + if chainConfig.IsPrague(block.Number(), block.Time()) { + vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) + core.ProcessParentBlockHash(statedb, vmenv, block.ParentHash()) + } for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution var ( From 710657305d3c23d9983a04034e92fa804aa42fa7 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Tue, 9 Jul 2024 18:29:14 +0200 Subject: [PATCH 14/18] fix stateAtTransaction --- eth/state_accessor.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 372c76f49692..11ca44f76720 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -239,6 +239,12 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } + // If prague hardfork, Insert parent block hash in the state as per EIP-2935. + if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) { + context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) + core.ProcessParentBlockHash(statedb, vmenv, block.ParentHash()) + } if txIndex == 0 && len(block.Transactions()) == 0 { return nil, vm.BlockContext{}, statedb, release, nil } From 998cfd857333548822ea40a880fe38d38a892d31 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Mon, 29 Jul 2024 11:27:27 +0200 Subject: [PATCH 15/18] reinit vmenv in miner --- miner/worker.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 0bc822dc6d9f..ea0f04eaf956 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -195,17 +195,14 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) log.Error("Failed to create sealing context", "err", err) return nil, err } - var ( - context vm.BlockContext - vmenv *vm.EVM - ) if header.ParentBeaconRoot != nil { - context = core.NewEVMBlockContext(header, miner.chain, nil) - vmenv = vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) + context := core.NewEVMBlockContext(header, miner.chain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) } if miner.chainConfig.IsPrague(header.Number, header.Time) { - // Prague is enabled after Cancun so vmenv should be initialized. + context := core.NewEVMBlockContext(header, miner.chain, nil) + vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) core.ProcessParentBlockHash(env.state, vmenv, header.ParentHash) } return env, nil From 09ac0941157ab83d64f35c195930ff0b83a29a43 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 1 Aug 2024 15:49:24 +0200 Subject: [PATCH 16/18] change param ordering --- cmd/evm/internal/t8ntool/execution.go | 2 +- core/state_processor.go | 4 ++-- core/state_processor_test.go | 4 ++-- eth/state_accessor.go | 2 +- eth/tracers/api.go | 8 ++++---- miner/worker.go | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index d39d3641f5c2..f2b9c573e46a 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -202,7 +202,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)] evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) ) - core.ProcessParentBlockHash(statedb, evm, prevHash) + core.ProcessParentBlockHash(prevHash, evm, statedb) } for i := 0; txIt.Next(); i++ { tx, err := txIt.Tx() diff --git a/core/state_processor.go b/core/state_processor.go index 09feb7996550..5a86931106e8 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -82,7 +82,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } if p.config.IsPrague(block.Number(), block.Time()) { // This should not underflow as genesis block is not processed. - ProcessParentBlockHash(statedb, vmenv, block.ParentHash()) + ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { @@ -216,7 +216,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat // ProcessParentBlockHash stores the parent block hash in the history storage contract // as per EIP-2935. -func ProcessParentBlockHash(statedb *state.StateDB, vmenv *vm.EVM, prevHash common.Hash) { +func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil { vmenv.Config.Tracer.OnSystemCallStart() } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 510cb5723a95..43150933690b 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -549,11 +549,11 @@ func TestProcessParentBlockHash(t *testing.T) { vmContext := NewEVMBlockContext(header, nil, &coinbase) evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) - ProcessParentBlockHash(statedb, evm, header.ParentHash) + ProcessParentBlockHash(header.ParentHash, evm, statedb) vmContext = NewEVMBlockContext(parent, nil, &coinbase) evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{}) - ProcessParentBlockHash(statedb, evm, parent.ParentHash) + ProcessParentBlockHash(parent.ParentHash, evm, statedb) // make sure that the state is correct if have := getParentBlockHash(statedb, 1); have != hashA { diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 11ca44f76720..94c497737600 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -243,7 +243,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) { context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) - core.ProcessParentBlockHash(statedb, vmenv, block.ParentHash()) + core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) } 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 d7155d00f766..9ee108d0f12f 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 if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) { context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) - core.ProcessParentBlockHash(statedb, vmenv, next.ParentHash()) + core.ProcessParentBlockHash(next.ParentHash(), vmenv, statedb) } // 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, vmenv, statedb) } if chainConfig.IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(statedb, vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}), block.ParentHash()) + core.ProcessParentBlockHash(block.ParentHash(), vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}), statedb) } for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { @@ -624,7 +624,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac } if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) { vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{}) - core.ProcessParentBlockHash(statedb, vmenv, block.ParentHash()) + core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) } for i, tx := range txs { // Generate the next state snapshot fast without tracing @@ -786,7 +786,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } if chainConfig.IsPrague(block.Number(), block.Time()) { vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}) - core.ProcessParentBlockHash(statedb, vmenv, block.ParentHash()) + core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) } for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution diff --git a/miner/worker.go b/miner/worker.go index ea0f04eaf956..d38edd8249ec 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -203,7 +203,7 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) if miner.chainConfig.IsPrague(header.Number, header.Time) { context := core.NewEVMBlockContext(header, miner.chain, nil) vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) - core.ProcessParentBlockHash(env.state, vmenv, header.ParentHash) + core.ProcessParentBlockHash(header.ParentHash, vmenv, env.state) } return env, nil } From 1bf5bd80a3f2310b378621dceb368559407d5b06 Mon Sep 17 00:00:00 2001 From: Sina M <1591639+s1na@users.noreply.github.com> Date: Thu, 22 Aug 2024 20:53:48 +0200 Subject: [PATCH 17/18] Apply suggestions from code review Co-authored-by: Martin HS --- core/state_processor.go | 13 +++++++------ core/state_processor_test.go | 4 ++-- eth/state_accessor.go | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 5a86931106e8..b9ea5c4cc278 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -81,7 +81,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } if p.config.IsPrague(block.Number(), block.Time()) { - // This should not underflow as genesis block is not processed. ProcessParentBlockHash(block.ParentHash(), vmenv, statedb) } // Iterate over and process the individual transactions @@ -217,11 +216,13 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat // ProcessParentBlockHash stores the parent block hash in the history storage contract // as per EIP-2935. func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { - if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil { - vmenv.Config.Tracer.OnSystemCallStart() - } - if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil { - defer vmenv.Config.Tracer.OnSystemCallEnd() + if vmenv.Config.Tracer != nil { + if Config.Tracer.OnSystemCallStart != nil { + vmenv.Config.Tracer.OnSystemCallStart() + } + if vmenv.Config.Tracer.OnSystemCallEnd != nil { + defer vmenv.Config.Tracer.OnSystemCallEnd() + } } msg := &Message{ diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 43150933690b..bf29fb97733f 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -557,10 +557,10 @@ func TestProcessParentBlockHash(t *testing.T) { // make sure that the state is correct if have := getParentBlockHash(statedb, 1); have != hashA { - t.Errorf("expected parent hash %v, got %v", hashA, have) + t.Errorf("want parent hash %v, have %v", hashA, have) } if have := getParentBlockHash(statedb, 0); have != hashB { - t.Errorf("expected parent hash %v, got %v", hashB, have) + t.Errorf("want parent hash %v, have %v", hashB, have) } } t.Run("MPT", func(t *testing.T) { diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 94c497737600..90f7c013919b 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -239,7 +239,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) } - // If prague hardfork, Insert parent block hash in the state as per EIP-2935. + // If prague hardfork, insert parent block hash in the state as per EIP-2935. if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) { context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{}) From 28b4f5a293a591ad06a34463583c46ab221cb548 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Thu, 22 Aug 2024 20:56:38 +0200 Subject: [PATCH 18/18] refactor systemcall tracing invocations --- core/state_processor.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index b9ea5c4cc278..ed7c26946ad2 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -189,11 +189,13 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root // contract. This method is exported to be used in tests. func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { - if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil { - vmenv.Config.Tracer.OnSystemCallStart() - } - if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil { - defer vmenv.Config.Tracer.OnSystemCallEnd() + if tracer := vmenv.Config.Tracer; tracer != nil { + if tracer.OnSystemCallStart != nil { + tracer.OnSystemCallStart() + } + if tracer.OnSystemCallEnd != nil { + defer tracer.OnSystemCallEnd() + } } // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with @@ -216,12 +218,12 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat // ProcessParentBlockHash stores the parent block hash in the history storage contract // as per EIP-2935. func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { - if vmenv.Config.Tracer != nil { - if Config.Tracer.OnSystemCallStart != nil { - vmenv.Config.Tracer.OnSystemCallStart() + if tracer := vmenv.Config.Tracer; tracer != nil { + if tracer.OnSystemCallStart != nil { + tracer.OnSystemCallStart() } - if vmenv.Config.Tracer.OnSystemCallEnd != nil { - defer vmenv.Config.Tracer.OnSystemCallEnd() + if tracer.OnSystemCallEnd != nil { + defer tracer.OnSystemCallEnd() } }