diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index da1fb3701f90..2f7e4cc4c089 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -255,7 +255,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, snapshot = statedb.Snapshot() prevGas = gaspool.Gas() ) - if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil { + if evm.Config.Tracer.OnTxStart != nil { evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) } // (ret []byte, usedGas uint64, failed bool, err error) @@ -265,7 +265,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) gaspool.SetGas(prevGas) - if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxEnd != nil { + if evm.Config.Tracer.OnTxEnd != nil { evm.Config.Tracer.OnTxEnd(nil, err) } continue @@ -311,7 +311,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, //receipt.BlockNumber receipt.TransactionIndex = uint(txIndex) receipts = append(receipts, receipt) - if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxEnd != nil { + if evm.Config.Tracer.OnTxEnd != nil { evm.Config.Tracer.OnTxEnd(receipt, nil) } } diff --git a/cmd/evm/internal/t8ntool/file_tracer.go b/cmd/evm/internal/t8ntool/file_tracer.go index 38fc35bd322e..a24a761ed098 100644 --- a/cmd/evm/internal/t8ntool/file_tracer.go +++ b/cmd/evm/internal/t8ntool/file_tracer.go @@ -36,7 +36,7 @@ import ( // and on tx end it closes the file. type fileWritingTracer struct { txIndex int // transaction counter - inner *tracing.Hooks // inner hooks + inner tracing.Hooks // inner hooks destination io.WriteCloser // the currently open file (if any) baseDir string // baseDir to write output-files to suffix string // suffix is the suffix to use when creating files @@ -58,7 +58,7 @@ func (l *fileWritingTracer) Write(p []byte) (n int, err error) { // newFileWriter creates a set of hooks which wraps inner hooks (typically a logger), // and writes the output to a file, one file per transaction. -func newFileWriter(baseDir string, innerFn func(out io.Writer) *tracing.Hooks) *tracing.Hooks { +func newFileWriter(baseDir string, innerFn func(out io.Writer) tracing.Hooks) tracing.Hooks { t := &fileWritingTracer{ baseDir: baseDir, suffix: "jsonl", @@ -69,7 +69,7 @@ func newFileWriter(baseDir string, innerFn func(out io.Writer) *tracing.Hooks) * // newResultWriter creates a set of hooks wraps and invokes an underlying tracer, // and writes the result (getResult-output) to file, one per transaction. -func newResultWriter(baseDir string, tracer *tracers.Tracer) *tracing.Hooks { +func newResultWriter(baseDir string, tracer *tracers.Tracer) tracing.Hooks { t := &fileWritingTracer{ baseDir: baseDir, getResult: tracer.GetResult, @@ -91,7 +91,7 @@ func (l *fileWritingTracer) OnTxStart(env *tracing.VMContext, tx *types.Transact log.Info("Created tracing-file", "path", fname) l.destination = traceFile } - if l.inner != nil && l.inner.OnTxStart != nil { + if l.inner.OnTxStart != nil { l.inner.OnTxStart(env, tx, from) } } @@ -99,7 +99,7 @@ func (l *fileWritingTracer) OnTxStart(env *tracing.VMContext, tx *types.Transact // OnTxEnd writes result (if getResult exist), closes any currently open output-file, // and invokes the inner OnTxEnd handler. func (l *fileWritingTracer) OnTxEnd(receipt *types.Receipt, err error) { - if l.inner != nil && l.inner.OnTxEnd != nil { + if l.inner.OnTxEnd != nil { l.inner.OnTxEnd(receipt, err) } if l.getResult != nil && l.destination != nil { @@ -114,37 +114,37 @@ func (l *fileWritingTracer) OnTxEnd(receipt *types.Receipt, err error) { l.txIndex++ } -func (l *fileWritingTracer) hooks() *tracing.Hooks { - return &tracing.Hooks{ +func (l *fileWritingTracer) hooks() tracing.Hooks { + return tracing.Hooks{ OnTxStart: l.OnTxStart, OnTxEnd: l.OnTxEnd, OnEnter: func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { - if l.inner != nil && l.inner.OnEnter != nil { + if l.inner.OnEnter != nil { l.inner.OnEnter(depth, typ, from, to, input, gas, value) } }, OnExit: func(depth int, output []byte, gasUsed uint64, err error, reverted bool) { - if l.inner != nil && l.inner.OnExit != nil { + if l.inner.OnExit != nil { l.inner.OnExit(depth, output, gasUsed, err, reverted) } }, OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { - if l.inner != nil && l.inner.OnOpcode != nil { + if l.inner.OnOpcode != nil { l.inner.OnOpcode(pc, op, gas, cost, scope, rData, depth, err) } }, OnFault: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { - if l.inner != nil && l.inner.OnFault != nil { + if l.inner.OnFault != nil { l.inner.OnFault(pc, op, gas, cost, scope, depth, err) } }, OnSystemCallStart: func() { - if l.inner != nil && l.inner.OnSystemCallStart != nil { + if l.inner.OnSystemCallStart != nil { l.inner.OnSystemCallStart() } }, OnSystemCallEnd: func() { - if l.inner != nil && l.inner.OnSystemCallEnd != nil { + if l.inner.OnSystemCallEnd != nil { l.inner.OnSystemCallEnd() } }, diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index e946ccddd567..742ad7175c37 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -167,11 +167,11 @@ func Transition(ctx *cli.Context) error { EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name), } if ctx.Bool(TraceEnableCallFramesFlag.Name) { - vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) *tracing.Hooks { + vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) tracing.Hooks { return logger.NewJSONLoggerWithCallFrames(logConfig, out) }) } else { - vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) *tracing.Hooks { + vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) tracing.Hooks { return logger.NewJSONLogger(logConfig, out) }) } diff --git a/cmd/evm/main.go b/cmd/evm/main.go index bf5be9a35924..8ad36952ca19 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -229,7 +229,7 @@ func main() { } // tracerFromFlags parses the cli flags and returns the specified tracer. -func tracerFromFlags(ctx *cli.Context) *tracing.Hooks { +func tracerFromFlags(ctx *cli.Context) tracing.Hooks { config := &logger.Config{ EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name), DisableStack: ctx.Bool(TraceDisableStackFlag.Name), @@ -248,7 +248,7 @@ func tracerFromFlags(ctx *cli.Context) *tracing.Hooks { default: fmt.Fprintf(os.Stderr, "unknown trace format: %q\n", format) os.Exit(1) - return nil + return tracing.Hooks{} } // Deprecated ways of configuring tracing. case ctx.Bool(MachineFlag.Name): @@ -256,7 +256,7 @@ func tracerFromFlags(ctx *cli.Context) *tracing.Hooks { case ctx.Bool(DebugFlag.Name): return logger.NewStreamingStructLogger(config, os.Stderr).Hooks() default: - return nil + return tracing.Hooks{} } } diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index b2cf28353b80..d117d5c57e70 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -198,7 +198,7 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, exe func runCmd(ctx *cli.Context) error { var ( - tracer *tracing.Hooks + tracer tracing.Hooks prestate *state.StateDB chainConfig *params.ChainConfig sender = common.BytesToAddress([]byte("sender")) @@ -363,11 +363,11 @@ allocations: %d allocated bytes: %d `, stats.GasUsed, stats.Time, stats.Allocs, stats.BytesAllocated) } - if tracer == nil { + if len(output) > 0 { fmt.Printf("%#x\n", output) - if err != nil { - fmt.Printf(" error: %v\n", err) - } + } + if err != nil { + fmt.Printf(" error: %v\n", err) } return nil diff --git a/core/blockchain.go b/core/blockchain.go index d52990ec5adc..dea421c56346 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -329,7 +329,7 @@ type BlockChain struct { validator Validator // Block and state validator interface prefetcher Prefetcher processor Processor // Block transaction processor interface - logger *tracing.Hooks + logger tracing.Hooks lastForkReadyAlert time.Time // Last time there was a fork readiness print out } @@ -491,10 +491,10 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine, // it in advance. bc.engine.VerifyHeader(bc, bc.CurrentHeader()) - if bc.logger != nil && bc.logger.OnBlockchainInit != nil { + if bc.logger.OnBlockchainInit != nil { bc.logger.OnBlockchainInit(chainConfig) } - if bc.logger != nil && bc.logger.OnGenesisBlock != nil { + if bc.logger.OnGenesisBlock != nil { if block := bc.CurrentBlock(); block.Number.Uint64() == 0 { alloc, err := getGenesisState(bc.db, block.Hash()) if err != nil { @@ -1311,7 +1311,7 @@ func (bc *BlockChain) Stop() { } } // Allow tracers to clean-up and release resources. - if bc.logger != nil && bc.logger.OnClose != nil { + if bc.logger.OnClose != nil { bc.logger.OnClose() } // Close the trie database, release all the held resources as the last step. @@ -1862,7 +1862,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness return nil, it.index, err } stats.processed++ - if bc.logger != nil && bc.logger.OnSkippedBlock != nil { + if bc.logger.OnSkippedBlock != nil { bc.logger.OnSkippedBlock(tracing.BlockEvent{ Block: block, Finalized: bc.CurrentFinalBlock(), @@ -1998,7 +1998,7 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s go func(start time.Time, throwaway *state.StateDB, block *types.Block) { // Disable tracing for prefetcher executions. vmCfg := bc.cfg.VmConfig - vmCfg.Tracer = nil + vmCfg.Tracer = tracing.Hooks{} bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt) blockPrefetchExecuteTimer.Update(time.Since(start)) @@ -2026,14 +2026,14 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s defer statedb.StopPrefetcher() } - if bc.logger != nil && bc.logger.OnBlockStart != nil { + if bc.logger.OnBlockStart != nil { bc.logger.OnBlockStart(tracing.BlockEvent{ Block: block, Finalized: bc.CurrentFinalBlock(), Safe: bc.CurrentSafeBlock(), }) } - if bc.logger != nil && bc.logger.OnBlockEnd != nil { + if bc.logger.OnBlockEnd != nil { defer func() { bc.logger.OnBlockEnd(blockEndErr) }() diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go index 3d1ef1503180..e04ce12d8102 100644 --- a/core/state/statedb_hooked.go +++ b/core/state/statedb_hooked.go @@ -33,16 +33,12 @@ import ( // on state operations. type hookedStateDB struct { inner *StateDB - hooks *tracing.Hooks + hooks tracing.Hooks } // NewHookedState wraps the given stateDb with the given hooks -func NewHookedState(stateDb *StateDB, hooks *tracing.Hooks) *hookedStateDB { - s := &hookedStateDB{stateDb, hooks} - if s.hooks == nil { - s.hooks = new(tracing.Hooks) - } - return s +func NewHookedState(stateDb *StateDB, hooks tracing.Hooks) *hookedStateDB { + return &hookedStateDB{stateDb, hooks} } func (s *hookedStateDB) CreateAccount(addr common.Address) { diff --git a/core/state/statedb_hooked_test.go b/core/state/statedb_hooked_test.go index f319b0e63ccc..c12529b8d88a 100644 --- a/core/state/statedb_hooked_test.go +++ b/core/state/statedb_hooked_test.go @@ -39,7 +39,7 @@ func TestBurn(t *testing.T) { var burned = new(uint256.Int) s, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) - hooked := NewHookedState(s, &tracing.Hooks{ + hooked := NewHookedState(s, tracing.Hooks{ OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { if reason == tracing.BalanceDecreaseSelfdestructBurn { burned.Add(burned, uint256.MustFromBig(prev)) @@ -94,7 +94,7 @@ func TestHooks(t *testing.T) { emitF := func(format string, a ...any) { result = append(result, fmt.Sprintf(format, a...)) } - sdb := NewHookedState(inner, &tracing.Hooks{ + sdb := NewHookedState(inner, tracing.Hooks{ OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { emitF("%v.balance: %v->%v (%v)", addr, prev, new, reason) }, diff --git a/core/state_processor.go b/core/state_processor.go index ee98326467f4..94197a1d6eea 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -76,8 +76,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Apply pre-execution system calls. var tracingStateDB = vm.StateDB(statedb) - if hooks := cfg.Tracer; hooks != nil { - tracingStateDB = state.NewHookedState(statedb, hooks) + if cfg.Tracer.HasStateHooks() { + tracingStateDB = state.NewHookedState(statedb, cfg.Tracer) } context = NewEVMBlockContext(header, p.chain, nil) evm := vm.NewEVM(context, tracingStateDB, p.config, cfg) @@ -137,13 +137,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // and uses the input parameters for its environment similar to ApplyTransaction. However, // this method takes an already created EVM instance as input. func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) { - if hooks := evm.Config.Tracer; hooks != nil { - if hooks.OnTxStart != nil { - hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) - } - if hooks.OnTxEnd != nil { - defer func() { hooks.OnTxEnd(receipt, err) }() - } + if evm.Config.Tracer.OnTxStart != nil { + evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From) + } + if evm.Config.Tracer.OnTxEnd != nil { + defer func() { evm.Config.Tracer.OnTxEnd(receipt, err) }() } // Apply the transaction to the current state (included in the env). result, err := ApplyMessage(evm, msg, gp) @@ -215,11 +213,9 @@ func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header * // 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, evm *vm.EVM) { - if tracer := evm.Config.Tracer; tracer != nil { - onSystemCallStart(tracer, evm.GetVMContext()) - if tracer.OnSystemCallEnd != nil { - defer tracer.OnSystemCallEnd() - } + onSystemCallStart(&evm.Config.Tracer, evm.GetVMContext()) + if evm.Config.Tracer.OnSystemCallEnd != nil { + defer evm.Config.Tracer.OnSystemCallEnd() } msg := &Message{ From: params.SystemAddress, @@ -239,11 +235,9 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) { // ProcessParentBlockHash stores the parent block hash in the history storage contract // as per EIP-2935/7709. func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { - if tracer := evm.Config.Tracer; tracer != nil { - onSystemCallStart(tracer, evm.GetVMContext()) - if tracer.OnSystemCallEnd != nil { - defer tracer.OnSystemCallEnd() - } + onSystemCallStart(&evm.Config.Tracer, evm.GetVMContext()) + if evm.Config.Tracer.OnSystemCallEnd != nil { + defer evm.Config.Tracer.OnSystemCallEnd() } msg := &Message{ From: params.SystemAddress, @@ -279,11 +273,9 @@ func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) error { } func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) error { - if tracer := evm.Config.Tracer; tracer != nil { - onSystemCallStart(tracer, evm.GetVMContext()) - if tracer.OnSystemCallEnd != nil { - defer tracer.OnSystemCallEnd() - } + onSystemCallStart(&evm.Config.Tracer, evm.GetVMContext()) + if evm.Config.Tracer.OnSystemCallEnd != nil { + defer evm.Config.Tracer.OnSystemCallEnd() } msg := &Message{ From: params.SystemAddress, diff --git a/core/state_transition.go b/core/state_transition.go index 681c30069654..17c75ed7926a 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -292,7 +292,7 @@ func (st *stateTransition) buyGas() error { return err } - if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil { + if st.evm.Config.Tracer.OnGasChange != nil { st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance) } st.gasRemaining = st.msg.GasLimit @@ -456,8 +456,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, msg.GasLimit, floorDataGas) } } - if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { - t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas) + if st.evm.Config.Tracer.OnGasChange != nil { + st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas) } st.gasRemaining -= gas @@ -530,8 +530,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { if st.gasUsed() < floorDataGas { prev := st.gasRemaining st.gasRemaining = st.initialGas - floorDataGas - if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { - t.OnGasChange(prev, st.gasRemaining, tracing.GasChangeTxDataFloor) + if st.evm.Config.Tracer.OnGasChange != nil { + st.evm.Config.Tracer.OnGasChange(prev, st.gasRemaining, tracing.GasChangeTxDataFloor) } } if peakGasUsed < floorDataGas { @@ -640,7 +640,7 @@ func (st *stateTransition) calcRefund() uint64 { if refund > st.state.GetRefund() { refund = st.state.GetRefund() } - if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && refund > 0 { + if st.evm.Config.Tracer.OnGasChange != nil && refund > 0 { st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, tracing.GasChangeTxRefunds) } return refund @@ -653,7 +653,7 @@ func (st *stateTransition) returnGas() { remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn) - if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining > 0 { + if st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining > 0 { st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, tracing.GasChangeTxLeftOverReturned) } diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 0485f7a3eb29..8a56ce153f05 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -188,7 +188,8 @@ type ( ) type Hooks struct { - // VM events + // VM events, make sure to update HasVMHooks + // if you ever add a new hook here OnTxStart TxStartHook OnTxEnd TxEndHook OnEnter EnterHook @@ -206,7 +207,8 @@ type Hooks struct { OnSystemCallStart OnSystemCallStartHook OnSystemCallStartV2 OnSystemCallStartHookV2 OnSystemCallEnd OnSystemCallEndHook - // State events + // State events, make sure to update HasStateHooks + // if you ever add a new hook here OnBalanceChange BalanceChangeHook OnNonceChange NonceChangeHook OnNonceChangeV2 NonceChangeHookV2 @@ -217,6 +219,27 @@ type Hooks struct { OnBlockHashRead BlockHashReadHook } +// HasVMHooks returns if any of the VM events are being hooked +func (h *Hooks) HasVMHooks() bool { + return h.OnTxStart != nil || + h.OnTxEnd != nil || + h.OnEnter != nil || + h.OnExit != nil || + h.OnOpcode != nil || + h.OnFault != nil || + h.OnGasChange != nil +} + +// HasStateHooks returns if any of the state events are being hooked +func (h *Hooks) HasStateHooks() bool { + return h.OnBalanceChange != nil || + h.OnNonceChange != nil || + h.OnNonceChangeV2 != nil || + h.OnCodeChange != nil || + h.OnStorageChange != nil || + h.OnLog != nil +} + // BalanceChangeReason is used to indicate the reason for a balance change, useful // for tracing and reporting. type BalanceChangeReason byte diff --git a/core/vm/contract.go b/core/vm/contract.go index 0eaa91d9596c..0add5bede1ee 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -126,24 +126,24 @@ func (c *Contract) Caller() common.Address { } // UseGas attempts the use gas and subtracts it and returns true on success -func (c *Contract) UseGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) (ok bool) { +func (c *Contract) UseGas(gas uint64, onGasChange tracing.GasChangeHook, reason tracing.GasChangeReason) (ok bool) { if c.Gas < gas { return false } - if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { - logger.OnGasChange(c.Gas, c.Gas-gas, reason) + if onGasChange != nil && reason != tracing.GasChangeIgnored { + onGasChange(c.Gas, c.Gas-gas, reason) } c.Gas -= gas return true } // RefundGas refunds gas to the contract -func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) { +func (c *Contract) RefundGas(gas uint64, onGasChange tracing.GasChangeHook, reason tracing.GasChangeReason) { if gas == 0 { return } - if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { - logger.OnGasChange(c.Gas, c.Gas+gas, reason) + if onGasChange != nil && reason != tracing.GasChangeIgnored { + onGasChange(c.Gas, c.Gas+gas, reason) } c.Gas += gas } diff --git a/core/vm/contracts.go b/core/vm/contracts.go index b65dff602ca0..11d4aadd6613 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -257,13 +257,13 @@ func ActivePrecompiles(rules params.Rules) []common.Address { // - the returned bytes, // - the _remaining_ gas, // - any error that occurred -func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) { +func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, onGasChange tracing.GasChangeHook) (ret []byte, remainingGas uint64, err error) { gasCost := p.RequiredGas(input) if suppliedGas < gasCost { return nil, 0, ErrOutOfGas } - if logger != nil && logger.OnGasChange != nil { - logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract) + if onGasChange != nil { + onGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract) } suppliedGas -= gasCost output, err := p.Run(input) diff --git a/core/vm/eips.go b/core/vm/eips.go index 7764bd20b624..23758d284eb3 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -358,7 +358,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC code := interpreter.evm.StateDB.GetCode(addr) paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64()) consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas) - scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) + scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } @@ -384,7 +384,7 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext // advanced past this boundary. contractAddr := scope.Contract.Address() consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) - scope.Contract.UseGas(wanted, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) + scope.Contract.UseGas(wanted, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } @@ -412,7 +412,7 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc { if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall { contractAddr := scope.Contract.Address() consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) - scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified) + scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } diff --git a/core/vm/evm.go b/core/vm/evm.go index b45a43454531..6ccdfdbc989f 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -125,6 +125,9 @@ type EVM struct { // jumpDests is the aggregated result of JUMPDEST analysis made through // the life cycle of EVM. jumpDests map[common.Hash]bitvec + + // tracingEnabled is used to shortcircuit some of the tracing calls + tracingEnabled bool } // NewEVM constructs an EVM instance with the supplied block context, state @@ -133,12 +136,13 @@ type EVM struct { // needed by calling evm.SetTxContext. func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { evm := &EVM{ - Context: blockCtx, - StateDB: statedb, - Config: config, - chainConfig: chainConfig, - chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), - jumpDests: make(map[common.Hash]bitvec), + Context: blockCtx, + StateDB: statedb, + Config: config, + chainConfig: chainConfig, + chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), + jumpDests: make(map[common.Hash]bitvec), + tracingEnabled: config.Tracer.HasVMHooks(), } evm.precompiles = activePrecompiledContracts(evm.chainRules) evm.interpreter = NewEVMInterpreter(evm) @@ -186,8 +190,8 @@ func isSystemCall(caller common.Address) bool { // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { - // Capture the tracer start/end events in debug mode - if evm.Config.Tracer != nil { + if evm.tracingEnabled { + // Capture the tracer start/end events in debug mode evm.captureBegin(evm.depth, CALL, caller, addr, input, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) @@ -230,7 +234,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g evm.Context.Transfer(evm.StateDB, caller, addr, value) if isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer.OnGasChange) } else { // Initialise a new contract and set the code that is to be used by the EVM. code := evm.resolveCode(addr) @@ -251,7 +255,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + if evm.Config.Tracer.OnGasChange != nil { evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } @@ -272,8 +276,8 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { - // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Tracer != nil { + if evm.tracingEnabled { + // Invoke tracer hooks that signal entering/exiting a call frame evm.captureBegin(evm.depth, CALLCODE, caller, addr, input, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) @@ -294,7 +298,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer.OnGasChange) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -306,7 +310,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + if evm.Config.Tracer.OnGasChange != nil { evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } gas = 0 @@ -321,8 +325,8 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt // DelegateCall differs from CallCode in the sense that it executes the given address' // code with the caller as context and the caller is set to the caller of the caller. func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { - // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Tracer != nil { + if evm.tracingEnabled { + // Invoke tracer hooks that signal entering/exiting a call frame // DELEGATECALL inherits value from parent call evm.captureBegin(evm.depth, DELEGATECALL, caller, addr, input, gas, value.ToBig()) defer func(startGas uint64) { @@ -337,7 +341,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, // It is allowed to call precompiles, even via delegatecall if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer.OnGasChange) } else { // Initialise a new contract and make initialise the delegate values // @@ -350,7 +354,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + if evm.Config.Tracer.OnGasChange != nil { evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } gas = 0 @@ -364,8 +368,8 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, // Opcodes that attempt to perform such modifications will result in exceptions // instead of performing the modifications. func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { - // Invoke tracer hooks that signal entering/exiting a call frame - if evm.Config.Tracer != nil { + if evm.tracingEnabled { + // Invoke tracer hooks that signal entering/exiting a call frame evm.captureBegin(evm.depth, STATICCALL, caller, addr, input, gas, nil) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) @@ -389,7 +393,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b evm.StateDB.AddBalance(addr, new(uint256.Int), tracing.BalanceChangeTouchAccount) if p, isPrecompile := evm.precompile(addr); isPrecompile { - ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) + ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer.OnGasChange) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -405,7 +409,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b if err != nil { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + if evm.Config.Tracer.OnGasChange != nil { evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } @@ -417,7 +421,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b // create creates a new contract using code as deployment code. func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) { - if evm.Config.Tracer != nil { + if evm.tracingEnabled { evm.captureBegin(evm.depth, typ, caller, address, code, gas, value.ToBig()) defer func(startGas uint64) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) @@ -443,7 +447,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui if statelessGas > gas { return nil, common.Address{}, 0, ErrOutOfGas } - if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + if evm.Config.Tracer.OnGasChange != nil { evm.Config.Tracer.OnGasChange(gas, gas-statelessGas, tracing.GasChangeWitnessContractCollisionCheck) } gas = gas - statelessGas @@ -464,7 +468,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code (storageRoot != (common.Hash{}) && storageRoot != types.EmptyRootHash) { // non-empty storage - if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + if evm.Config.Tracer.OnGasChange != nil { evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) } return nil, common.Address{}, 0, ErrContractAddressCollision @@ -491,7 +495,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui if consumed < wanted { return nil, common.Address{}, 0, ErrOutOfGas } - if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + if evm.Config.Tracer.OnGasChange != nil { evm.Config.Tracer.OnGasChange(gas, gas-consumed, tracing.GasChangeWitnessContractInit) } gas = gas - consumed @@ -511,7 +515,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) if err != ErrExecutionReverted { - contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution) + contract.UseGas(contract.Gas, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallFailedExecution) } } return ret, address, contract.Gas, err @@ -537,12 +541,12 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b if !evm.chainRules.IsEIP4762 { createDataGas := uint64(len(ret)) * params.CreateDataGas - if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { + if !contract.UseGas(createDataGas, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallCodeStorage) { return ret, ErrCodeStoreOutOfGas } } else { consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true, contract.Gas) - contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) + contract.UseGas(consumed, evm.Config.Tracer.OnGasChange, tracing.GasChangeWitnessCodeChunk) if len(ret) > 0 && (consumed < wanted) { return ret, ErrCodeStoreOutOfGas } @@ -601,29 +605,21 @@ func (evm *EVM) resolveCodeHash(addr common.Address) common.Hash { func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } func (evm *EVM) captureBegin(depth int, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) { - tracer := evm.Config.Tracer - if tracer.OnEnter != nil { - tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value) + if evm.Config.Tracer.OnEnter != nil { + evm.Config.Tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value) } - if tracer.OnGasChange != nil { - tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance) + if evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance) } } func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret []byte, err error) { - tracer := evm.Config.Tracer - if leftOverGas != 0 && tracer.OnGasChange != nil { - tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned) - } - var reverted bool - if err != nil { - reverted = true - } - if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) { - reverted = false + if evm.Config.Tracer.OnGasChange != nil && leftOverGas != 0 { + evm.Config.Tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned) } - if tracer.OnExit != nil { - tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) + if evm.Config.Tracer.OnExit != nil { + reverted := err != nil && (evm.chainRules.IsHomestead || !errors.Is(err, ErrCodeStoreOutOfGas)) + evm.Config.Tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) } } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 63bb6d2d51cb..fb52d8b6ffae 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -443,8 +443,8 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( if witness := interpreter.evm.StateDB.Witness(); witness != nil { witness.AddBlockHash(num64) } - if tracer := interpreter.evm.Config.Tracer; tracer != nil && tracer.OnBlockHashRead != nil { - tracer.OnBlockHashRead(num64, res) + if interpreter.evm.Config.Tracer.OnBlockHashRead != nil { + interpreter.evm.Config.Tracer.OnBlockHashRead(num64, res) } num.SetBytes(res[:]) } else { @@ -670,7 +670,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b // reuse size int for stackvalue stackvalue := size - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallContractCreation) res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract.Address(), input, gas, &value) // Push item on the stack based on the returned error. If the ruleset is @@ -686,7 +686,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b } scope.Stack.push(&stackvalue) - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { interpreter.returnData = res // set REVERT data to return data buffer @@ -710,7 +710,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] // Apply EIP150 gas -= gas / 64 - scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2) + scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract.Address(), input, gas, @@ -722,7 +722,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([] stackvalue.SetBytes(addr.Bytes()) } scope.Stack.push(&stackvalue) - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { interpreter.returnData = res // set REVERT data to return data buffer @@ -762,7 +762,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -795,7 +795,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([ scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -824,7 +824,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -853,7 +853,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded) interpreter.returnData = ret return ret, nil @@ -890,13 +890,11 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) - if tracer := interpreter.evm.Config.Tracer; tracer != nil { - if tracer.OnEnter != nil { - tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) - } - if tracer.OnExit != nil { - tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) - } + if interpreter.evm.Config.Tracer.OnEnter != nil { + interpreter.evm.Config.Tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) + } + if interpreter.evm.Config.Tracer.OnExit != nil { + interpreter.evm.Config.Tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) } return nil, errStopToken } @@ -910,13 +908,11 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.SelfDestruct6780(scope.Contract.Address()) - if tracer := interpreter.evm.Config.Tracer; tracer != nil { - if tracer.OnEnter != nil { - tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) - } - if tracer.OnExit != nil { - tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) - } + if interpreter.evm.Config.Tracer.OnEnter != nil { + interpreter.evm.Config.Tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) + } + if interpreter.evm.Config.Tracer.OnExit != nil { + interpreter.evm.Config.Tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false) } return nil, errStopToken } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 34d19008da7e..ba9f6cef9638 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -29,7 +29,7 @@ import ( // Config are the configuration options for the Interpreter type Config struct { - Tracer *tracing.Hooks + Tracer tracing.Hooks NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages ExtraEips []int // Additional EIPS that are to be enabled @@ -202,7 +202,6 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( gasCopy uint64 // for EVMLogger to log gas remaining before execution logged bool // deferred EVMLogger should ignore already logged steps res []byte // result of the opcode execution function - debug = in.evm.Config.Tracer != nil ) // Don't move this deferred function, it's placed before the OnOpcode-deferred method, // so that it gets executed _after_: the OnOpcode needs the stacks before @@ -213,36 +212,32 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( }() contract.Input = input - if debug { - defer func() { // this deferred method handles exit-with-error - if err == nil { - return - } - if !logged && in.evm.Config.Tracer.OnOpcode != nil { - in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) - } - if logged && in.evm.Config.Tracer.OnFault != nil { - in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) - } - }() - } + defer func() { // this deferred method handles exit-with-error + if err == nil { + return + } + if !logged && in.evm.Config.Tracer.OnOpcode != nil { + in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + } + if logged && in.evm.Config.Tracer.OnFault != nil { + in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err)) + } + }() // The Interpreter main run loop (contextual). This loop runs until either an // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during // the execution of one of the operations or until the done flag is set by the // parent context. _ = jumpTable[0] // nil-check the jumpTable out of the loop for { - if debug { - // Capture pre-execution values for tracing. - logged, pcCopy, gasCopy = false, pc, contract.Gas - } + // Capture pre-execution values for tracing. + logged, pcCopy, gasCopy = false, pc, contract.Gas if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment && !contract.IsSystemCall { // if the PC ends up in a new "chunk" of verkleized code, charge the // associated costs. contractAddr := contract.Address() consumed, wanted := in.evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas) - contract.UseGas(consumed, in.evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) + contract.UseGas(consumed, in.evm.Config.Tracer.OnGasChange, tracing.GasChangeWitnessCodeChunk) if consumed < wanted { return nil, ErrOutOfGas } @@ -301,14 +296,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( } // Do tracing before potential memory expansion - if debug { - if in.evm.Config.Tracer.OnGasChange != nil { - in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) - } - if in.evm.Config.Tracer.OnOpcode != nil { - in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) - logged = true - } + if in.evm.Config.Tracer.OnGasChange != nil { + in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) + } + if in.evm.Config.Tracer.OnOpcode != nil { + in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) + logged = true } if memorySize > 0 { mem.Resize(memorySize) diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 085b018e4c42..49e82f50b3ae 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -164,7 +164,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) g evm.StateDB.AddAddressToAccessList(addr) // Charge the remaining difference here already, to correctly calculate available // gas for call - if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { + if !contract.UseGas(coldCost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) { return 0, ErrOutOfGas } } @@ -265,7 +265,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc { coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929 // Charge the remaining difference here already, to correctly calculate available // gas for call - if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { + if !contract.UseGas(coldCost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) { return 0, ErrOutOfGas } total += coldCost @@ -280,7 +280,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc { evm.StateDB.AddAddressToAccessList(target) cost = params.ColdAccountAccessCostEIP2929 } - if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { + if !contract.UseGas(cost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) { return 0, ErrOutOfGas } total += cost diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 9d984291f263..fda4dc516741 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -130,7 +130,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { vmenv = NewEnv(cfg) rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) - if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { + if cfg.EVMConfig.Tracer.OnTxStart != nil { cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: @@ -148,7 +148,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { cfg.GasLimit, uint256.MustFromBig(cfg.Value), ) - if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxEnd != nil { + if cfg.EVMConfig.Tracer.OnTxEnd != nil { cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err) } return ret, cfg.State, err @@ -168,7 +168,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { vmenv = NewEnv(cfg) rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) - if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { + if cfg.EVMConfig.Tracer.OnTxStart != nil { cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: @@ -182,7 +182,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { cfg.GasLimit, uint256.MustFromBig(cfg.Value), ) - if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxEnd != nil { + if cfg.EVMConfig.Tracer.OnTxEnd != nil { cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err) } return code, address, leftOverGas, err @@ -201,7 +201,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er statedb = cfg.State rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) ) - if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil { + if cfg.EVMConfig.Tracer.OnTxStart != nil { cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin) } // Execute the preparatory steps for state transition which includes: @@ -217,7 +217,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er cfg.GasLimit, uint256.MustFromBig(cfg.Value), ) - if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxEnd != nil { + if cfg.EVMConfig.Tracer.OnTxEnd != nil { cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err) } return ret, leftOverGas, err diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index d75a5b0459e8..920668a79b3f 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -666,7 +666,7 @@ func TestColdAccountAccessCost(t *testing.T) { var have = uint64(0) Execute(tc.code, nil, &Config{ EVMConfig: vm.Config{ - Tracer: &tracing.Hooks{ + Tracer: tracing.Hooks{ OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { // Uncomment to investigate failures: //t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost) @@ -920,7 +920,7 @@ func TestDelegatedAccountAccessCost(t *testing.T) { ChainConfig: params.MergedTestChainConfig, State: statedb, EVMConfig: vm.Config{ - Tracer: &tracing.Hooks{ + Tracer: tracing.Hooks{ OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { // Uncomment to investigate failures: t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost) diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 7ed2a5936e1f..4a41ef3af7ea 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -208,7 +208,7 @@ func newStateTracer(ctx *Context, cfg json.RawMessage, chainCfg *params.ChainCon GetResult: func() (json.RawMessage, error) { return json.Marshal(t) }, - Hooks: &tracing.Hooks{ + Hooks: tracing.Hooks{ OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { t.Balance[addr] = (*hexutil.Big)(new) }, diff --git a/eth/tracers/dir.go b/eth/tracers/dir.go index 05c76bceb7e2..1529c6af0313 100644 --- a/eth/tracers/dir.go +++ b/eth/tracers/dir.go @@ -39,7 +39,7 @@ type Context struct { // This involves a method to retrieve results and one to // stop tracing. type Tracer struct { - *tracing.Hooks + tracing.Hooks GetResult func() (json.RawMessage, error) // Stop terminates execution of the tracer at the first opportune moment. Stop func(err error) diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go index 70da34f4272f..8bf9d048d700 100644 --- a/eth/tracers/internal/tracetest/calltrace_test.go +++ b/eth/tracers/internal/tracetest/calltrace_test.go @@ -121,10 +121,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } - logState := vm.StateDB(st.StateDB) - if tracer.Hooks != nil { - logState = state.NewHookedState(st.StateDB, tracer.Hooks) - } + logState := state.NewHookedState(st.StateDB, tracer.Hooks) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) @@ -355,11 +352,7 @@ func TestInternals(t *testing.T) { }, false, rawdb.HashScheme) defer st.Close() - logState := vm.StateDB(st.StateDB) - if hooks := tc.tracer.Hooks; hooks != nil { - logState = state.NewHookedState(st.StateDB, hooks) - } - + logState := state.NewHookedState(st.StateDB, tc.tracer.Hooks) tx, err := types.SignNewTx(key, signer, &types.LegacyTx{ To: &to, Value: big.NewInt(0), diff --git a/eth/tracers/internal/tracetest/erc7562_tracer_test.go b/eth/tracers/internal/tracetest/erc7562_tracer_test.go index f6e81f5886fd..6a678094a7ed 100644 --- a/eth/tracers/internal/tracetest/erc7562_tracer_test.go +++ b/eth/tracers/internal/tracetest/erc7562_tracer_test.go @@ -114,10 +114,7 @@ func TestErc7562Tracer(t *testing.T) { if err != nil { t.Fatalf("failed to create erc7562 tracer: %v", err) } - logState := vm.StateDB(st.StateDB) - if tracer.Hooks != nil { - logState = state.NewHookedState(st.StateDB, tracer.Hooks) - } + logState := state.NewHookedState(st.StateDB, tracer.Hooks) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) if err != nil { t.Fatalf("failed to prepare transaction for tracing: %v", err) diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go index 7ec737f4e496..d59160ef05f7 100644 --- a/eth/tracers/js/goja.go +++ b/eth/tracers/js/goja.go @@ -235,7 +235,7 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage, chainCo t.logValue = t.log.setupObject() return &tracers.Tracer{ - Hooks: &tracing.Hooks{ + Hooks: tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, OnEnter: t.OnEnter, diff --git a/eth/tracers/live.go b/eth/tracers/live.go index 8b222d2e6cdf..320a938810e2 100644 --- a/eth/tracers/live.go +++ b/eth/tracers/live.go @@ -23,7 +23,7 @@ import ( "github.com/ethereum/go-ethereum/core/tracing" ) -type ctorFunc func(config json.RawMessage) (*tracing.Hooks, error) +type ctorFunc func(config json.RawMessage) (tracing.Hooks, error) // LiveDirectory is the collection of tracers which can be used // during normal block import operations. @@ -39,12 +39,12 @@ func (d *liveDirectory) Register(name string, f ctorFunc) { } // New instantiates a tracer by name. -func (d *liveDirectory) New(name string, config json.RawMessage) (*tracing.Hooks, error) { +func (d *liveDirectory) New(name string, config json.RawMessage) (tracing.Hooks, error) { if len(config) == 0 { config = json.RawMessage("{}") } if f, ok := d.elems[name]; ok { return f(config) } - return nil, errors.New("not found") + return tracing.Hooks{}, errors.New("not found") } diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index f3def8560646..386a592c144a 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -37,9 +37,9 @@ func init() { // as soon as we have a real live tracer. type noop struct{} -func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) { +func newNoopTracer(_ json.RawMessage) (tracing.Hooks, error) { t := &noop{} - return &tracing.Hooks{ + return tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, OnEnter: t.OnEnter, diff --git a/eth/tracers/live/supply.go b/eth/tracers/live/supply.go index bae7445cb434..3fcde3f8ef05 100644 --- a/eth/tracers/live/supply.go +++ b/eth/tracers/live/supply.go @@ -92,13 +92,13 @@ type supplyTracerConfig struct { MaxSize int `json:"maxSize"` // MaxSize is the maximum size in megabytes of the tracer log file before it gets rotated. It defaults to 100 megabytes. } -func newSupplyTracer(cfg json.RawMessage) (*tracing.Hooks, error) { +func newSupplyTracer(cfg json.RawMessage) (tracing.Hooks, error) { var config supplyTracerConfig if err := json.Unmarshal(cfg, &config); err != nil { - return nil, fmt.Errorf("failed to parse config: %v", err) + return tracing.Hooks{}, fmt.Errorf("failed to parse config: %v", err) } if config.Path == "" { - return nil, errors.New("supply tracer output path is required") + return tracing.Hooks{}, errors.New("supply tracer output path is required") } // Store traces in a rotating file @@ -113,7 +113,7 @@ func newSupplyTracer(cfg json.RawMessage) (*tracing.Hooks, error) { delta: newSupplyInfo(), logger: logger, } - return &tracing.Hooks{ + return tracing.Hooks{ OnBlockchainInit: t.onBlockchainInit, OnBlockStart: t.onBlockStart, OnBlockEnd: t.onBlockEnd, diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go index 0d51f405225a..4e2c58c09c51 100644 --- a/eth/tracers/logger/access_list_tracer.go +++ b/eth/tracers/logger/access_list_tracer.go @@ -119,8 +119,8 @@ func NewAccessListTracer(acl types.AccessList, addressesToExclude map[common.Add } } -func (a *AccessListTracer) Hooks() *tracing.Hooks { - return &tracing.Hooks{ +func (a *AccessListTracer) Hooks() tracing.Hooks { + return tracing.Hooks{ OnOpcode: a.OnOpcode, } } diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index 824a5e0c3e23..39be2dc2789b 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -244,8 +244,8 @@ func NewStructLogger(cfg *Config) *StructLogger { return logger } -func (l *StructLogger) Hooks() *tracing.Hooks { - return &tracing.Hooks{ +func (l *StructLogger) Hooks() tracing.Hooks { + return tracing.Hooks{ OnTxStart: l.OnTxStart, OnTxEnd: l.OnTxEnd, OnSystemCallStartV2: l.OnSystemCallStart, @@ -426,8 +426,8 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { return l } -func (t *mdLogger) Hooks() *tracing.Hooks { - return &tracing.Hooks{ +func (t *mdLogger) Hooks() tracing.Hooks { + return tracing.Hooks{ OnTxStart: t.OnTxStart, OnSystemCallStartV2: t.OnSystemCallStart, OnSystemCallEnd: t.OnSystemCallEnd, diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 52ac3945d453..fb3cca047e28 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -58,17 +58,17 @@ type jsonLogger struct { encoder *json.Encoder cfg *Config env *tracing.VMContext - hooks *tracing.Hooks + hooks tracing.Hooks } // NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects // into the provided stream. -func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks { +func NewJSONLogger(cfg *Config, writer io.Writer) tracing.Hooks { l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg} if l.cfg == nil { l.cfg = &Config{} } - l.hooks = &tracing.Hooks{ + l.hooks = tracing.Hooks{ OnTxStart: l.OnTxStart, OnSystemCallStart: l.onSystemCallStart, OnExit: l.OnExit, @@ -80,12 +80,12 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks { // NewJSONLoggerWithCallFrames creates a new EVM tracer that prints execution steps as JSON objects // into the provided stream. It also includes call frames in the output. -func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) *tracing.Hooks { +func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) tracing.Hooks { l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg} if l.cfg == nil { l.cfg = &Config{} } - l.hooks = &tracing.Hooks{ + l.hooks = tracing.Hooks{ OnTxStart: l.OnTxStart, OnSystemCallStart: l.onSystemCallStart, OnEnter: l.OnEnter, @@ -129,10 +129,10 @@ func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracin func (l *jsonLogger) onSystemCallStart() { // Process no events while in system call. - hooks := *l.hooks - *l.hooks = tracing.Hooks{ + hooks := l.hooks + l.hooks = tracing.Hooks{ OnSystemCallEnd: func() { - *l.hooks = hooks + l.hooks = hooks }, } } diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go index cec45a1e7a58..be59bbed6936 100644 --- a/eth/tracers/native/4byte.go +++ b/eth/tracers/native/4byte.go @@ -64,7 +64,7 @@ func newFourByteTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *p chainConfig: chainConfig, } return &tracers.Tracer{ - Hooks: &tracing.Hooks{ + Hooks: tracing.Hooks{ OnTxStart: t.OnTxStart, OnEnter: t.OnEnter, }, diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go index c2247d1ce491..7972db339539 100644 --- a/eth/tracers/native/call.go +++ b/eth/tracers/native/call.go @@ -132,7 +132,7 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *param return nil, err } return &tracers.Tracer{ - Hooks: &tracing.Hooks{ + Hooks: tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, OnEnter: t.OnEnter, diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 4e7fc31a9c6e..3f7ba95eb941 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -143,7 +143,7 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *p ft := &flatCallTracer{tracer: t, ctx: ctx, config: config, chainConfig: chainConfig} return &tracers.Tracer{ - Hooks: &tracing.Hooks{ + Hooks: tracing.Hooks{ OnTxStart: ft.OnTxStart, OnTxEnd: ft.OnTxEnd, OnEnter: ft.OnEnter, diff --git a/eth/tracers/native/erc7562.go b/eth/tracers/native/erc7562.go index 3ab98c7132ae..938012c56a8b 100644 --- a/eth/tracers/native/erc7562.go +++ b/eth/tracers/native/erc7562.go @@ -153,7 +153,7 @@ func newErc7562Tracer(ctx *tracers.Context, cfg json.RawMessage, _ *params.Chain return nil, err } return &tracers.Tracer{ - Hooks: &tracing.Hooks{ + Hooks: tracing.Hooks{ OnTxStart: t.OnTxStart, OnOpcode: t.OnOpcode, OnTxEnd: t.OnTxEnd, diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 77ab254568e6..8a9d6aebd5ce 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -57,7 +57,7 @@ func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params t := &muxTracer{names: names, tracers: objects} return &tracers.Tracer{ - Hooks: &tracing.Hooks{ + Hooks: tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, OnEnter: t.OnEnter, diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go index ac174cc25e7f..a7d3ae32fa08 100644 --- a/eth/tracers/native/noop.go +++ b/eth/tracers/native/noop.go @@ -39,7 +39,7 @@ type noopTracer struct{} func newNoopTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) { t := &noopTracer{} return &tracers.Tracer{ - Hooks: &tracing.Hooks{ + Hooks: tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, OnEnter: t.OnEnter, diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go index 57c66ae32723..1d33a99756b5 100644 --- a/eth/tracers/native/prestate.go +++ b/eth/tracers/native/prestate.go @@ -99,7 +99,7 @@ func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *p deleted: make(map[common.Address]bool), } return &tracers.Tracer{ - Hooks: &tracing.Hooks{ + Hooks: tracing.Hooks{ OnTxStart: t.OnTxStart, OnTxEnd: t.OnTxEnd, OnOpcode: t.OnOpcode, diff --git a/internal/ethapi/logtracer.go b/internal/ethapi/logtracer.go index 456aa937367f..5a8c6dc58b46 100644 --- a/internal/ethapi/logtracer.go +++ b/internal/ethapi/logtracer.go @@ -68,8 +68,8 @@ func newTracer(traceTransfers bool, blockNumber uint64, blockHash, txHash common } } -func (t *tracer) Hooks() *tracing.Hooks { - return &tracing.Hooks{ +func (t *tracer) Hooks() tracing.Hooks { + return tracing.Hooks{ OnEnter: t.onEnter, OnExit: t.onExit, OnLog: t.onLog, diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 362536bcb564..6cf21647c1e8 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -255,8 +255,8 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, senders = make(map[common.Hash]common.Address) ) tracingStateDB := vm.StateDB(sim.state) - if hooks := tracer.Hooks(); hooks != nil { - tracingStateDB = state.NewHookedState(sim.state, hooks) + if tracer != nil { + tracingStateDB = state.NewHookedState(sim.state, tracer.Hooks()) } evm := vm.NewEVM(blockContext, tracingStateDB, sim.chainConfig, *vmConfig) // It is possible to override precompiles with EVM bytecode, or diff --git a/tests/block_test.go b/tests/block_test.go index 91d9f2e653a0..76289022b19d 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/tracing" ) func TestBlockchain(t *testing.T) { @@ -105,7 +106,7 @@ func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) { } for _, snapshot := range snapshotConf { for _, dbscheme := range dbschemeConf { - if err := bt.checkFailure(t, test.Run(snapshot, dbscheme, true, nil, nil)); err != nil { + if err := bt.checkFailure(t, test.Run(snapshot, dbscheme, true, tracing.Hooks{}, nil)); err != nil { t.Errorf("test with config {snapshotter:%v, scheme:%v} failed: %v", snapshot, dbscheme, err) return } diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 3b88753b1c82..811366b93b20 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -111,7 +111,7 @@ type btHeaderMarshaling struct { ExcessBlobGas *math.HexOrDecimal64 } -func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) { +func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) { config, ok := Forks[t.json.Network] if !ok { return UnsupportedForkError{t.json.Network} diff --git a/tests/state_test_util.go b/tests/state_test_util.go index a22e470ad80f..33861f6b3c1c 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -323,8 +323,8 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh evm := vm.NewEVM(context, st.StateDB, config, vmconfig) - if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil { - tracer.OnTxStart(evm.GetVMContext(), nil, msg.From) + if evm.Config.Tracer.OnTxStart != nil { + evm.Config.Tracer.OnTxStart(evm.GetVMContext(), nil, msg.From) } // Execute the message. snapshot := st.StateDB.Snapshot() @@ -333,7 +333,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh vmRet, err := core.ApplyMessage(evm, msg, gaspool) if err != nil { st.StateDB.RevertToSnapshot(snapshot) - if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil { + if evm.Config.Tracer.OnTxEnd != nil { evm.Config.Tracer.OnTxEnd(nil, err) } return st, common.Hash{}, 0, err @@ -347,9 +347,9 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh // Commit state mutations into database. root, _ = st.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number()), config.IsCancun(block.Number(), block.Time())) - if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil { + if evm.Config.Tracer.OnTxEnd != nil { receipt := &types.Receipt{GasUsed: vmRet.UsedGas} - tracer.OnTxEnd(receipt, nil) + evm.Config.Tracer.OnTxEnd(receipt, nil) } return st, root, vmRet.UsedGas, nil }