Summary
When resuming execution from a snapshot boundary with initialBlockTxOffset > 0 (partial block), the receipts passed to engine.Finalize() only contain receipts from the re-executed portion (txs startTxIndex to end), not the full block. This causes the Pectra requests hash validation to fail because deposit request extraction needs ALL receipt logs.
Impact
- Prevents starting execution from any snapshot boundary that falls mid-block after Pectra activation
- Affects both serial (
exec3_serial.go:436) and parallel (exec3_parallel.go:2389) executors
- The serial executor skips post-validation for partial blocks (
startTxIndex > 0) but still runs Finalize which can return an error
Root Cause
Receipt building accumulates receipts only from the re-executed portion:
- Serial:
blockReceipts starts from startTxIndex (exec3_serial.go:489)
- Parallel:
receipts built from be.results which only has re-executed txs (exec3_parallel.go:2310)
The prior receipts (txs 0 to startTxIndex-1) exist in the RCache domain history but are not loaded.
Proposed Fix
For partial blocks, load prior receipts from rawdb.ReadReceiptsCacheV2 (or reconstruct from rawtemporaldb.ReceiptAsOf) for txNums before the re-execution start, and prepend them to the receipts list before calling Finalize.
Workaround
Pass skipReceiptsEval=true to Finalize for partial blocks. The syscall state writes still execute; only the requests hash validation is skipped. The commitment trie root check catches any state inconsistency.
🤖 Generated with Claude Code
Summary
When resuming execution from a snapshot boundary with
initialBlockTxOffset > 0(partial block), the receipts passed toengine.Finalize()only contain receipts from the re-executed portion (txsstartTxIndexto end), not the full block. This causes the Pectra requests hash validation to fail because deposit request extraction needs ALL receipt logs.Impact
exec3_serial.go:436) and parallel (exec3_parallel.go:2389) executorsstartTxIndex > 0) but still runs Finalize which can return an errorRoot Cause
Receipt building accumulates receipts only from the re-executed portion:
blockReceiptsstarts fromstartTxIndex(exec3_serial.go:489)receiptsbuilt frombe.resultswhich only has re-executed txs (exec3_parallel.go:2310)The prior receipts (txs 0 to startTxIndex-1) exist in the RCache domain history but are not loaded.
Proposed Fix
For partial blocks, load prior receipts from
rawdb.ReadReceiptsCacheV2(or reconstruct fromrawtemporaldb.ReceiptAsOf) for txNums before the re-execution start, and prepend them to the receipts list before calling Finalize.Workaround
Pass
skipReceiptsEval=trueto Finalize for partial blocks. The syscall state writes still execute; only the requests hash validation is skipped. The commitment trie root check catches any state inconsistency.🤖 Generated with Claude Code