Skip to content

exec: partial block at snapshot boundary passes incomplete receipts to Finalize #20452

@mh0lt

Description

@mh0lt

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions