From e3c5831e7cdb722c83bbb12142e673749f79ddd3 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Fri, 17 Mar 2023 09:22:58 +1000 Subject: [PATCH] core: Set L1CostFunc in NewEVMBlockContext (#71) Avoids potential for bugs where L1CostFunc is not manually set after creating the block context. --- accounts/abi/bind/backends/simulated.go | 3 +-- core/evm.go | 4 +++- core/state_prefetcher.go | 3 +-- core/state_processor.go | 6 ++---- eth/api_backend.go | 3 +-- eth/state_accessor.go | 3 +-- eth/tracers/api.go | 21 +++++++-------------- eth/tracers/api_test.go | 3 +-- les/api_backend.go | 3 +-- les/odr_test.go | 4 ++-- les/state_accessor.go | 3 +-- light/odr_test.go | 2 +- tests/state_test.go | 2 +- tests/state_test_util.go | 2 +- 14 files changed, 24 insertions(+), 38 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 2ed15e41b..26897e6b1 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -716,8 +716,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM msg := callMsg{call} txContext := core.NewEVMTxContext(msg) - evmContext := core.NewEVMBlockContext(block.Header(), b.blockchain, nil) - evmContext.L1CostFunc = types.NewL1CostFunc(b.config, stateDB) + evmContext := core.NewEVMBlockContext(block.Header(), b.blockchain, nil, b.config, stateDB) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true}) diff --git a/core/evm.go b/core/evm.go index 35e12338e..b705c0c7a 100644 --- a/core/evm.go +++ b/core/evm.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" ) // ChainContext supports retrieving headers and consensus parameters from the @@ -36,7 +37,7 @@ type ChainContext interface { } // NewEVMBlockContext creates a new context for use in the EVM. -func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address) vm.BlockContext { +func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common.Address, config *params.ChainConfig, statedb types.StateGetter) vm.BlockContext { var ( beneficiary common.Address baseFee *big.Int @@ -66,6 +67,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common BaseFee: baseFee, GasLimit: header.GasLimit, Random: random, + L1CostFunc: types.NewL1CostFunc(config, statedb), } } diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 4c0a782c1..76bec62e8 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -51,11 +51,10 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c var ( header = block.Header() gaspool = new(GasPool).AddGas(block.GasLimit()) - blockContext = NewEVMBlockContext(header, p.bc, nil) + blockContext = NewEVMBlockContext(header, p.bc, nil, p.config, statedb) evm = vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) signer = types.MakeSigner(p.config, header.Number) ) - blockContext.L1CostFunc = types.NewL1CostFunc(p.config, statedb) // Iterate over and process the individual transactions byzantium := p.config.IsByzantium(block.Number()) for i, tx := range block.Transactions() { diff --git a/core/state_processor.go b/core/state_processor.go index b0134fb70..933f611c3 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -70,8 +70,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) } - blockContext := NewEVMBlockContext(header, p.bc, nil) - blockContext.L1CostFunc = types.NewL1CostFunc(p.config, statedb) + blockContext := NewEVMBlockContext(header, p.bc, nil, p.config, statedb) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, p.config, cfg) // Iterate over and process the individual transactions for i, tx := range block.Transactions() { @@ -164,8 +163,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo return nil, err } // Create a new context to be used in the EVM environment - blockContext := NewEVMBlockContext(header, bc, author) - blockContext.L1CostFunc = types.NewL1CostFunc(config, statedb) + blockContext := NewEVMBlockContext(header, bc, author, config, statedb) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) } diff --git a/eth/api_backend.go b/eth/api_backend.go index f68532557..c001a1d64 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -232,8 +232,7 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *sta vmConfig = b.eth.blockchain.GetVMConfig() } txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(header, b.eth.BlockChain(), nil) - context.L1CostFunc = types.NewL1CostFunc(b.eth.blockchain.Config(), state) + context := core.NewEVMBlockContext(header, b.eth.BlockChain(), nil, b.eth.blockchain.Config(), state) return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error, nil } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 854039305..561e9c245 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -214,8 +214,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, // Assemble the transaction call message and return if the requested offset msg, _ := tx.AsMessage(signer, block.BaseFee()) txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) - context.L1CostFunc = types.NewL1CostFunc(eth.blockchain.Config(), statedb) + context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil, eth.blockchain.Config(), statedb) if idx == txIndex { return msg, context, statedb, release, nil } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index 12da9066a..2689c9387 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -290,9 +290,8 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed for task := range taskCh { var ( signer = types.MakeSigner(api.backend.ChainConfig(), task.block.Number()) - blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil) + blockCtx = core.NewEVMBlockContext(task.block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), task.statedb) ) - blockCtx.L1CostFunc = types.NewL1CostFunc(api.backend.ChainConfig(), task.statedb) // Trace all the transactions contained within for i, tx := range task.block.Transactions() { msg, _ := tx.AsMessage(signer, task.block.BaseFee()) @@ -576,10 +575,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config roots []common.Hash signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) chainConfig = api.backend.ChainConfig() - vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, chainConfig, statedb) deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) ) - vmctx.L1CostFunc = types.NewL1CostFunc(chainConfig, statedb) for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { return nil, err @@ -653,11 +651,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac txs = block.Transactions() blockHash = block.Hash() is158 = api.backend.ChainConfig().IsEIP158(block.Number()) - blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb) signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) results = make([]*txTraceResult, len(txs)) ) - blockCtx.L1CostFunc = types.NewL1CostFunc(api.backend.ChainConfig(), statedb) for i, tx := range txs { // Generate the next state snapshot fast without tracing msg, _ := tx.AsMessage(signer, block.BaseFee()) @@ -701,8 +698,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat defer pend.Done() // Fetch and execute the next transaction trace tasks for task := range jobs { - blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - blockCtx.L1CostFunc = types.NewL1CostFunc(api.backend.ChainConfig(), task.statedb) + blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), task.statedb) msg, _ := txs[task.index].AsMessage(signer, block.BaseFee()) txctx := &Context{ BlockHash: blockHash, @@ -721,8 +717,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat // Feed the transactions into the tracers and return var failed error - blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) - blockCtx.L1CostFunc = types.NewL1CostFunc(api.backend.ChainConfig(), statedb) + blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb) txloop: for i, tx := range txs { // Send the trace task over for execution @@ -800,7 +795,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block dumps []string signer = types.MakeSigner(api.backend.ChainConfig(), block.Number()) chainConfig = api.backend.ChainConfig() - vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, chainConfig, statedb) canon = true ) // Check if there are any overrides: the caller may wish to enable a future @@ -812,7 +807,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Note: This copies the config, to not screw up the main config chainConfig, canon = overrideConfig(chainConfig, config.Overrides) } - vmctx.L1CostFunc = types.NewL1CostFunc(chainConfig, statedb) for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution var ( @@ -972,7 +966,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc } defer release() - vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) + vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil, api.backend.ChainConfig(), statedb) // Apply the customization rules if required. if config != nil { if err := config.StateOverrides.Apply(statedb); err != nil { @@ -980,7 +974,6 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc } config.BlockOverrides.Apply(&vmctx) } - vmctx.L1CostFunc = types.NewL1CostFunc(api.backend.ChainConfig(), statedb) // Execute the trace msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee()) if err != nil { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 87e3001f6..96a7f7f7d 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -255,11 +255,10 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block for idx, tx := range block.Transactions() { msg, _ := tx.AsMessage(signer, block.BaseFee()) txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(block.Header(), b.chain, nil) + context := core.NewEVMBlockContext(block.Header(), b.chain, nil, b.chainConfig, statedb) if idx == txIndex { return msg, context, statedb, release, nil } - context.L1CostFunc = types.NewL1CostFunc(b.chainConfig, statedb) vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{}) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) diff --git a/les/api_backend.go b/les/api_backend.go index b292f4011..dc11fe97a 100644 --- a/les/api_backend.go +++ b/les/api_backend.go @@ -189,8 +189,7 @@ func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *sta vmConfig = new(vm.Config) } txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(header, b.eth.blockchain, nil) - context.L1CostFunc = types.NewL1CostFunc(b.eth.chainConfig, state) + context := core.NewEVMBlockContext(header, b.eth.blockchain, nil, b.eth.chainConfig, state) return vm.NewEVM(context, txContext, state, b.eth.chainConfig, *vmConfig), state.Error, nil } diff --git a/les/odr_test.go b/les/odr_test.go index e028d35e6..3a839bfb6 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -138,7 +138,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)} - context := core.NewEVMBlockContext(header, bc, nil) + context := core.NewEVMBlockContext(header, bc, nil, config, statedb) txContext := core.NewEVMTxContext(msg) vmenv := vm.NewEVM(context, txContext, statedb, config, vm.Config{NoBaseFee: true}) @@ -152,7 +152,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai state := light.NewState(ctx, header, lc.Odr()) state.SetBalance(bankAddr, math.MaxBig256) msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)} - context := core.NewEVMBlockContext(header, lc, nil) + context := core.NewEVMBlockContext(header, lc, nil, config, state) txContext := core.NewEVMTxContext(msg) vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true}) gp := new(core.GasPool).AddGas(math.MaxUint64) diff --git a/les/state_accessor.go b/les/state_accessor.go index 841b6b755..7bcf42bf3 100644 --- a/les/state_accessor.go +++ b/les/state_accessor.go @@ -62,12 +62,11 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types. // Assemble the transaction call message and return if the requested offset msg, _ := tx.AsMessage(signer, block.BaseFee()) txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil) + context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil, leth.blockchain.Config(), statedb) statedb.SetTxContext(tx.Hash(), idx) if idx == txIndex { return msg, context, statedb, release, nil } - context.L1CostFunc = types.NewL1CostFunc(leth.blockchain.Config(), statedb) // Not yet the searched for transaction, execute on top of the current state vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{}) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { diff --git a/light/odr_test.go b/light/odr_test.go index 903c7f6f9..e0d337b76 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -207,7 +207,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain st.SetBalance(testBankAddress, math.MaxBig256) msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true)} txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(header, chain, nil) + context := core.NewEVMBlockContext(header, chain, nil, config, st) vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true}) gp := new(core.GasPool).AddGas(math.MaxUint64) result, _ := core.ApplyMessage(vmenv, msg, gp) diff --git a/tests/state_test.go b/tests/state_test.go index 7dd2f678c..90d2d8cc7 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -222,7 +222,7 @@ func runBenchmark(b *testing.B, t *StateTest) { // Prepare the EVM. txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) + context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase, config, statedb) context.GetHash = vmTestBlockHash context.BaseFee = baseFee evm := vm.NewEVM(context, txContext, statedb, config, vmconfig) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index b2e87fb00..1fc59fdfa 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -245,7 +245,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // Prepare the EVM. txContext := core.NewEVMTxContext(msg) - context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) + context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase, config, statedb) context.GetHash = vmTestBlockHash context.BaseFee = baseFee context.Random = nil