Skip to content

[r3.5] stagedsync: fix log index reset and missing notifications in parallel execution - #22155

Merged
AskAlexSharov merged 3 commits into
release/3.5from
cp/22110-to-3.5
Jul 6, 2026
Merged

AskAlexSharov merged 3 commits into
release/3.5from
cp/22110-to-3.5

Conversation

@sudeepdino008

@sudeepdino008 sudeepdino008 commented Jul 2, 2026 •

Copy link
Copy Markdown
Member

Cherry-pick of #22110 (merged squash commit a01ede3) to release/3.5.

@sudeepdino008

Copy link
Copy Markdown
Member Author

⚠️ Depends on #22110, which is not yet merged. This backport cherry-picks the 3 commits currently on #22110. Before merging this PR, check #22110 for any new/amended commits (e.g. review changes) and re-sync this branch so the two stay in lockstep.

@sudeepdino008
sudeepdino008 marked this pull request as draft July 2, 2026 13:47
@Sahil-4555

Copy link
Copy Markdown
Collaborator

@sudeepdino008 I have pushed few more commits on #22110 based on the review feedback. Can you please cherry-pick the latest changes into this branch as #22110 is merged in main.

… parallel execution (#22110)

### Issue

When Erigon is doing parallel block execution (`EXEC3_PARALLEL=true`),
the state snapshots can end at step boundaries which fall mid-block. So
when we restart the node or resume sync from these snapshots, the
execution stage needs to start/resume execution from the middle of the
block (running only the remaining transactions of that block).

While finalizing the transaction receipts for this partial block
execution, the code in `exec3_parallel.go` was checking `if
txVersion.TxIndex > 0 && tx > 0` to fetch the previous transaction's
receipt from the memory results map. But for the first transaction task
of this new batch (where the local slice task index `tx` is `0`, but the
actual block-level index `txVersion.TxIndex` is `> 0`), this check was
failing and `prevReceipt` remained `nil`. Because of this, it called
`CreateNextReceipt(nil)` and the starting log index and cumulative gas
for that mid-block transaction got reset to `0`. This wrong log index
got written directly to the database `ReceiptDomain` and caused
inconsistent `logIndex` values when clients queried `eth_getLogs`.

Additionally, for partial blocks the websocket notification path was
publishing tail-only receipts (only the resumed portion) via
`RecentReceipts.Add`, which `eth_subscribe` log/receipt clients would
receive as the complete block — diverging from `eth_getLogs` results.

### Fix

The main fix is in the parallel executor's receipt finalization loop in
`exec3_parallel.go`. We changed the `finalize` function signature to
accept `cumulativeGasUsed` and `firstLogIndex` directly instead of a
`prevReceipt` pointer, and it now calls `CreateReceipt` instead of
`CreateNextReceipt`. This matches how the serial executor handles
receipt creation. We also branch explicitly on `tx == 0` (batch
boundary) instead of checking `prevReceipt == nil`. When the first task
in a batch has `TxIndex > 0` (meaning we are resuming mid-block), we
query the temporal database using`rawtemporaldb.ReceiptAsOf` to fetch
the previous transaction's cumulative gas used, cumulative blob gas
used, and log index offset. We excluded `IsBlockEnd` tasks from this
fallback since `finalizeSystemTx` never consumes `prevReceipt` anyway.
Also added a two-step nil check on `be.finalizedResults[tx-1]` before
accessing `.Receipt` since `finalizedResults` is a map and a missing key
would return nil and cause a panic.

For the notification issue, we gated `RecentReceipts.Add` behind
`!applyResult.isPartial` and moved it outside the block validation scope
so that incomplete tail-only receipts are not published for partial
blocks. We now use `applyResult.Txs` and `applyResult.Header` directly
instead of fetching from the database. This is consistent with how the
serial path gates behind `startTxIndex == 0` in `exec3_serial.go:421`.

For the blob gas issue, we added a `cumulativeBlobGasUsed` field to
`execResult` and snapshot `be.blobGasUsed` into it at finalization time.
The publish loop now uses this per-result snapshot instead of reading
`be.blobGasUsed` directly, which could have been overwritten by a later
transaction. We also initialize `be.blobGasUsed` from the database
`cumBlobGasUsed` value at the resume boundary.

Added `TestParallelResumeBoundaryAndNotifications` unit test to pin
theresume boundary receipt reconstruction (first task with `TxIndex > 0`
at slice index 0 → correct offsets from DB) and the `isPartial` flag
that controls notification skipping.

Closes: #22106
(cherry picked from commit a01ede3)
@sudeepdino008
sudeepdino008 marked this pull request as ready for review July 6, 2026 08:12
@AskAlexSharov
AskAlexSharov enabled auto-merge (squash) July 6, 2026 08:48
@AskAlexSharov
AskAlexSharov merged commit 3d04bc5 into release/3.5 Jul 6, 2026
88 of 89 checks passed
@AskAlexSharov
AskAlexSharov deleted the cp/22110-to-3.5 branch July 6, 2026 09:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants