Summary
On a node at the tip, debug_traceBlockByNumber("latest", …) panics at rpc/jsonrpc/tracing.go:239. The panic is recovered in rpc/service.go:229-232, so the client gets method handler crashed.
traceBlock resolves the block tag on the overlay view (tracing.go:60, api.filters) but replays the block on the committed view (ComputeBlockContext, _txNumReader and the temporal reads all use the plain tx). During the forkchoice flush+commit window it therefore traces block N's transactions against a state that still ends at N−1, execution diverges, and the gas assert fires.
Evidence
Run 30798564490, job parallel, erigon 1cbe6138df5. Five fixtures failed, all on block 25673291 and with every tracer type (default, prestateTracer ×2, callTracer, parity), so it is not tracer-specific:
[EROR] RPC method debug_traceBlockByNumber crashed:
assert: block.GasUsed() 12191709 != gasUsed 9239398. blockNum=25673291
[service.go:231 panic.go:783 tracing.go:239 tracing.go:46 …]
08:52:43.675 head updated number=25673291 <- overlay published, bgCommit=false
08:52:43.844 … 08:52:44.209 5 × crash on 25673291
08:52:45.286 Timings: Forkchoice flush+commit=2s <- commit lands ~1.6 s after the crashes
The window exists today, without FcuBackgroundCommit: head and notifications are published pre-commit, and flush+commit=2s is ~15% of a mainnet slot. The serial job of the same run saw zero crashes, the parallel one five.
Already fixed by #22533
#22533 changes exactly that line, moving debug_traceBlockBy* to the committed view:
- blockNumber, hash, _, err := rpchelper.GetCanonicalBlockNumber(ctx, blockNrOrHash, tx, api._blockReader, api.filters)
+ // nil filters: resolve on the committed view — the replay below reads
+ // temporal data through the same plain tx (see rpchelper.GetBlockNumber).
+ blockNumber, hash, _, err := rpchelper.GetCanonicalBlockNumber(ctx, blockNrOrHash, tx, api._blockReader, nil)
Summary
On a node at the tip,
debug_traceBlockByNumber("latest", …)panics atrpc/jsonrpc/tracing.go:239. The panic is recovered inrpc/service.go:229-232, so the client getsmethod handler crashed.traceBlockresolves the block tag on the overlay view (tracing.go:60,api.filters) but replays the block on the committed view (ComputeBlockContext,_txNumReaderand the temporal reads all use the plaintx). During the forkchoice flush+commit window it therefore traces block N's transactions against a state that still ends at N−1, execution diverges, and the gas assert fires.Evidence
Run 30798564490, job parallel, erigon
1cbe6138df5. Five fixtures failed, all on block 25673291 and with every tracer type (default,prestateTracer×2,callTracer, parity), so it is not tracer-specific:The window exists today, without
FcuBackgroundCommit: head and notifications are published pre-commit, andflush+commit=2sis ~15% of a mainnet slot. The serial job of the same run saw zero crashes, the parallel one five.Already fixed by #22533
#22533 changes exactly that line, moving
debug_traceBlockBy*to the committed view: