Skip to content

fix: fetch unknown blocks referenced by attestations#112

Draft
MegaRedHand wants to merge 4 commits intomainfrom
fetch-unknown-attestation-blocks
Draft

fix: fetch unknown blocks referenced by attestations#112
MegaRedHand wants to merge 4 commits intomainfrom
fetch-unknown-attestation-blocks

Conversation

@MegaRedHand
Copy link
Collaborator

@MegaRedHand MegaRedHand commented Feb 10, 2026

Motivation

Closes #91

Currently, attestations that reference blocks we don't have are rejected outright. This causes attestation loss during normal operation — when blocks arrive slightly out of order or when a node is catching up, valid attestations get discarded simply because the referenced block hasn't been processed yet.

This is particularly impactful during sync: a node receiving attestations before their referenced blocks loses fork choice weight that could help it converge to the correct head faster.

Description

Replace the "reject unknown" behavior with a pending attestation queue. When an attestation references a block we don't have (target or head), buffer it and retry processing after the missing block arrives.

How it works

Queuing:

  • On gossip attestation, check if target/head blocks are known
  • If source is unknown, reject immediately (source is the trust anchor, not recoverable)
  • If target/head is unknown, pre-validate (slot sanity, validator ID, finalization check) and queue
  • Request missing blocks from the network

Processing:

  • When a block is successfully imported, check if any pending attestations were waiting for it
  • If all referenced blocks are now available, process through the full on_gossip_attestation flow (including signature verification)
  • If still waiting on other blocks, keep pending

Cleanup (three paths):

  • TTL-based: expired attestations cleaned up at tick interval 2 (every 4 seconds)
  • Finalization-based: attestations whose target is now finalized are removed after finalization advances
  • Eviction: oldest attestation evicted when global cap is reached

DoS protection

Limit Value Rationale
Per-block cap 32 attestations Limits amplification per unknown block
Global cap 512 attestations Bounds total memory usage
TTL 4 slots (16 seconds) Attestations older than this are stale

Pre-validation filters garbage before queuing: slot range check, known source, non-finalized target, valid validator ID.

Integration with block processing

Pending attestations are processed inside process_or_pend_block, after collect_pending_children. The pending attestation system is fully independent of the pending block system — it only touches self.pending_attestations and self.store, not the block processing queue.

How to test

make lint   # No warnings
make test   # All unit + forkchoice spec tests pass

The feature exercises a code path that requires out-of-order block/attestation arrival, which the current spec test fixtures don't cover. Full validation requires a multi-client devnet where attestations routinely arrive before their referenced blocks.

MegaRedHand and others added 4 commits February 3, 2026 16:41
Resolve conflict: adapt contains_block → get_block_header after
storage header/body split refactor.
Conflicts resolved:
- crates/blockchain/src/lib.rs: kept main's iterative queue-based block
  processing (VecDeque + process_or_pend_block + collect_pending_children)
  and integrated PR's pending attestation system on top. pending_blocks
  uses main's HashMap<H256, HashSet<H256>> type (block data in DB).
  process_pending_attestations called after collect_pending_children in
  process_or_pend_block.
- docs/checkpoint_sync.md: kept main's reviewed version.
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.

Fetch unknown blocks referenced by attestations

2 participants

Comments