core, eth: use tracing.Hooks by value

the main motivation was to make Contract.UseGas and
Contract.RefundGas inlinable.
This commit is contained in:
Ömer Faruk IRMAK 2025-07-10 20:40:51 +03:00
parent 83aa643621
commit 57fa10b206
43 changed files with 241 additions and 254 deletions

View file

@ -255,7 +255,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
snapshot = statedb.Snapshot() snapshot = statedb.Snapshot()
prevGas = gaspool.Gas() 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) evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
} }
// (ret []byte, usedGas uint64, failed bool, err error) // (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) log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()}) rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
gaspool.SetGas(prevGas) 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) evm.Config.Tracer.OnTxEnd(nil, err)
} }
continue continue
@ -311,7 +311,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
//receipt.BlockNumber //receipt.BlockNumber
receipt.TransactionIndex = uint(txIndex) receipt.TransactionIndex = uint(txIndex)
receipts = append(receipts, receipt) 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) evm.Config.Tracer.OnTxEnd(receipt, nil)
} }
} }

View file

@ -36,7 +36,7 @@ import (
// and on tx end it closes the file. // and on tx end it closes the file.
type fileWritingTracer struct { type fileWritingTracer struct {
txIndex int // transaction counter txIndex int // transaction counter
inner *tracing.Hooks // inner hooks inner tracing.Hooks // inner hooks
destination io.WriteCloser // the currently open file (if any) destination io.WriteCloser // the currently open file (if any)
baseDir string // baseDir to write output-files to baseDir string // baseDir to write output-files to
suffix string // suffix is the suffix to use when creating files 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), // newFileWriter creates a set of hooks which wraps inner hooks (typically a logger),
// and writes the output to a file, one file per transaction. // 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{ t := &fileWritingTracer{
baseDir: baseDir, baseDir: baseDir,
suffix: "jsonl", 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, // newResultWriter creates a set of hooks wraps and invokes an underlying tracer,
// and writes the result (getResult-output) to file, one per transaction. // 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{ t := &fileWritingTracer{
baseDir: baseDir, baseDir: baseDir,
getResult: tracer.GetResult, getResult: tracer.GetResult,
@ -91,7 +91,7 @@ func (l *fileWritingTracer) OnTxStart(env *tracing.VMContext, tx *types.Transact
log.Info("Created tracing-file", "path", fname) log.Info("Created tracing-file", "path", fname)
l.destination = traceFile l.destination = traceFile
} }
if l.inner != nil && l.inner.OnTxStart != nil { if l.inner.OnTxStart != nil {
l.inner.OnTxStart(env, tx, from) 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, // OnTxEnd writes result (if getResult exist), closes any currently open output-file,
// and invokes the inner OnTxEnd handler. // and invokes the inner OnTxEnd handler.
func (l *fileWritingTracer) OnTxEnd(receipt *types.Receipt, err error) { 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) l.inner.OnTxEnd(receipt, err)
} }
if l.getResult != nil && l.destination != nil { if l.getResult != nil && l.destination != nil {
@ -114,37 +114,37 @@ func (l *fileWritingTracer) OnTxEnd(receipt *types.Receipt, err error) {
l.txIndex++ l.txIndex++
} }
func (l *fileWritingTracer) hooks() *tracing.Hooks { func (l *fileWritingTracer) hooks() tracing.Hooks {
return &tracing.Hooks{ return tracing.Hooks{
OnTxStart: l.OnTxStart, OnTxStart: l.OnTxStart,
OnTxEnd: l.OnTxEnd, OnTxEnd: l.OnTxEnd,
OnEnter: func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { 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) l.inner.OnEnter(depth, typ, from, to, input, gas, value)
} }
}, },
OnExit: func(depth int, output []byte, gasUsed uint64, err error, reverted bool) { 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) 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) { 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) 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) { 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) l.inner.OnFault(pc, op, gas, cost, scope, depth, err)
} }
}, },
OnSystemCallStart: func() { OnSystemCallStart: func() {
if l.inner != nil && l.inner.OnSystemCallStart != nil { if l.inner.OnSystemCallStart != nil {
l.inner.OnSystemCallStart() l.inner.OnSystemCallStart()
} }
}, },
OnSystemCallEnd: func() { OnSystemCallEnd: func() {
if l.inner != nil && l.inner.OnSystemCallEnd != nil { if l.inner.OnSystemCallEnd != nil {
l.inner.OnSystemCallEnd() l.inner.OnSystemCallEnd()
} }
}, },

View file

@ -167,11 +167,11 @@ func Transition(ctx *cli.Context) error {
EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name), EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name),
} }
if ctx.Bool(TraceEnableCallFramesFlag.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) return logger.NewJSONLoggerWithCallFrames(logConfig, out)
}) })
} else { } 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) return logger.NewJSONLogger(logConfig, out)
}) })
} }

View file

@ -229,7 +229,7 @@ func main() {
} }
// tracerFromFlags parses the cli flags and returns the specified tracer. // 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{ config := &logger.Config{
EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name), EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name),
DisableStack: ctx.Bool(TraceDisableStackFlag.Name), DisableStack: ctx.Bool(TraceDisableStackFlag.Name),
@ -248,7 +248,7 @@ func tracerFromFlags(ctx *cli.Context) *tracing.Hooks {
default: default:
fmt.Fprintf(os.Stderr, "unknown trace format: %q\n", format) fmt.Fprintf(os.Stderr, "unknown trace format: %q\n", format)
os.Exit(1) os.Exit(1)
return nil return tracing.Hooks{}
} }
// Deprecated ways of configuring tracing. // Deprecated ways of configuring tracing.
case ctx.Bool(MachineFlag.Name): case ctx.Bool(MachineFlag.Name):
@ -256,7 +256,7 @@ func tracerFromFlags(ctx *cli.Context) *tracing.Hooks {
case ctx.Bool(DebugFlag.Name): case ctx.Bool(DebugFlag.Name):
return logger.NewStreamingStructLogger(config, os.Stderr).Hooks() return logger.NewStreamingStructLogger(config, os.Stderr).Hooks()
default: default:
return nil return tracing.Hooks{}
} }
} }

View file

@ -198,7 +198,7 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, exe
func runCmd(ctx *cli.Context) error { func runCmd(ctx *cli.Context) error {
var ( var (
tracer *tracing.Hooks tracer tracing.Hooks
prestate *state.StateDB prestate *state.StateDB
chainConfig *params.ChainConfig chainConfig *params.ChainConfig
sender = common.BytesToAddress([]byte("sender")) sender = common.BytesToAddress([]byte("sender"))
@ -363,11 +363,11 @@ allocations: %d
allocated bytes: %d allocated bytes: %d
`, stats.GasUsed, stats.Time, stats.Allocs, stats.BytesAllocated) `, stats.GasUsed, stats.Time, stats.Allocs, stats.BytesAllocated)
} }
if tracer == nil { if len(output) > 0 {
fmt.Printf("%#x\n", output) 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 return nil

View file

@ -329,7 +329,7 @@ type BlockChain struct {
validator Validator // Block and state validator interface validator Validator // Block and state validator interface
prefetcher Prefetcher prefetcher Prefetcher
processor Processor // Block transaction processor interface processor Processor // Block transaction processor interface
logger *tracing.Hooks logger tracing.Hooks
lastForkReadyAlert time.Time // Last time there was a fork readiness print out 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. // it in advance.
bc.engine.VerifyHeader(bc, bc.CurrentHeader()) bc.engine.VerifyHeader(bc, bc.CurrentHeader())
if bc.logger != nil && bc.logger.OnBlockchainInit != nil { if bc.logger.OnBlockchainInit != nil {
bc.logger.OnBlockchainInit(chainConfig) 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 { if block := bc.CurrentBlock(); block.Number.Uint64() == 0 {
alloc, err := getGenesisState(bc.db, block.Hash()) alloc, err := getGenesisState(bc.db, block.Hash())
if err != nil { if err != nil {
@ -1311,7 +1311,7 @@ func (bc *BlockChain) Stop() {
} }
} }
// Allow tracers to clean-up and release resources. // Allow tracers to clean-up and release resources.
if bc.logger != nil && bc.logger.OnClose != nil { if bc.logger.OnClose != nil {
bc.logger.OnClose() bc.logger.OnClose()
} }
// Close the trie database, release all the held resources as the last step. // 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 return nil, it.index, err
} }
stats.processed++ stats.processed++
if bc.logger != nil && bc.logger.OnSkippedBlock != nil { if bc.logger.OnSkippedBlock != nil {
bc.logger.OnSkippedBlock(tracing.BlockEvent{ bc.logger.OnSkippedBlock(tracing.BlockEvent{
Block: block, Block: block,
Finalized: bc.CurrentFinalBlock(), 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) { go func(start time.Time, throwaway *state.StateDB, block *types.Block) {
// Disable tracing for prefetcher executions. // Disable tracing for prefetcher executions.
vmCfg := bc.cfg.VmConfig vmCfg := bc.cfg.VmConfig
vmCfg.Tracer = nil vmCfg.Tracer = tracing.Hooks{}
bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt) bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt)
blockPrefetchExecuteTimer.Update(time.Since(start)) blockPrefetchExecuteTimer.Update(time.Since(start))
@ -2026,14 +2026,14 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
defer statedb.StopPrefetcher() defer statedb.StopPrefetcher()
} }
if bc.logger != nil && bc.logger.OnBlockStart != nil { if bc.logger.OnBlockStart != nil {
bc.logger.OnBlockStart(tracing.BlockEvent{ bc.logger.OnBlockStart(tracing.BlockEvent{
Block: block, Block: block,
Finalized: bc.CurrentFinalBlock(), Finalized: bc.CurrentFinalBlock(),
Safe: bc.CurrentSafeBlock(), Safe: bc.CurrentSafeBlock(),
}) })
} }
if bc.logger != nil && bc.logger.OnBlockEnd != nil { if bc.logger.OnBlockEnd != nil {
defer func() { defer func() {
bc.logger.OnBlockEnd(blockEndErr) bc.logger.OnBlockEnd(blockEndErr)
}() }()

View file

@ -33,16 +33,12 @@ import (
// on state operations. // on state operations.
type hookedStateDB struct { type hookedStateDB struct {
inner *StateDB inner *StateDB
hooks *tracing.Hooks hooks tracing.Hooks
} }
// NewHookedState wraps the given stateDb with the given hooks // NewHookedState wraps the given stateDb with the given hooks
func NewHookedState(stateDb *StateDB, hooks *tracing.Hooks) *hookedStateDB { func NewHookedState(stateDb *StateDB, hooks tracing.Hooks) *hookedStateDB {
s := &hookedStateDB{stateDb, hooks} return &hookedStateDB{stateDb, hooks}
if s.hooks == nil {
s.hooks = new(tracing.Hooks)
}
return s
} }
func (s *hookedStateDB) CreateAccount(addr common.Address) { func (s *hookedStateDB) CreateAccount(addr common.Address) {

View file

@ -39,7 +39,7 @@ func TestBurn(t *testing.T) {
var burned = new(uint256.Int) var burned = new(uint256.Int)
s, _ := New(types.EmptyRootHash, NewDatabaseForTesting()) 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) { OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
if reason == tracing.BalanceDecreaseSelfdestructBurn { if reason == tracing.BalanceDecreaseSelfdestructBurn {
burned.Add(burned, uint256.MustFromBig(prev)) burned.Add(burned, uint256.MustFromBig(prev))
@ -94,7 +94,7 @@ func TestHooks(t *testing.T) {
emitF := func(format string, a ...any) { emitF := func(format string, a ...any) {
result = append(result, fmt.Sprintf(format, a...)) 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) { OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
emitF("%v.balance: %v->%v (%v)", addr, prev, new, reason) emitF("%v.balance: %v->%v (%v)", addr, prev, new, reason)
}, },

View file

@ -76,8 +76,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// Apply pre-execution system calls. // Apply pre-execution system calls.
var tracingStateDB = vm.StateDB(statedb) var tracingStateDB = vm.StateDB(statedb)
if hooks := cfg.Tracer; hooks != nil { if cfg.Tracer.HasStateHooks() {
tracingStateDB = state.NewHookedState(statedb, hooks) tracingStateDB = state.NewHookedState(statedb, cfg.Tracer)
} }
context = NewEVMBlockContext(header, p.chain, nil) context = NewEVMBlockContext(header, p.chain, nil)
evm := vm.NewEVM(context, tracingStateDB, p.config, cfg) 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, // and uses the input parameters for its environment similar to ApplyTransaction. However,
// this method takes an already created EVM instance as input. // 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) { 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 evm.Config.Tracer.OnTxStart != nil {
if hooks.OnTxStart != nil { evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From) }
} if evm.Config.Tracer.OnTxEnd != nil {
if hooks.OnTxEnd != nil { defer func() { evm.Config.Tracer.OnTxEnd(receipt, err) }()
defer func() { hooks.OnTxEnd(receipt, err) }()
}
} }
// Apply the transaction to the current state (included in the env). // Apply the transaction to the current state (included in the env).
result, err := ApplyMessage(evm, msg, gp) 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 // ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
// contract. This method is exported to be used in tests. // contract. This method is exported to be used in tests.
func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) { func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
if tracer := evm.Config.Tracer; tracer != nil { onSystemCallStart(&evm.Config.Tracer, evm.GetVMContext())
onSystemCallStart(tracer, evm.GetVMContext()) if evm.Config.Tracer.OnSystemCallEnd != nil {
if tracer.OnSystemCallEnd != nil { defer evm.Config.Tracer.OnSystemCallEnd()
defer tracer.OnSystemCallEnd()
}
} }
msg := &Message{ msg := &Message{
From: params.SystemAddress, 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 // ProcessParentBlockHash stores the parent block hash in the history storage contract
// as per EIP-2935/7709. // as per EIP-2935/7709.
func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) { func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) {
if tracer := evm.Config.Tracer; tracer != nil { onSystemCallStart(&evm.Config.Tracer, evm.GetVMContext())
onSystemCallStart(tracer, evm.GetVMContext()) if evm.Config.Tracer.OnSystemCallEnd != nil {
if tracer.OnSystemCallEnd != nil { defer evm.Config.Tracer.OnSystemCallEnd()
defer tracer.OnSystemCallEnd()
}
} }
msg := &Message{ msg := &Message{
From: params.SystemAddress, 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 { func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) error {
if tracer := evm.Config.Tracer; tracer != nil { onSystemCallStart(&evm.Config.Tracer, evm.GetVMContext())
onSystemCallStart(tracer, evm.GetVMContext()) if evm.Config.Tracer.OnSystemCallEnd != nil {
if tracer.OnSystemCallEnd != nil { defer evm.Config.Tracer.OnSystemCallEnd()
defer tracer.OnSystemCallEnd()
}
} }
msg := &Message{ msg := &Message{
From: params.SystemAddress, From: params.SystemAddress,

View file

@ -292,7 +292,7 @@ func (st *stateTransition) buyGas() error {
return err 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.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance)
} }
st.gasRemaining = st.msg.GasLimit 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) return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, msg.GasLimit, floorDataGas)
} }
} }
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { if st.evm.Config.Tracer.OnGasChange != nil {
t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas) st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas)
} }
st.gasRemaining -= gas st.gasRemaining -= gas
@ -530,8 +530,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
if st.gasUsed() < floorDataGas { if st.gasUsed() < floorDataGas {
prev := st.gasRemaining prev := st.gasRemaining
st.gasRemaining = st.initialGas - floorDataGas st.gasRemaining = st.initialGas - floorDataGas
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { if st.evm.Config.Tracer.OnGasChange != nil {
t.OnGasChange(prev, st.gasRemaining, tracing.GasChangeTxDataFloor) st.evm.Config.Tracer.OnGasChange(prev, st.gasRemaining, tracing.GasChangeTxDataFloor)
} }
} }
if peakGasUsed < floorDataGas { if peakGasUsed < floorDataGas {
@ -640,7 +640,7 @@ func (st *stateTransition) calcRefund() uint64 {
if refund > st.state.GetRefund() { if refund > st.state.GetRefund() {
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) st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, tracing.GasChangeTxRefunds)
} }
return refund return refund
@ -653,7 +653,7 @@ func (st *stateTransition) returnGas() {
remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice))
st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn) 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) st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, tracing.GasChangeTxLeftOverReturned)
} }

View file

@ -188,7 +188,8 @@ type (
) )
type Hooks struct { type Hooks struct {
// VM events // VM events, make sure to update HasVMHooks
// if you ever add a new hook here
OnTxStart TxStartHook OnTxStart TxStartHook
OnTxEnd TxEndHook OnTxEnd TxEndHook
OnEnter EnterHook OnEnter EnterHook
@ -206,7 +207,8 @@ type Hooks struct {
OnSystemCallStart OnSystemCallStartHook OnSystemCallStart OnSystemCallStartHook
OnSystemCallStartV2 OnSystemCallStartHookV2 OnSystemCallStartV2 OnSystemCallStartHookV2
OnSystemCallEnd OnSystemCallEndHook OnSystemCallEnd OnSystemCallEndHook
// State events // State events, make sure to update HasStateHooks
// if you ever add a new hook here
OnBalanceChange BalanceChangeHook OnBalanceChange BalanceChangeHook
OnNonceChange NonceChangeHook OnNonceChange NonceChangeHook
OnNonceChangeV2 NonceChangeHookV2 OnNonceChangeV2 NonceChangeHookV2
@ -217,6 +219,27 @@ type Hooks struct {
OnBlockHashRead BlockHashReadHook 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 // BalanceChangeReason is used to indicate the reason for a balance change, useful
// for tracing and reporting. // for tracing and reporting.
type BalanceChangeReason byte type BalanceChangeReason byte

View file

@ -126,24 +126,24 @@ func (c *Contract) Caller() common.Address {
} }
// UseGas attempts the use gas and subtracts it and returns true on success // 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 { if c.Gas < gas {
return false return false
} }
if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { if onGasChange != nil && reason != tracing.GasChangeIgnored {
logger.OnGasChange(c.Gas, c.Gas-gas, reason) onGasChange(c.Gas, c.Gas-gas, reason)
} }
c.Gas -= gas c.Gas -= gas
return true return true
} }
// RefundGas refunds gas to the contract // 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 { if gas == 0 {
return return
} }
if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { if onGasChange != nil && reason != tracing.GasChangeIgnored {
logger.OnGasChange(c.Gas, c.Gas+gas, reason) onGasChange(c.Gas, c.Gas+gas, reason)
} }
c.Gas += gas c.Gas += gas
} }

View file

@ -257,13 +257,13 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
// - the returned bytes, // - the returned bytes,
// - the _remaining_ gas, // - the _remaining_ gas,
// - any error that occurred // - 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) gasCost := p.RequiredGas(input)
if suppliedGas < gasCost { if suppliedGas < gasCost {
return nil, 0, ErrOutOfGas return nil, 0, ErrOutOfGas
} }
if logger != nil && logger.OnGasChange != nil { if onGasChange != nil {
logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract) onGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract)
} }
suppliedGas -= gasCost suppliedGas -= gasCost
output, err := p.Run(input) output, err := p.Run(input)

View file

@ -358,7 +358,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
code := interpreter.evm.StateDB.GetCode(addr) code := interpreter.evm.StateDB.GetCode(addr)
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64()) paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas) 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 { if consumed < wanted {
return nil, ErrOutOfGas return nil, ErrOutOfGas
} }
@ -384,7 +384,7 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
// advanced past this boundary. // advanced past this boundary.
contractAddr := scope.Contract.Address() contractAddr := scope.Contract.Address()
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) 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 { if consumed < wanted {
return nil, ErrOutOfGas return nil, ErrOutOfGas
} }
@ -412,7 +412,7 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall { if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall {
contractAddr := scope.Contract.Address() contractAddr := scope.Contract.Address()
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) 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 { if consumed < wanted {
return nil, ErrOutOfGas return nil, ErrOutOfGas
} }

View file

@ -125,6 +125,9 @@ type EVM struct {
// jumpDests is the aggregated result of JUMPDEST analysis made through // jumpDests is the aggregated result of JUMPDEST analysis made through
// the life cycle of EVM. // the life cycle of EVM.
jumpDests map[common.Hash]bitvec 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 // NewEVM constructs an EVM instance with the supplied block context, state
@ -133,12 +136,13 @@ type EVM struct {
// needed by calling evm.SetTxContext. // needed by calling evm.SetTxContext.
func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM { func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM {
evm := &EVM{ evm := &EVM{
Context: blockCtx, Context: blockCtx,
StateDB: statedb, StateDB: statedb,
Config: config, Config: config,
chainConfig: chainConfig, chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time), chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
jumpDests: make(map[common.Hash]bitvec), jumpDests: make(map[common.Hash]bitvec),
tracingEnabled: config.Tracer.HasVMHooks(),
} }
evm.precompiles = activePrecompiledContracts(evm.chainRules) evm.precompiles = activePrecompiledContracts(evm.chainRules)
evm.interpreter = NewEVMInterpreter(evm) 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 // the necessary steps to create accounts and reverses the state in case of an
// execution error or failed value transfer. // 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) { 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.tracingEnabled {
if evm.Config.Tracer != nil { // Capture the tracer start/end events in debug mode
evm.captureBegin(evm.depth, CALL, caller, addr, input, gas, value.ToBig()) evm.captureBegin(evm.depth, CALL, caller, addr, input, gas, value.ToBig())
defer func(startGas uint64) { defer func(startGas uint64) {
evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) 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) evm.Context.Transfer(evm.StateDB, caller, addr, value)
if isPrecompile { if isPrecompile {
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer) ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer.OnGasChange)
} else { } else {
// Initialise a new contract and set the code that is to be used by the EVM. // Initialise a new contract and set the code that is to be used by the EVM.
code := evm.resolveCode(addr) code := evm.resolveCode(addr)
@ -251,7 +255,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
if err != nil { if err != nil {
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted { 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) 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' // CallCode differs from Call in the sense that it executes the given address'
// code with the caller as context. // 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) { 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.tracingEnabled {
if evm.Config.Tracer != nil { // Invoke tracer hooks that signal entering/exiting a call frame
evm.captureBegin(evm.depth, CALLCODE, caller, addr, input, gas, value.ToBig()) evm.captureBegin(evm.depth, CALLCODE, caller, addr, input, gas, value.ToBig())
defer func(startGas uint64) { defer func(startGas uint64) {
evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) 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 // It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(addr); isPrecompile { 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 { } else {
// Initialise a new contract and set the code that is to be used by the EVM. // 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. // 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 { if err != nil {
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted { 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) evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
} }
gas = 0 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' // 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. // 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) { 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.tracingEnabled {
if evm.Config.Tracer != nil { // Invoke tracer hooks that signal entering/exiting a call frame
// DELEGATECALL inherits value from parent call // DELEGATECALL inherits value from parent call
evm.captureBegin(evm.depth, DELEGATECALL, caller, addr, input, gas, value.ToBig()) evm.captureBegin(evm.depth, DELEGATECALL, caller, addr, input, gas, value.ToBig())
defer func(startGas uint64) { 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 // It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(addr); isPrecompile { 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 { } else {
// Initialise a new contract and make initialise the delegate values // 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 { if err != nil {
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted { 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) evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
} }
gas = 0 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 // Opcodes that attempt to perform such modifications will result in exceptions
// instead of performing the modifications. // 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) { 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.tracingEnabled {
if evm.Config.Tracer != nil { // Invoke tracer hooks that signal entering/exiting a call frame
evm.captureBegin(evm.depth, STATICCALL, caller, addr, input, gas, nil) evm.captureBegin(evm.depth, STATICCALL, caller, addr, input, gas, nil)
defer func(startGas uint64) { defer func(startGas uint64) {
evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) 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) evm.StateDB.AddBalance(addr, new(uint256.Int), tracing.BalanceChangeTouchAccount)
if p, isPrecompile := evm.precompile(addr); isPrecompile { 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 { } else {
// Initialise a new contract and set the code that is to be used by the EVM. // 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. // 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 { if err != nil {
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted { 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) 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. // 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) { 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()) evm.captureBegin(evm.depth, typ, caller, address, code, gas, value.ToBig())
defer func(startGas uint64) { defer func(startGas uint64) {
evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) 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 { if statelessGas > gas {
return nil, common.Address{}, 0, ErrOutOfGas 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) evm.Config.Tracer.OnGasChange(gas, gas-statelessGas, tracing.GasChangeWitnessContractCollisionCheck)
} }
gas = gas - statelessGas 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 || if evm.StateDB.GetNonce(address) != 0 ||
(contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code
(storageRoot != (common.Hash{}) && storageRoot != types.EmptyRootHash) { // non-empty storage (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) evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
} }
return nil, common.Address{}, 0, ErrContractAddressCollision 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 { if consumed < wanted {
return nil, common.Address{}, 0, ErrOutOfGas 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) evm.Config.Tracer.OnGasChange(gas, gas-consumed, tracing.GasChangeWitnessContractInit)
} }
gas = gas - consumed 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) { if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted { 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 return ret, address, contract.Gas, err
@ -537,12 +541,12 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
if !evm.chainRules.IsEIP4762 { if !evm.chainRules.IsEIP4762 {
createDataGas := uint64(len(ret)) * params.CreateDataGas 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 return ret, ErrCodeStoreOutOfGas
} }
} else { } else {
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true, contract.Gas) 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) { if len(ret) > 0 && (consumed < wanted) {
return ret, ErrCodeStoreOutOfGas 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) 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) { 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 evm.Config.Tracer.OnEnter != nil {
if tracer.OnEnter != nil { evm.Config.Tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value)
tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value)
} }
if tracer.OnGasChange != nil { if evm.Config.Tracer.OnGasChange != nil {
tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance) evm.Config.Tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance)
} }
} }
func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret []byte, err error) { func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret []byte, err error) {
tracer := evm.Config.Tracer if evm.Config.Tracer.OnGasChange != nil && leftOverGas != 0 {
if leftOverGas != 0 && tracer.OnGasChange != nil { evm.Config.Tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned)
tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned)
} }
var reverted bool if evm.Config.Tracer.OnExit != nil {
if err != nil { reverted := err != nil && (evm.chainRules.IsHomestead || !errors.Is(err, ErrCodeStoreOutOfGas))
reverted = true evm.Config.Tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
}
if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) {
reverted = false
}
if tracer.OnExit != nil {
tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
} }
} }

