cl: enforce Fulu data availability across block imports - #23292
Draft
yperbasis wants to merge 15 commits into
Draft
cl: enforce Fulu data availability across block imports#23292yperbasis wants to merge 15 commits into
yperbasis wants to merge 15 commits into
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Prevents Fulu blocks with unavailable PeerDAS columns from entering fork choice.
Changes:
- Return the data-unavailable error after scheduling deferred recovery.
- Initialize spectests with the anchor head to exercise synced behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
cl/phase1/forkchoice/on_block.go |
Rejects blocks until column data is available. |
cl/spectest/consensus_tests/fork_choice.go |
Initializes synced data from the anchor block and state. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Suppressed comments (2)
cl/phase1/stages/chain_tip_sync.go:271
ErrEIP7594ColumnDataNotAvailableis transient, but this error path marks its root as seen on the following line. Every later range response then skips that block even after PeerDAS obtains the columns, and its descendants remain blocked for the rest of this chain-tip invocation. Leave unavailable roots retryable while continuing to suppress retries for non-transient processing errors.
if err := processBlock(ctx, cfg, cfg.indiciesDB, block, true, true, true); err != nil {
log.Debug("failed to process chain-tip block", "err", err, "blockSlot", block.Block.Slot)
cl/phase1/network/services/block_service.go:344
- A newly scheduled job has a zero
retryAfter, so this guard allows the first queued data-availability retry on the next 50 ms ticker tick. That means the initial attempt and first retry are not separated bydataAvailabilityRetryInterval, contrary to the one-second retry policy. Initialize the retry deadline when scheduling specifically afterErrEIP7594ColumnDataNotAvailable, while preserving immediate processing for jobs queued for other reasons.
if now.Before(blockJob.retryAfter) {
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.
Suppressed comments (1)
cl/phase1/network/services/block_service.go:345
- Newly scheduled jobs leave
retryAfterat its zero value, so this check permits the first queued retry on the next 50 ms block-service tick. The four queued retries therefore are not all spaced one second apart as intended: only retries after the first queued attempt are delayed. Initialize the DA job's first retry deadline from its scheduling time.
if now.Before(blockJob.retryAfter) {
return true
yperbasis
marked this pull request as draft
August 17, 2026 12:25
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A recent Fulu block with blob commitments could enter fork choice while its required PeerDAS columns were unavailable. A Caplin validator could then attest to or build on a head whose data it could neither sample nor serve.
Summary
OnBlockinvariant for Fulu blocks inside the protocol's data-column request window, regardless of the callerDesign
For a Fulu block with blob commitments,
OnBlockderives the availability requirement from the store slot and the epoch-basedMIN_EPOCHS_FOR_DATA_COLUMN_SIDECARS_REQUESTSwindow. A caller cannot disable this check for a block whose columns the network is still required to serve. Blocks older than that window remain importable during historical sync because peers are no longer required to retain their columns.ForwardSync and ChainTipSync acquire columns before entering the locked fork-choice path. A normal node downloads its custody columns; an archive node downloads enough columns to recover the blobs. Both paths derive the fork from the block slot, recheck
peerDas.IsDataAvailable, and import only after availability succeeds. Chain-tip availability failures remain retryable and do not enter the round's permanent seen set.Locally produced Fulu blocks store all configured data columns before
OnBlock, so the same invariant also applies to self-produced blocks.EL blob responses are not sufficient evidence for Fulu because the returned blobs and cell proofs are not converted into stored columns. The Deneb and Electra shortcut requires one complete 131072-byte blob and one 48-byte proof for every commitment. Safe Fulu EL materialization is tracked in erigontech/security#80.
Resource bounds
Testing
make erigon integrationFixes erigontech/security#79.