erigontech / erigontech/erigon

stagedsync: post-execution block validation (receipts root/bloom) is skipped for blocks resumed mid-block

Open
#22,237 1 comment 0 reactions 1 assignee Claimed by @yperbasis View on GitHub
QA
Dominant language
Go
Stars
3.6k
Forks
1.5k
Avg merge
1d 16h
Merged PRs (30d)
455

Description

### Context

When execution resumes mid-block (a state snapshot / commit boundary inside a block — the scenario of #22106 / #22110), both executors skip post-execution block validation for the resumed block:

- parallel: `blockValidator` (receipts root, bloom, gas used) is only spawned under `applyResult.BlockNum > 0 && !applyResult.isPartial` in `execImpl` (execution/stagedsync/exec3_parallel.go)
- serial: `validateBlockPostExecution` is gated on `startTxIndex == 0` (execution/stagedsync/exec3_serial.go)

So the one block that completes across a restart is never checked against `header.ReceiptHash` / `header.Bloom` / `header.GasUsed`. State correctness is still protected by the commitment root; this is specifically the receipts-side header validation for one block per resume.

### Why it can't just be enabled

The block-level accumulators feeding the validator are tail-scoped on resume:

- `be.blockRegularGasUsed` / `be.blockStateGasUsed` / `be.blockGasUsed` (parallel) and `se.blockGasUsed` / `se.blockStateGasUsed` (serial) only accumulate over the txs executed in the resumed batch, and the EIP-7778 / EIP-8037 regular/state gas split of the prefix is not recoverable from the receipt domain
- the parallel `ApplyCount` / `blockUpdateCount` cross-check is batch-scoped as well

### What already exists to build on

#22235 reconstructs the prefix receipts for resumed blocks (`receipts.DerivePriorReceipts`: RCacheV2 fast path, replay fallback) and marks such blocks `receiptsComplete`. With the full receipt set available:

- receipts-root and bloom validation are computable as-is
- the replay fallback already re-executes the prefix, so it could return the missing gas-split accumulators instead of discarding them
- pre-Amsterdam `header.GasUsed` could alternatively be checked from the last receipt's `CumulativeGasUsed`

### Suggested direction

Extend the resume reconstruction to also restore the block-level gas counters, then gate the validator on `receiptsComplete` instead of `!isPartial` (serial analogously), so a resumed block gets the same post-execution validation as any other. The `ApplyCount` cross-check likely stays batch-scoped.

Split out of the "deliberately not addressed" list of #22235.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.