View file

@ -443,8 +443,8 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
if witness := interpreter.evm.StateDB.Witness(); witness != nil { if witness := interpreter.evm.StateDB.Witness(); witness != nil {
witness.AddBlockHash(num64) witness.AddBlockHash(num64)
} }
if tracer := interpreter.evm.Config.Tracer; tracer != nil && tracer.OnBlockHashRead != nil { if interpreter.evm.Config.Tracer.OnBlockHashRead != nil {
tracer.OnBlockHashRead(num64, res) interpreter.evm.Config.Tracer.OnBlockHashRead(num64, res)
} }
num.SetBytes(res[:]) num.SetBytes(res[:])
} else { } else {
@ -670,7 +670,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
// reuse size int for stackvalue // reuse size int for stackvalue
stackvalue := size 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) 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 // 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.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 { if suberr == ErrExecutionReverted {
interpreter.returnData = res // set REVERT data to return data buffer interpreter.returnData = res // set REVERT data to return data buffer
@ -710,7 +710,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
// Apply EIP150 // Apply EIP150
gas -= gas / 64 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 // reuse size int for stackvalue
stackvalue := size stackvalue := size
res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract.Address(), input, gas, 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()) stackvalue.SetBytes(addr.Bytes())
} }
scope.Stack.push(&stackvalue) 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 { if suberr == ErrExecutionReverted {
interpreter.returnData = res // set REVERT data to return data buffer 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.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 interpreter.returnData = ret
return ret, nil return ret, nil
@ -795,7 +795,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) 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 interpreter.returnData = ret
return ret, nil return ret, nil
@ -824,7 +824,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) 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 interpreter.returnData = ret
return ret, nil return ret, nil
@ -853,7 +853,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) 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 interpreter.returnData = ret
return ret, nil return ret, nil
@ -890,13 +890,11 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address()) balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address()) interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
if tracer := interpreter.evm.Config.Tracer; tracer != nil { if interpreter.evm.Config.Tracer.OnEnter != nil {
if tracer.OnEnter != nil { interpreter.evm.Config.Tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) }
} if interpreter.evm.Config.Tracer.OnExit != nil {
if tracer.OnExit != nil { interpreter.evm.Config.Tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
}
} }
return nil, errStopToken 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.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct) interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
interpreter.evm.StateDB.SelfDestruct6780(scope.Contract.Address()) interpreter.evm.StateDB.SelfDestruct6780(scope.Contract.Address())
if tracer := interpreter.evm.Config.Tracer; tracer != nil { if interpreter.evm.Config.Tracer.OnEnter != nil {
if tracer.OnEnter != nil { interpreter.evm.Config.Tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig()) }
} if interpreter.evm.Config.Tracer.OnExit != nil {
if tracer.OnExit != nil { interpreter.evm.Config.Tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
}
} }
return nil, errStopToken return nil, errStopToken
} }

View file

@ -29,7 +29,7 @@ import (
// Config are the configuration options for the Interpreter // Config are the configuration options for the Interpreter
type Config struct { type Config struct {
Tracer *tracing.Hooks Tracer tracing.Hooks
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls) NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
ExtraEips []int // Additional EIPS that are to be enabled 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 gasCopy uint64 // for EVMLogger to log gas remaining before execution
logged bool // deferred EVMLogger should ignore already logged steps logged bool // deferred EVMLogger should ignore already logged steps
res []byte // result of the opcode execution function 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, // 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 // 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 contract.Input = input
if debug { defer func() { // this deferred method handles exit-with-error
defer func() { // this deferred method handles exit-with-error if err == nil {
if err == nil { return
return }
} if !logged && in.evm.Config.Tracer.OnOpcode != nil {
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))
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 {
if logged && in.evm.Config.Tracer.OnFault != nil { in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err))
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 // The Interpreter main run loop (contextual). This loop runs until either an
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during // 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 // the execution of one of the operations or until the done flag is set by the
// parent context. // parent context.
_ = jumpTable[0] // nil-check the jumpTable out of the loop _ = jumpTable[0] // nil-check the jumpTable out of the loop
for { for {
if debug { // Capture pre-execution values for tracing.
// Capture pre-execution values for tracing. logged, pcCopy, gasCopy = false, pc, contract.Gas
logged, pcCopy, gasCopy = false, pc, contract.Gas
}
if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment && !contract.IsSystemCall { if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment && !contract.IsSystemCall {
// if the PC ends up in a new "chunk" of verkleized code, charge the // if the PC ends up in a new "chunk" of verkleized code, charge the
// associated costs. // associated costs.
contractAddr := contract.Address() contractAddr := contract.Address()
consumed, wanted := in.evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas) 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 { if consumed < wanted {
return nil, ErrOutOfGas return nil, ErrOutOfGas
} }
@ -301,14 +296,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
} }
// Do tracing before potential memory expansion // Do tracing before potential memory expansion
if debug { if in.evm.Config.Tracer.OnGasChange != nil {
if in.evm.Config.Tracer.OnGasChange != nil { in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode) }
} if in.evm.Config.Tracer.OnOpcode != nil {
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))
in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err)) logged = true
logged = true
}
} }
if memorySize > 0 { if memorySize > 0 {
mem.Resize(memorySize) mem.Resize(memorySize)

View file

@ -164,7 +164,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) g
evm.StateDB.AddAddressToAccessList(addr) evm.StateDB.AddAddressToAccessList(addr)
// Charge the remaining difference here already, to correctly calculate available // Charge the remaining difference here already, to correctly calculate available
// gas for call // 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 return 0, ErrOutOfGas
} }
} }
@ -265,7 +265,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929 coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
// Charge the remaining difference here already, to correctly calculate available // Charge the remaining difference here already, to correctly calculate available
// gas for call // 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 return 0, ErrOutOfGas
} }
total += coldCost total += coldCost
@ -280,7 +280,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
evm.StateDB.AddAddressToAccessList(target) evm.StateDB.AddAddressToAccessList(target)
cost = params.ColdAccountAccessCostEIP2929 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 return 0, ErrOutOfGas
} }
total += cost total += cost

View file

@ -130,7 +130,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
vmenv = NewEnv(cfg) vmenv = NewEnv(cfg)
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) 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) 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: // 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, cfg.GasLimit,
uint256.MustFromBig(cfg.Value), 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) cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err)
} }
return ret, cfg.State, err return ret, cfg.State, err
@ -168,7 +168,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
vmenv = NewEnv(cfg) vmenv = NewEnv(cfg)
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) 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) 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: // 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, cfg.GasLimit,
uint256.MustFromBig(cfg.Value), 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) cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err)
} }
return code, address, 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 statedb = cfg.State
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time) 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) 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: // 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, cfg.GasLimit,
uint256.MustFromBig(cfg.Value), 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) cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err)
} }
return ret, leftOverGas, err return ret, leftOverGas, err

View file

@ -666,7 +666,7 @@ func TestColdAccountAccessCost(t *testing.T) {
var have = uint64(0) var have = uint64(0)
Execute(tc.code, nil, &Config{ Execute(tc.code, nil, &Config{
EVMConfig: vm.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) { OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
// Uncomment to investigate failures: // Uncomment to investigate failures:
//t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost) //t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost)
@ -920,7 +920,7 @@ func TestDelegatedAccountAccessCost(t *testing.T) {
ChainConfig: params.MergedTestChainConfig, ChainConfig: params.MergedTestChainConfig,
State: statedb, State: statedb,
EVMConfig: vm.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) { OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
// Uncomment to investigate failures: // Uncomment to investigate failures:
t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost) t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost)

View file

@ -208,7 +208,7 @@ func newStateTracer(ctx *Context, cfg json.RawMessage, chainCfg *params.ChainCon
GetResult: func() (json.RawMessage, error) { GetResult: func() (json.RawMessage, error) {
return json.Marshal(t) return json.Marshal(t)
}, },
Hooks: &tracing.Hooks{ Hooks: tracing.Hooks{
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
t.Balance[addr] = (*hexutil.Big)(new) t.Balance[addr] = (*hexutil.Big)(new)
}, },

View file

@ -39,7 +39,7 @@ type Context struct {
// This involves a method to retrieve results and one to // This involves a method to retrieve results and one to
// stop tracing. // stop tracing.
type Tracer struct { type Tracer struct {
*tracing.Hooks tracing.Hooks
GetResult func() (json.RawMessage, error) GetResult func() (json.RawMessage, error)
// Stop terminates execution of the tracer at the first opportune moment. // Stop terminates execution of the tracer at the first opportune moment.
Stop func(err error) Stop func(err error)

View file

@ -121,10 +121,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to create call tracer: %v", err) t.Fatalf("failed to create call tracer: %v", err)
} }
logState := vm.StateDB(st.StateDB) logState := state.NewHookedState(st.StateDB, tracer.Hooks)
if tracer.Hooks != nil {
logState = state.NewHookedState(st.StateDB, tracer.Hooks)
}
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)
@ -355,11 +352,7 @@ func TestInternals(t *testing.T) {
}, false, rawdb.HashScheme) }, false, rawdb.HashScheme)
defer st.Close() defer st.Close()
logState := vm.StateDB(st.StateDB) logState := state.NewHookedState(st.StateDB, tc.tracer.Hooks)
if hooks := tc.tracer.Hooks; hooks != nil {
logState = state.NewHookedState(st.StateDB, hooks)
}
tx, err := types.SignNewTx(key, signer, &types.LegacyTx{ tx, err := types.SignNewTx(key, signer, &types.LegacyTx{
To: &to, To: &to,
Value: big.NewInt(0), Value: big.NewInt(0),

View file

@ -114,10 +114,7 @@ func TestErc7562Tracer(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to create erc7562 tracer: %v", err) t.Fatalf("failed to create erc7562 tracer: %v", err)
} }
logState := vm.StateDB(st.StateDB) logState := state.NewHookedState(st.StateDB, tracer.Hooks)
if tracer.Hooks != nil {
logState = state.NewHookedState(st.StateDB, tracer.Hooks)
}
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee) msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
if err != nil { if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err) t.Fatalf("failed to prepare transaction for tracing: %v", err)

View file

@ -235,7 +235,7 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage, chainCo
t.logValue = t.log.setupObject() t.logValue = t.log.setupObject()
return &tracers.Tracer{ return &tracers.Tracer{
Hooks: &tracing.Hooks{ Hooks: tracing.Hooks{
OnTxStart: t.OnTxStart, OnTxStart: t.OnTxStart,
OnTxEnd: t.OnTxEnd, OnTxEnd: t.OnTxEnd,
OnEnter: t.OnEnter, OnEnter: t.OnEnter,

View file

@ -23,7 +23,7 @@ import (
"github.com/ethereum/go-ethereum/core/tracing" "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 // LiveDirectory is the collection of tracers which can be used
// during normal block import operations. // during normal block import operations.
@ -39,12 +39,12 @@ func (d *liveDirectory) Register(name string, f ctorFunc) {
} }
// New instantiates a tracer by name. // 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 { if len(config) == 0 {
config = json.RawMessage("{}") config = json.RawMessage("{}")
} }
if f, ok := d.elems[name]; ok { if f, ok := d.elems[name]; ok {
return f(config) return f(config)
} }
return nil, errors.New("not found") return tracing.Hooks{}, errors.New("not found")
} }

View file

@ -37,9 +37,9 @@ func init() {
// as soon as we have a real live tracer. // as soon as we have a real live tracer.
type noop struct{} type noop struct{}
func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) { func newNoopTracer(_ json.RawMessage) (tracing.Hooks, error) {
t := &noop{} t := &noop{}
return &tracing.Hooks{ return tracing.Hooks{
OnTxStart: t.OnTxStart, OnTxStart: t.OnTxStart,
OnTxEnd: t.OnTxEnd, OnTxEnd: t.OnTxEnd,
OnEnter: t.OnEnter, OnEnter: t.OnEnter,

View file

@ -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. 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 var config supplyTracerConfig
if err := json.Unmarshal(cfg, &config); err != nil { 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 == "" { 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 // Store traces in a rotating file
@ -113,7 +113,7 @@ func newSupplyTracer(cfg json.RawMessage) (*tracing.Hooks, error) {
delta: newSupplyInfo(), delta: newSupplyInfo(),
logger: logger, logger: logger,
} }
return &tracing.Hooks{ return tracing.Hooks{
OnBlockchainInit: t.onBlockchainInit, OnBlockchainInit: t.onBlockchainInit,
OnBlockStart: t.onBlockStart, OnBlockStart: t.onBlockStart,
OnBlockEnd: t.onBlockEnd, OnBlockEnd: t.onBlockEnd,

View file

@ -119,8 +119,8 @@ func NewAccessListTracer(acl types.AccessList, addressesToExclude map[common.Add
} }
} }
func (a *AccessListTracer) Hooks() *tracing.Hooks { func (a *AccessListTracer) Hooks() tracing.Hooks {
return &tracing.Hooks{ return tracing.Hooks{
OnOpcode: a.OnOpcode, OnOpcode: a.OnOpcode,
} }
} }

View file

@ -244,8 +244,8 @@ func NewStructLogger(cfg *Config) *StructLogger {
return logger return logger
} }
func (l *StructLogger) Hooks() *tracing.Hooks { func (l *StructLogger) Hooks() tracing.Hooks {
return &tracing.Hooks{ return tracing.Hooks{
OnTxStart: l.OnTxStart, OnTxStart: l.OnTxStart,
OnTxEnd: l.OnTxEnd, OnTxEnd: l.OnTxEnd,
OnSystemCallStartV2: l.OnSystemCallStart, OnSystemCallStartV2: l.OnSystemCallStart,
@ -426,8 +426,8 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger {
return l return l
} }
func (t *mdLogger) Hooks() *tracing.Hooks { func (t *mdLogger) Hooks() tracing.Hooks {
return &tracing.Hooks{ return tracing.Hooks{
OnTxStart: t.OnTxStart, OnTxStart: t.OnTxStart,
OnSystemCallStartV2: t.OnSystemCallStart, OnSystemCallStartV2: t.OnSystemCallStart,
OnSystemCallEnd: t.OnSystemCallEnd, OnSystemCallEnd: t.OnSystemCallEnd,

View file

@ -58,17 +58,17 @@ type jsonLogger struct {
encoder *json.Encoder encoder *json.Encoder
cfg *Config cfg *Config
env *tracing.VMContext env *tracing.VMContext
hooks *tracing.Hooks hooks tracing.Hooks
} }
// NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects // NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects
// into the provided stream. // 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} l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg}
if l.cfg == nil { if l.cfg == nil {
l.cfg = &Config{} l.cfg = &Config{}
} }
l.hooks = &tracing.Hooks{ l.hooks = tracing.Hooks{
OnTxStart: l.OnTxStart, OnTxStart: l.OnTxStart,
OnSystemCallStart: l.onSystemCallStart, OnSystemCallStart: l.onSystemCallStart,
OnExit: l.OnExit, 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 // 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. // 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} l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg}
if l.cfg == nil { if l.cfg == nil {
l.cfg = &Config{} l.cfg = &Config{}
} }
l.hooks = &tracing.Hooks{ l.hooks = tracing.Hooks{
OnTxStart: l.OnTxStart, OnTxStart: l.OnTxStart,
OnSystemCallStart: l.onSystemCallStart, OnSystemCallStart: l.onSystemCallStart,
OnEnter: l.OnEnter, OnEnter: l.OnEnter,
@ -129,10 +129,10 @@ func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracin
func (l *jsonLogger) onSystemCallStart() { func (l *jsonLogger) onSystemCallStart() {
// Process no events while in system call. // Process no events while in system call.
hooks := *l.hooks hooks := l.hooks
*l.hooks = tracing.Hooks{ l.hooks = tracing.Hooks{
OnSystemCallEnd: func() { OnSystemCallEnd: func() {
*l.hooks = hooks l.hooks = hooks
}, },
} }
} }

View file

@ -64,7 +64,7 @@ func newFourByteTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *p
chainConfig: chainConfig, chainConfig: chainConfig,
} }
return &tracers.Tracer{ return &tracers.Tracer{
Hooks: &tracing.Hooks{ Hooks: tracing.Hooks{
OnTxStart: t.OnTxStart, OnTxStart: t.OnTxStart,
OnEnter: t.OnEnter, OnEnter: t.OnEnter,
}, },

View file

@ -132,7 +132,7 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *param
return nil, err return nil, err
} }
return &tracers.Tracer{ return &tracers.Tracer{
Hooks: &tracing.Hooks{ Hooks: tracing.Hooks{
OnTxStart: t.OnTxStart, OnTxStart: t.OnTxStart,
OnTxEnd: t.OnTxEnd, OnTxEnd: t.OnTxEnd,
OnEnter: t.OnEnter, OnEnter: t.OnEnter,

View file

@ -143,7 +143,7 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *p
ft := &flatCallTracer{tracer: t, ctx: ctx, config: config, chainConfig: chainConfig} ft := &flatCallTracer{tracer: t, ctx: ctx, config: config, chainConfig: chainConfig}
return &tracers.Tracer{ return &tracers.Tracer{
Hooks: &tracing.Hooks{ Hooks: tracing.Hooks{
OnTxStart: ft.OnTxStart, OnTxStart: ft.OnTxStart,
OnTxEnd: ft.OnTxEnd, OnTxEnd: ft.OnTxEnd,
OnEnter: ft.OnEnter, OnEnter: ft.OnEnter,

View file

@ -153,7 +153,7 @@ func newErc7562Tracer(ctx *tracers.Context, cfg json.RawMessage, _ *params.Chain
return nil, err return nil, err
} }
return &tracers.Tracer{ return &tracers.Tracer{
Hooks: &tracing.Hooks{ Hooks: tracing.Hooks{
OnTxStart: t.OnTxStart, OnTxStart: t.OnTxStart,
OnOpcode: t.OnOpcode, OnOpcode: t.OnOpcode,
OnTxEnd: t.OnTxEnd, OnTxEnd: t.OnTxEnd,

View file

@ -57,7 +57,7 @@ func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params
t := &muxTracer{names: names, tracers: objects} t := &muxTracer{names: names, tracers: objects}
return &tracers.Tracer{ return &tracers.Tracer{
Hooks: &tracing.Hooks{ Hooks: tracing.Hooks{
OnTxStart: t.OnTxStart, OnTxStart: t.OnTxStart,
OnTxEnd: t.OnTxEnd, OnTxEnd: t.OnTxEnd,
OnEnter: t.OnEnter, OnEnter: t.OnEnter,

View file

@ -39,7 +39,7 @@ type noopTracer struct{}
func newNoopTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) { func newNoopTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
t := &noopTracer{} t := &noopTracer{}
return &tracers.Tracer{ return &tracers.Tracer{
Hooks: &tracing.Hooks{ Hooks: tracing.Hooks{
OnTxStart: t.OnTxStart, OnTxStart: t.OnTxStart,
OnTxEnd: t.OnTxEnd, OnTxEnd: t.OnTxEnd,
OnEnter: t.OnEnter, OnEnter: t.OnEnter,

View file

@ -99,7 +99,7 @@ func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *p
deleted: make(map[common.Address]bool), deleted: make(map[common.Address]bool),
} }
return &tracers.Tracer{ return &tracers.Tracer{
Hooks: &tracing.Hooks{ Hooks: tracing.Hooks{
OnTxStart: t.OnTxStart, OnTxStart: t.OnTxStart,
OnTxEnd: t.OnTxEnd, OnTxEnd: t.OnTxEnd,
OnOpcode: t.OnOpcode, OnOpcode: t.OnOpcode,

View file

@ -68,8 +68,8 @@ func newTracer(traceTransfers bool, blockNumber uint64, blockHash, txHash common
} }
} }
func (t *tracer) Hooks() *tracing.Hooks { func (t *tracer) Hooks() tracing.Hooks {
return &tracing.Hooks{ return tracing.Hooks{
OnEnter: t.onEnter, OnEnter: t.onEnter,
OnExit: t.onExit, OnExit: t.onExit,
OnLog: t.onLog, OnLog: t.onLog,

View file

@ -255,8 +255,8 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
senders = make(map[common.Hash]common.Address) senders = make(map[common.Hash]common.Address)
) )
tracingStateDB := vm.StateDB(sim.state) tracingStateDB := vm.StateDB(sim.state)
if hooks := tracer.Hooks(); hooks != nil { if tracer != nil {
tracingStateDB = state.NewHookedState(sim.state, hooks) tracingStateDB = state.NewHookedState(sim.state, tracer.Hooks())
} }
evm := vm.NewEVM(blockContext, tracingStateDB, sim.chainConfig, *vmConfig) evm := vm.NewEVM(blockContext, tracingStateDB, sim.chainConfig, *vmConfig)
// It is possible to override precompiles with EVM bytecode, or // It is possible to override precompiles with EVM bytecode, or

View file

@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/tracing"
) )
func TestBlockchain(t *testing.T) { func TestBlockchain(t *testing.T) {
@ -105,7 +106,7 @@ func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) {
} }
for _, snapshot := range snapshotConf { for _, snapshot := range snapshotConf {
for _, dbscheme := range dbschemeConf { 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) t.Errorf("test with config {snapshotter:%v, scheme:%v} failed: %v", snapshot, dbscheme, err)
return return
} }

View file

@ -111,7 +111,7 @@ type btHeaderMarshaling struct {
ExcessBlobGas *math.HexOrDecimal64 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] config, ok := Forks[t.json.Network]
if !ok { if !ok {
return UnsupportedForkError{t.json.Network} return UnsupportedForkError{t.json.Network}

View file

@ -323,8 +323,8 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
evm := vm.NewEVM(context, st.StateDB, config, vmconfig) evm := vm.NewEVM(context, st.StateDB, config, vmconfig)
if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil { if evm.Config.Tracer.OnTxStart != nil {
tracer.OnTxStart(evm.GetVMContext(), nil, msg.From) evm.Config.Tracer.OnTxStart(evm.GetVMContext(), nil, msg.From)
} }
// Execute the message. // Execute the message.
snapshot := st.StateDB.Snapshot() 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) vmRet, err := core.ApplyMessage(evm, msg, gaspool)
if err != nil { if err != nil {
st.StateDB.RevertToSnapshot(snapshot) 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) evm.Config.Tracer.OnTxEnd(nil, err)
} }
return st, common.Hash{}, 0, 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. // Commit state mutations into database.
root, _ = st.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number()), config.IsCancun(block.Number(), block.Time())) 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} receipt := &types.Receipt{GasUsed: vmRet.UsedGas}
tracer.OnTxEnd(receipt, nil) evm.Config.Tracer.OnTxEnd(receipt, nil)
} }
return st, root, vmRet.UsedGas, nil return st, root, vmRet.UsedGas, nil
} }