ChainSafe / ChainSafe/lodestar

range sync still imports the orphaned payload envelope of the last block in a batch

Open
#10,008 2 comments 0 reactions 0 assignees View on GitHub
spec-gloas
Dominant language
TypeScript
Stars
1.4k
Forks
483
Avg merge
1d 16h
Merged PRs (30d)
150

Description

### Describe the bug

follow-up to #10005 / #10006. range sync classifies a payload as orphaned only when the child is visible: `assertLinearChainSegment()` sees the child for every block of a batch except the last one, and the parent case covers a known first block whose envelope is in the batch map (#10002). the envelope of the last block in a batch (or of a count=1 target batch) has no child in the segment yet, so it is still DA-verified and imported.

if the first block of the next batch turns out to build on that block's EMPTY variant, the FULL variant is a childless leaf. while block attestations are not imported (finalized sync chain, or blocks older than `FORK_CHOICE_ATT_EPOCH_LIMIT`) both variants have weight 0, same root, and `getPayloadStatusTiebreaker` picks FULL for any block older than the previous slot, so the head parks on the leaf, same mechanism as the incident fixed by #10005. it only frees itself once a block with a newer justification is imported and the leaf fails `nodeIsViableForHead`, ~2 epochs in a finalizing chain, indefinitely during non-finality.

### Conditions

all three at once:

- the last block of a batch has an orphaned payload (glamsterdam-devnet-9 through the non-finality stretch: 34 orphaned envelopes skipped over ~8250 slots on lodestar-erigon-1, ~0.4% of slots, 1/32 of those land on a batch end)
- the serving peer includes orphaned envelopes in by-range responses (lodestar and nimbus do, lighthouse and prysm omit them)
- the chain is not finalizing, otherwise it self-heals in ~2 epochs

not critical: with #10005 + #10006 all 30 devnet-9 lodestar nodes synced to head and lodestar-erigon-1 crossed the whole non-finality stretch (258 batches) without parking once.

### Options

- **defer the last envelope of a batch** while attestations are not imported and let the next batch classify it, as #10002 already does for a parent envelope in the map. needs `verifyBlocksSanityChecks()` and `assertLinearChainSegment()` to fall back to `seenPayloadEnvelopeInputCache` when the parent envelope is not in the batch map, and `processBlocks()` to import that cached parent envelope when the first block builds on it or prune it when it does not. this also subsumes the known-block case of #10006. interactions to verify: a sync chain that ends at the deferred block (the next chain re-downloads the epoch and takes the normal path), a gossip child at the tip needing the deferred payload (unknown-parent sync finds the complete cache entry), DA for the cached columns
- **fork choice tiebreak** preferring the variant with descendants at a zero-weight tie would be a one-liner but deviates from spec `get_head`, which orders by `(weight, root, payload_status)` and makes the childless FULL leaf the head in exactly this tie. spec fork choice vectors can encode it, not an option
- **stop serving orphaned envelopes by range** like lighthouse/prysm would shrink the exposure to nimbus peers. with #10005 a range-synced lodestar node no longer holds orphaned envelopes anyway, only nodes that imported them live at the tip do

Contributor guide

Open the contributing guide

Research direction

Review verifyBlocksSanityChecks(), assertLinearChainSegment(), and processBlocks(), along with the related issues #10002, #10005, and #10006. Compare the proposed deferred-envelope path with the stated fork-choice and serving alternatives, then verify the listed sync, gossip, and data-availability interactions. Done means the last envelope of a batch is no longer incorrectly imported and the described non-finality case no longer parks the head.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
blockchain, distributed-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.