In getLogsV3 (rpc/jsonrpc/eth_receipts.go:380, main at 52b071b) a nil header skips only the current txNum:
if blockNumChanged {
if header, err = api._blockReader.HeaderByNumber(ctx, tx, blockNum); err != nil {
return nil, err
}
if header == nil {
log.Warn("[rpc] header is nil", "blockNum", blockNum)
continue
}
}
The iterator reports blockNumChanged only for the first txNum of a block, so the remaining txNums of that block are processed with whatever header holds:
- If an earlier block in the range loaded a header, its hash and time are used: logs come back stamped with the previous block, and
TryGetCachedReceipt looks up receipts under the wrong block hash.
- If the nil header is the first one in the range,
header is still nil and header.Hash() panics; the call fails with "method handler crashed".
This looks reachable on a standalone rpcdaemon when a block is pruned or reorged away while the request runs. Found in the review of #23963.
Fix: when the header is nil, skip every txNum of that block (for example, remember the skipped block number and continue until it changes), or return an error.
In
getLogsV3(rpc/jsonrpc/eth_receipts.go:380,mainat 52b071b) a nil header skips only the current txNum:The iterator reports
blockNumChangedonly for the first txNum of a block, so the remaining txNums of that block are processed with whateverheaderholds:TryGetCachedReceiptlooks up receipts under the wrong block hash.headeris still nil andheader.Hash()panics; the call fails with "method handler crashed".This looks reachable on a standalone rpcdaemon when a block is pruned or reorged away while the request runs. Found in the review of #23963.
Fix: when the header is nil, skip every txNum of that block (for example, remember the skipped block number and continue until it changes), or return an error.