From 69ba0a07fa6451f22c61be3c3d8b73f3d7ecd10d Mon Sep 17 00:00:00 2001 From: Guillaume Ballet <3272758+gballet@users.noreply.github.com> Date: Thu, 23 Apr 2026 22:03:05 +0200 Subject: [PATCH] call evm.Free everywhere there is a NewEVM call --- eth/gasestimator/gasestimator.go | 1 + eth/state_accessor.go | 1 + eth/tracers/api.go | 9 ++++++++- internal/ethapi/api.go | 2 ++ internal/ethapi/simulate.go | 1 + miner/worker.go | 3 +++ 6 files changed, 16 insertions(+), 1 deletion(-) diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go index ad6491fd93..2c13353f35 100644 --- a/eth/gasestimator/gasestimator.go +++ b/eth/gasestimator/gasestimator.go @@ -244,6 +244,7 @@ func run(ctx context.Context, call *core.Message, opts *Options) (*core.Executio evmContext.BlobBaseFee = new(big.Int) } evm := vm.NewEVM(evmContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true}) + defer evm.Free() // Monitor the outer context and interrupt the EVM upon cancellation. To avoid // a dangling goroutine until the outer estimation finishes, create an internal diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 7467e1e590..f23dd5bfaf 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -247,6 +247,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, // Insert parent beacon block root in the state as per EIP-4788. context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) evm := vm.NewEVM(context, statedb, eth.blockchain.Config(), vm.Config{}) + defer evm.Free() if beaconRoot := block.BeaconRoot(); beaconRoot != nil { core.ProcessBeaconBlockRoot(*beaconRoot, evm) } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index b5ddc78a10..d669f64008 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -379,6 +379,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) { core.ProcessParentBlockHash(next.ParentHash(), evm) } + evm.Free() // 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 @@ -524,6 +525,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) ) evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) + defer evm.Free() if beaconRoot := block.BeaconRoot(); beaconRoot != nil { core.ProcessBeaconBlockRoot(*beaconRoot, evm) } @@ -584,6 +586,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) evm := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{}) + defer evm.Free() if beaconRoot := block.BeaconRoot(); beaconRoot != nil { core.ProcessBeaconBlockRoot(*beaconRoot, evm) } @@ -673,6 +676,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat var failed error blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) evm := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{}) + defer evm.Free() txloop: for i, tx := range txs { @@ -758,6 +762,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) + defer evm.Free() if beaconRoot := block.BeaconRoot(); beaconRoot != nil { core.ProcessBeaconBlockRoot(*beaconRoot, evm) } @@ -805,6 +810,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) } _, err = core.ApplyMessage(evm, msg, nil) + evm.Free() if writer != nil { writer.Flush() } @@ -817,7 +823,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block } // Finalize the state so any modifications are written to the trie // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect - statedb.Finalise(evm.ChainConfig().IsEIP158(block.Number())) + statedb.Finalise(chainConfig.IsEIP158(block.Number())) // If we've traced the transaction we were looking for, abort if tx.Hash() == txHash { @@ -999,6 +1005,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor } tracingStateDB := state.NewHookedState(statedb, tracer.Hooks) evm := vm.NewEVM(vmctx, tracingStateDB, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true}) + defer evm.Free() if precompiles != nil { evm.SetPrecompiles(precompiles) } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 149e12c5b8..cfcc732164 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -775,6 +775,7 @@ func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *s blockContext.BlobBaseFee = new(big.Int) } evm := b.GetEVM(ctx, state, header, vmConfig, blockContext) + defer evm.Free() if precompiles != nil { evm.SetPrecompiles(precompiles) } @@ -1390,6 +1391,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH evm.Context.BlobBaseFee = new(big.Int) } res, err := core.ApplyMessage(evm, msg, nil) + evm.Free() 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 d18561760e..e0898a63d0 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -312,6 +312,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, tracingStateDB = state.NewHookedState(sim.state, hooks) } evm := vm.NewEVM(blockContext, tracingStateDB, sim.chainConfig, *vmConfig) + defer evm.Free() // It is possible to override precompiles with EVM bytecode, or // move them to another address. if precompiles != nil { diff --git a/miner/worker.go b/miner/worker.go index ae5d6c306f..9b65fc5fd7 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -83,6 +83,9 @@ func (env *environment) txFitsSize(tx *types.Transaction) bool { // discard terminates the background threads before discarding it. func (env *environment) discard() { env.state.StopPrefetcher() + if env.evm != nil { + env.evm.Free() + } } const (