diff --git a/cmd/evm/internal/t8ntool/file_tracer.go b/cmd/evm/internal/t8ntool/file_tracer.go index 38fc35bd322e..6b61906f1cc8 100644 --- a/cmd/evm/internal/t8ntool/file_tracer.go +++ b/cmd/evm/internal/t8ntool/file_tracer.go @@ -138,6 +138,15 @@ func (l *fileWritingTracer) hooks() *tracing.Hooks { l.inner.OnFault(pc, op, gas, cost, scope, depth, err) } }, + OnFaultV2: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + if l.inner != nil { + if l.inner.OnFaultV2 != nil { + l.inner.OnFaultV2(pc, op, gas, cost, scope, rData, depth, err) + } else 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 { l.inner.OnSystemCallStart() diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 8e50dc3d8f3e..d3fb846aa152 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -113,6 +113,12 @@ type ( // FaultHook is invoked when an error occurs during the execution of an opcode. FaultHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, depth int, err error) + // FaultHookV2 is invoked when an error occurs during the execution of an opcode. + // It includes the return data (e.g. revert reason) available at the time of the fault. + // This mirrors the signature of OpcodeHook by including rData and allows tracers to + // capture revert data directly at fault time. + FaultHookV2 = func(pc uint64, op byte, gas, cost uint64, scope OpContext, rData []byte, depth int, err error) + // GasChangeHook is invoked when the gas changes. GasChangeHook = func(old, new uint64, reason GasChangeReason) @@ -198,6 +204,7 @@ type Hooks struct { OnExit ExitHook OnOpcode OpcodeHook OnFault FaultHook + OnFaultV2 FaultHookV2 OnGasChange GasChangeHook // Chain events OnBlockchainInit BlockchainInitHook diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 52dbe83d86c7..2e2aff8f163e 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -155,8 +155,12 @@ func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte if !logged && evm.Config.Tracer.OnOpcode != nil { evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err)) } - if logged && evm.Config.Tracer.OnFault != nil { - evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, evm.depth, VMErrorFromErr(err)) + if logged { + if evm.Config.Tracer.OnFaultV2 != nil { + evm.Config.Tracer.OnFaultV2(pcCopy, byte(op), gasCopy, cost, callContext, evm.returnData, evm.depth, VMErrorFromErr(err)) + } else if evm.Config.Tracer.OnFault != nil { + evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, evm.depth, VMErrorFromErr(err)) + } } }() } diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go index 52ac3945d453..60a3b522df7d 100644 --- a/eth/tracers/logger/logger_json.go +++ b/eth/tracers/logger/logger_json.go @@ -74,6 +74,7 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks { OnExit: l.OnExit, OnOpcode: l.OnOpcode, OnFault: l.OnFault, + OnFaultV2: l.OnFaultV2, } return l.hooks } @@ -92,15 +93,19 @@ func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) *tracing.Hooks { OnExit: l.OnExit, OnOpcode: l.OnOpcode, OnFault: l.OnFault, + OnFaultV2: l.OnFaultV2, } return l.hooks } func (l *jsonLogger) OnFault(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) { - // TODO: Add rData to this interface as well l.OnOpcode(pc, op, gas, cost, scope, nil, depth, err) } +func (l *jsonLogger) OnFaultV2(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + l.OnOpcode(pc, op, gas, cost, scope, rData, depth, err) +} + func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { memory := scope.MemoryData() stack := scope.StackData() diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go index 77ab254568e6..6f924aec61c6 100644 --- a/eth/tracers/native/mux.go +++ b/eth/tracers/native/mux.go @@ -64,6 +64,7 @@ func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params OnExit: t.OnExit, OnOpcode: t.OnOpcode, OnFault: t.OnFault, + OnFaultV2: t.OnFaultV2, OnGasChange: t.OnGasChange, OnBalanceChange: t.OnBalanceChange, OnNonceChange: t.OnNonceChange, @@ -92,6 +93,16 @@ func (t *muxTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing. } } +func (t *muxTracer) OnFaultV2(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + for _, t := range t.tracers { + if t.OnFaultV2 != nil { + t.OnFaultV2(pc, op, gas, cost, scope, rData, depth, err) + } else if t.OnFault != nil { + t.OnFault(pc, op, gas, cost, scope, depth, err) + } + } +} + func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) { for _, t := range t.tracers { if t.OnGasChange != nil {