From a793bc7f5f0e09c97a410797cfc24015c0083bae Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Fri, 29 Nov 2024 22:39:42 +0800 Subject: [PATCH] core: switch EVM tx context in ApplyMessage (#30809) This change relocates the EVM tx context switching to the ApplyMessage function. With this change, we can remove a lot of EVM.SetTxContext calls before message execution. ### Tracing API changes - This PR replaces the `GasPrice` field of the `VMContext` struct with `BaseFee`. Users may instead take the effective gas price from `tx.EffectiveGasTipValue(env.BaseFee)`. --------- Co-authored-by: Sina Mahmoodi --- cmd/evm/internal/t8ntool/execution.go | 7 ++-- core/block_validator.go | 2 +- core/state_prefetcher.go | 16 +++------ core/state_processor.go | 6 ---- core/state_transition.go | 29 ++++++++-------- core/tracing/hooks.go | 5 ++- core/vm/evm.go | 2 +- eth/gasestimator/gasestimator.go | 8 ++--- eth/state_accessor.go | 2 -- eth/tracers/api.go | 20 ++++------- eth/tracers/api_test.go | 2 -- .../internal/tracetest/calltrace_test.go | 33 ++++++++----------- .../internal/tracetest/flat_calltrace_test.go | 1 - .../internal/tracetest/prestate_test.go | 1 - eth/tracers/js/goja.go | 2 +- eth/tracers/js/tracer_test.go | 4 +-- eth/tracers/tracers_test.go | 8 +---- internal/ethapi/api.go | 11 +++---- internal/ethapi/simulate.go | 1 - tests/state_test_util.go | 2 -- 20 files changed, 57 insertions(+), 105 deletions(-) diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 6034b0d33a..7a0de86a11 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -253,16 +253,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, statedb.SetTxContext(tx.Hash(), txIndex) var ( - txContext = core.NewEVMTxContext(msg) - snapshot = statedb.Snapshot() - prevGas = gaspool.Gas() + snapshot = statedb.Snapshot() + prevGas = gaspool.Gas() ) if tracer != nil && tracer.OnTxStart != nil { tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) } // (ret []byte, usedGas uint64, failed bool, err error) - - evm.SetTxContext(txContext) msgResult, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { statedb.RevertToSnapshot(snapshot) diff --git a/core/block_validator.go b/core/block_validator.go index 59783a0407..5885df9ee2 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -93,7 +93,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { } // The individual checks for blob validity (version-check + not empty) - // happens in StateTransition. + // happens in state transition. } // Check blob gas usage. diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 3b987bb289..805df5ef62 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -65,7 +65,10 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c return // Also invalid block, bail out } statedb.SetTxContext(tx.Hash(), i) - if err := precacheTransaction(msg, gaspool, evm); err != nil { + + // We attempt to apply a transaction. The goal is not to execute + // the transaction successfully, rather to warm up touched data slots. + if _, err := ApplyMessage(evm, msg, gaspool); err != nil { return // Ugh, something went horribly wrong, bail out } // If we're pre-byzantium, pre-load trie nodes for the intermediate root @@ -78,14 +81,3 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c statedb.IntermediateRoot(true) } } - -// precacheTransaction attempts to apply a transaction to the given state database -// and uses the input parameters for its environment. The goal is not to execute -// the transaction successfully, rather to warm up touched data slots. -func precacheTransaction(msg *Message, gaspool *GasPool, evm *vm.EVM) error { - // Update the evm with the new transaction context. - evm.SetTxContext(NewEVMTxContext(msg)) - // Add addresses to access list if applicable - _, err := ApplyMessage(evm, msg, gaspool) - return err -} diff --git a/core/state_processor.go b/core/state_processor.go index 9472ab638b..d8637a2a52 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -140,17 +140,11 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, defer func() { hooks.OnTxEnd(receipt, err) }() } } - - // Create a new context to be used in the EVM environment. - txContext := NewEVMTxContext(msg) - evm.SetTxContext(txContext) - // Apply the transaction to the current state (included in the env). result, err := ApplyMessage(evm, msg, gp) if err != nil { return nil, err } - // Update the state with pending changes. var root []byte if evm.ChainConfig().IsByzantium(blockNumber) { diff --git a/core/state_transition.go b/core/state_transition.go index 4bd3c00167..ea7e3df2ff 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -187,10 +187,11 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In // indicates a core error meaning that the message would always fail for that particular // state and would never be accepted within a block. func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) { - return NewStateTransition(evm, msg, gp).TransitionDb() + evm.SetTxContext(NewEVMTxContext(msg)) + return newStateTransition(evm, msg, gp).execute() } -// StateTransition represents a state transition. +// stateTransition represents a state transition. // // == The State Transitioning Model // @@ -212,7 +213,7 @@ func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, err // // 5. Run Script section // 6. Derive new state root -type StateTransition struct { +type stateTransition struct { gp *GasPool msg *Message gasRemaining uint64 @@ -221,9 +222,9 @@ type StateTransition struct { evm *vm.EVM } -// NewStateTransition initialises and returns a new state transition object. -func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition { - return &StateTransition{ +// newStateTransition initialises and returns a new state transition object. +func newStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *stateTransition { + return &stateTransition{ gp: gp, evm: evm, msg: msg, @@ -232,14 +233,14 @@ func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition } // to returns the recipient of the message. -func (st *StateTransition) to() common.Address { +func (st *stateTransition) to() common.Address { if st.msg == nil || st.msg.To == nil /* contract creation */ { return common.Address{} } return *st.msg.To } -func (st *StateTransition) buyGas() error { +func (st *stateTransition) buyGas() error { mgval := new(big.Int).SetUint64(st.msg.GasLimit) mgval.Mul(mgval, st.msg.GasPrice) balanceCheck := new(big.Int).Set(mgval) @@ -283,7 +284,7 @@ func (st *StateTransition) buyGas() error { return nil } -func (st *StateTransition) preCheck() error { +func (st *stateTransition) preCheck() error { // Only check transactions that are not fake msg := st.msg if !msg.SkipNonceChecks { @@ -368,7 +369,7 @@ func (st *StateTransition) preCheck() error { return st.buyGas() } -// TransitionDb will transition the state by applying the current message and +// execute will transition the state by applying the current message and // returning the evm execution result with following fields. // // - used gas: total gas used (including gas being refunded) @@ -378,7 +379,7 @@ func (st *StateTransition) preCheck() error { // // However if any consensus issue encountered, return the error directly with // nil evm execution result. -func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { +func (st *stateTransition) execute() (*ExecutionResult, error) { // First check this message satisfies all consensus rules before // applying the message. The rules include these clauses // @@ -493,7 +494,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { }, nil } -func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { +func (st *stateTransition) refundGas(refundQuotient uint64) uint64 { // Apply refund counter, capped to a refund quotient refund := st.gasUsed() / refundQuotient if refund > st.state.GetRefund() { @@ -523,11 +524,11 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 { } // gasUsed returns the amount of gas used up by the state transition. -func (st *StateTransition) gasUsed() uint64 { +func (st *stateTransition) gasUsed() uint64 { return st.initialGas - st.gasRemaining } // blobGasUsed returns the amount of blob gas used by the message. -func (st *StateTransition) blobGasUsed() uint64 { +func (st *stateTransition) blobGasUsed() uint64 { return uint64(len(st.msg.BlobHashes) * params.BlobTxBlobGasPerBlob) } diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 0c5cae354b..5218e80c9b 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -55,9 +55,8 @@ type VMContext struct { BlockNumber *big.Int Time uint64 Random *common.Hash - // Effective tx gas price - GasPrice *big.Int - StateDB StateDB + BaseFee *big.Int + StateDB StateDB } // BlockEvent is emitted upon tracing an incoming block. diff --git a/core/vm/evm.go b/core/vm/evm.go index 34e5fa766b..07e4a272fa 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -605,7 +605,7 @@ func (evm *EVM) GetVMContext() *tracing.VMContext { BlockNumber: evm.Context.BlockNumber, Time: evm.Context.Time, Random: evm.Context.Random, - GasPrice: evm.TxContext.GasPrice, + BaseFee: evm.Context.BaseFee, StateDB: evm.StateDB, } } diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index 5729f84278..9b24bfbf96 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -217,21 +217,19 @@ func execute(ctx context.Context, call *core.Message, opts *Options, gasLimit ui func run(ctx context.Context, call *core.Message, opts *Options) (*core.ExecutionResult, error) { // Assemble the call and the call context var ( - msgContext = core.NewEVMTxContext(call) evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil) - dirtyState = opts.State.Copy() ) // Lower the basefee to 0 to avoid breaking EVM // invariants (basefee < feecap). - if msgContext.GasPrice.Sign() == 0 { + if call.GasPrice.Sign() == 0 { evmContext.BaseFee = new(big.Int) } - if msgContext.BlobFeeCap != nil && msgContext.BlobFeeCap.BitLen() == 0 { + if call.BlobGasFeeCap != nil && call.BlobGasFeeCap.BitLen() == 0 { evmContext.BlobBaseFee = new(big.Int) } evm := vm.NewEVM(evmContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true}) - evm.SetTxContext(msgContext) + // Monitor the outer context and interrupt the EVM upon cancellation. To avoid // a dangling goroutine until the outer estimation finishes, create an internal // context for the lifetime of this method call. diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 43432cff31..0749d73791 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -255,8 +255,6 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, } // Assemble the transaction call message and return if the requested offset msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - txContext := core.NewEVMTxContext(msg) - evm.SetTxContext(txContext) // Not yet the searched for transaction, execute on top of the current state statedb.SetTxContext(tx.Hash(), idx) diff --git a/eth/tracers/api.go b/eth/tracers/api.go index a2c11e0fe2..3416c11a67 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -546,11 +546,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config if err := ctx.Err(); err != nil { return nil, err } - var ( - msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) - txContext = core.NewEVMTxContext(msg) - ) - evm.SetTxContext(txContext) + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) statedb.SetTxContext(tx.Hash(), i) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) @@ -708,7 +704,6 @@ txloop: // Generate the next state snapshot fast without tracing msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) statedb.SetTxContext(tx.Hash(), i) - evm.SetTxContext(core.NewEVMTxContext(msg)) if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { failed = err break txloop @@ -792,12 +787,11 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution var ( - msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) - txContext = core.NewEVMTxContext(msg) - vmConf vm.Config - dump *os.File - writer *bufio.Writer - err error + msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee()) + vmConf vm.Config + dump *os.File + writer *bufio.Writer + err error ) // If the transaction needs tracing, swap out the configs if tx.Hash() == txHash || txHash == (common.Hash{}) { @@ -820,7 +814,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } } // Execute the transaction and flush any traces to disk - evm.SetTxContext(txContext) statedb.SetTxContext(tx.Hash(), i) if vmConf.Tracer.OnTxStart != nil { vmConf.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) @@ -1016,7 +1009,6 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor } // The actual TxContext will be created as part of ApplyTransactionWithEVM. evm := vm.NewEVM(vmctx, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) - evm.SetTxContext(vm.TxContext{GasPrice: message.GasPrice, BlobFeeCap: message.BlobGasFeeCap}) // Define a meaningful timeout of a single transaction trace if config.Timeout != nil { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 2b5cfa35c8..2ae36287fa 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -177,8 +177,6 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block return tx, context, statedb, release, nil } msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - txContext := core.NewEVMTxContext(msg) - evm.SetTxContext(txContext) if _, err := core.ApplyMessage(evm, 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/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 869558c324..999ab211c0 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -133,7 +133,6 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to prepare transaction for tracing: %v", err) } evm := vm.NewEVM(context, logState, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) - evm.SetTxContext(core.NewEVMTxContext(msg)) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { @@ -206,11 +205,6 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.Fatalf("failed to parse testcase input: %v", err) } signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time)) - origin, _ := signer.Sender(tx) - txContext := vm.TxContext{ - Origin: origin, - GasPrice: tx.GasPrice(), - } context := test.Context.toBlockContext(test.Genesis) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { @@ -222,19 +216,25 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) { b.ReportAllocs() b.ResetTimer() - tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config) - if err != nil { - b.Fatalf("failed to create call tracer: %v", err) - } - evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) - evm.SetTxContext(txContext) + evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{}) for i := 0; i < b.N; i++ { snap := state.StateDB.Snapshot() - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - if _, err = st.TransitionDb(); err != nil { + tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config) + if err != nil { + b.Fatalf("failed to create call tracer: %v", err) + } + evm.Config.Tracer = tracer.Hooks + if tracer.OnTxStart != nil { + tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) + } + _, err = core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) + if err != nil { b.Fatalf("failed to execute transaction: %v", err) } + if tracer.OnTxEnd != nil { + tracer.OnTxEnd(&types.Receipt{GasUsed: tx.Gas()}, nil) + } if _, err = tracer.GetResult(); err != nil { b.Fatal(err) } @@ -372,12 +372,7 @@ func TestInternals(t *testing.T) { if err != nil { t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err) } - txContext := vm.TxContext{ - Origin: origin, - GasPrice: tx.GasPrice(), - } evm := vm.NewEVM(context, logState, config, vm.Config{Tracer: tc.tracer.Hooks}) - evm.SetTxContext(txContext) msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0)) if err != nil { t.Fatalf("test %v: failed to create message: %v", tc.name, err) diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go index 1dbdc7caac..553eaf1b57 100644 --- a/eth/tracers/internal/tracetest/flat_calltrace_test.go +++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go @@ -99,7 +99,6 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string return fmt.Errorf("failed to prepare transaction for tracing: %v", err) } evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) - evm.SetTxContext(core.NewEVMTxContext(msg)) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go index b8dec51db1..ad3d75d8de 100644 --- a/eth/tracers/internal/tracetest/prestate_test.go +++ b/eth/tracers/internal/tracetest/prestate_test.go @@ -107,7 +107,6 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) { t.Fatalf("failed to prepare transaction for tracing: %v", err) } evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks}) - evm.SetTxContext(core.NewEVMTxContext(msg)) tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 35abd00017..227ea57226 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -260,7 +260,7 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from t.activePrecompiles = vm.ActivePrecompiles(rules) t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64()) t.ctx["gas"] = t.vm.ToValue(tx.Gas()) - gasPriceBig, err := t.toBig(t.vm, env.GasPrice.String()) + gasPriceBig, err := t.toBig(t.vm, tx.EffectiveGasTipValue(env.BaseFee).String()) if err != nil { t.err = err return diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index 54f628b5f3..faad1e7194 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -59,7 +59,7 @@ type vmContext struct { } func testCtx() *vmContext { - return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} + return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1), BaseFee: big.NewInt(0)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}} } func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) { @@ -76,7 +76,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo contract.Code = contractCode } - tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller()) + tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit, GasPrice: vmctx.txCtx.GasPrice}), contract.Caller()) tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig()) ret, err := evm.Interpreter().Run(contract, []byte{}, false) tracer.OnExit(0, ret, startGas-contract.Gas, err, true) diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 72cc1bde25..9d8f70386f 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -47,10 +47,6 @@ func BenchmarkTransactionTrace(b *testing.B) { if err != nil { b.Fatal(err) } - txContext := vm.TxContext{ - Origin: from, - GasPrice: tx.GasPrice(), - } context := vm.BlockContext{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -90,7 +86,6 @@ func BenchmarkTransactionTrace(b *testing.B) { //EnableReturnData: false, }) evm := vm.NewEVM(context, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()}) - evm.SetTxContext(txContext) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { b.Fatalf("failed to prepare transaction for tracing: %v", err) @@ -101,8 +96,7 @@ func BenchmarkTransactionTrace(b *testing.B) { for i := 0; i < b.N; i++ { snap := state.StateDB.Snapshot() tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) - st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - res, err := st.TransitionDb() + res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())) if err != nil { b.Fatal(err) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index ded4db50aa..067d07ba7a 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -867,7 +867,6 @@ func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *s if precompiles != nil { evm.SetPrecompiles(precompiles) } - evm.SetTxContext(core.NewEVMTxContext(msg)) res, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp) // If an internal state error occurred, let that have precedence. Otherwise, // a "trie root missing" type of error will masquerade as e.g. "insufficient gas" @@ -1331,17 +1330,17 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH // Apply the transaction with the access list tracer tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles) config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true} - vmenv := b.GetEVM(ctx, statedb, header, &config, nil) + evm := b.GetEVM(ctx, statedb, header, &config, nil) + // Lower the basefee to 0 to avoid breaking EVM // invariants (basefee < feecap). if msg.GasPrice.Sign() == 0 { - vmenv.Context.BaseFee = new(big.Int) + evm.Context.BaseFee = new(big.Int) } if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 { - vmenv.Context.BlobBaseFee = new(big.Int) + evm.Context.BlobBaseFee = new(big.Int) } - vmenv.SetTxContext(core.NewEVMTxContext(msg)) - res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) + res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)) if err != nil { return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err) } diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 2161e1d5f4..f6647c7ba4 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -207,7 +207,6 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, tracer.reset(tx.Hash(), uint(i)) // EoA check is always skipped, even in validation mode. msg := call.ToMessage(header.BaseFee, !sim.validate, true) - evm.SetTxContext(core.NewEVMTxContext(msg)) result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp) if err != nil { txErr := txValidationError(err) diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 446ffb40d5..6884ae7ed5 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -277,7 +277,6 @@ 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.GetHash = vmTestBlockHash context.BaseFee = baseFee @@ -294,7 +293,6 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh context.BlobBaseFee = eip4844.CalcBlobFee(*t.json.Env.ExcessBlobGas) } evm := vm.NewEVM(context, st.StateDB, config, vmconfig) - evm.SetTxContext(txContext) if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil { tracer.OnTxStart(evm.GetVMContext(), nil, msg.From)