eth/tracers: fix evm trace for t8n (#34862)

The mux tracer fanned out every standard hook to its children but never
forwarded OnSystemCall{Start,End}. Tracers that rely on these - like
`logger.jsonLogger`, which uses the start hook to silence its opcode
hook for the duration of a system call - never got the signal when
wrapped behind a mux.

In evm t8n, combining `--trace` with `--opcode-count` (default for geth
with exec specs) produces exactly that wrapping. The first system call
(e.g. `ProcessBeaconBlockRoot`) then fires `OnOpcode` on the json logger
before any `OnTxStart` has run, dereferencing a nil env and crashing
t8n.

Forward both hooks through the mux. The V2 fan-out falls back to V1 for
children that only implement the legacy hook, mirroring the precedence
already used in `core/state_processor.go`.
This commit is contained in:
felipe 2026-05-01 16:38:33 +02:00 committed by GitHub
parent a15778c52f
commit b9c5fe6d26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -67,18 +67,20 @@ func NewMuxTracer(names []string, objects []*tracers.Tracer) (*tracers.Tracer, e
t := &muxTracer{names: names, tracers: objects}
return &tracers.Tracer{
Hooks: &tracing.Hooks{
OnTxStart: t.OnTxStart,
OnTxEnd: t.OnTxEnd,
OnEnter: t.OnEnter,
OnExit: t.OnExit,
OnOpcode: t.OnOpcode,
OnFault: t.OnFault,
OnGasChange: t.OnGasChange,
OnBalanceChange: t.OnBalanceChange,
OnNonceChange: t.OnNonceChange,
OnCodeChange: t.OnCodeChange,
OnStorageChange: t.OnStorageChange,
OnLog: t.OnLog,
OnTxStart: t.OnTxStart,
OnTxEnd: t.OnTxEnd,
OnEnter: t.OnEnter,
OnExit: t.OnExit,
OnOpcode: t.OnOpcode,
OnFault: t.OnFault,
OnGasChange: t.OnGasChange,
OnBalanceChange: t.OnBalanceChange,
OnNonceChange: t.OnNonceChange,
OnCodeChange: t.OnCodeChange,
OnStorageChange: t.OnStorageChange,
OnLog: t.OnLog,
OnSystemCallStartV2: t.OnSystemCallStart,
OnSystemCallEnd: t.OnSystemCallEnd,
},
GetResult: t.GetResult,
Stop: t.Stop,
@ -189,6 +191,24 @@ func (t *muxTracer) OnLog(log *types.Log) {
}
}
func (t *muxTracer) OnSystemCallStart(vm *tracing.VMContext) {
for _, t := range t.tracers {
if t.OnSystemCallStartV2 != nil {
t.OnSystemCallStartV2(vm)
} else if t.OnSystemCallStart != nil {
t.OnSystemCallStart()
}
}
}
func (t *muxTracer) OnSystemCallEnd() {
for _, t := range t.tracers {
if t.OnSystemCallEnd != nil {
t.OnSystemCallEnd()
}
}
}
// GetResult returns an empty json object.
func (t *muxTracer) GetResult() (json.RawMessage, error) {
resObject := make(map[string]json.RawMessage)