Skip to content

feat(syncer): implement head sync in range syncer for beacon client (#1550) - #1577

Draft
alok-108 wants to merge 1 commit into
ReamLabs:masterfrom
alok-108:feat/range-syncer-head-sync
Draft

alok-108 wants to merge 1 commit into
ReamLabs:masterfrom
alok-108:feat/range-syncer-head-sync

Conversation

@alok-108

Copy link
Copy Markdown

Resolves #1550

Overview

Extends BlockRangeSyncer beyond the finalized_slot up to the network's canonical head_slot, ensuring that restarted or lagging nodes sync unfinalized blocks seamlessly before switching to live gossip propagation.

Changes

  1. Canonical Peer Grouping & Head Resolution:
    • Peers are clustered by (finalized_root, finalized_epoch) rather than just scalar slots, preventing splits across competing forks.
    • Computes canonical_checkpoint, finalized_slot, and head_slot from canonical peers.
  2. Two-Stage Sync Target:
    • sync_target_slot(local_slot) targets finalized_slot during Phase 1 (FinalizedSync) and transitions to head_slot in Phase 2 (HeadSync).
  3. Slot-Aware Peer Selection:
    • Added fetch_idle_peer_for_slot(min_slot) to avoid requesting block ranges from lagging peers whose advertised head slot is lower than the requested range start.
  4. Temporary Ban Expiration:
    • Implemented 5-minute ban duration (BAN_DURATION) with automatic unbanning during periodic peer set updates.
  5. Pre-Fulu Blob Sidecar Availability Fallback:
    • Added fallback in Store::is_data_available for pre-Fulu blocks to retrieve and verify blobs from blobs_and_proofs_provider.
  6. Unit Tests:
    • Added unit test suites for canonical checkpoint resolution, slot-aware peer scheduling, and ban expiration.

Verification

  • cargo test -p ream-syncer --features devnet5 (5/5 tests passed)
  • cargo clippy -p ream-syncer -p ream-network-manager --features devnet5 --no-deps -- --deny warnings (0 warnings)
  • cargo check -p ream-network-manager --features devnet5 (0 errors)

…fallback (ReamLabs#1550)

- Extend range syncer beyond finalized slot to network canonical head slot
- Group peers by canonical (finalized_root, finalized_epoch) and resolve majority head slot
- Add fetch_idle_peer_for_slot for slot-aware peer download scheduling
- Implement 5-minute ban cooldown to unban temporary failed peers
- Restore pre-Fulu blob sidecar availability check in store.is_data_available
@perfogic

perfogic commented Sep 12, 2026 •

Copy link
Copy Markdown
Collaborator

Thanks for working on this. @vuonghuuhung is already working on the same issue in ream-collective/ream#19 as part of our EPF Cohort 7 project and plans to open a PR here soon.

On the PR as well, there’s still a problem with head sync here. sync_target_slot switches between finalized and head targets, but we’re still fetching ranges from any eligible peer without checking which unfinalized chain they’re serving.

Two peers can agree on the finalized checkpoint but have different heads. Since the completion check only looks at the slot, we could end up on a non-canonical branch and still report “synced.”

So just changing the target from finalized to head isn’t enough, we also need to handle those competing branches. We’ve discussed this before, and Hans is already working on it.

@shariqnaiyer, I tagged you to help coordinate the overlap with our EPF work.

@KolbyML

KolbyML commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Thanks for working on this. @vuonghuuhung is already working on the same issue in ream-collective/ream#19 as part of our EPF Cohort 7 project and plans to open a PR here soon.

On the PR as well, there’s still a problem with head sync here. sync_target_slot switches between finalized and head targets, but we’re still fetching ranges from any eligible peer without checking which unfinalized chain they’re serving.

Two peers can agree on the finalized checkpoint but have different heads. Since the completion check only looks at the slot, we could end up on a non-canonical branch and still report “synced.”

So just changing the target from finalized to head isn’t enough, we also need to handle those competing branches. We’ve discussed this before, and Hans is already working on it.

@shariqnaiyer, I tagged you to help coordinate the overlap with our EPF work.

@perfogic so you guys are going to make a PR for this?

@vuonghuuhung

Copy link
Copy Markdown
Contributor

Thanks for working on this. @vuonghuuhung is already working on the same issue in ream-collective/ream#19 as part of our EPF Cohort 7 project and plans to open a PR here soon.

On the PR as well, there’s still a problem with head sync here. sync_target_slot switches between finalized and head targets, but we’re still fetching ranges from any eligible peer without checking which unfinalized chain they’re serving.

Two peers can agree on the finalized checkpoint but have different heads. Since the completion check only looks at the slot, we could end up on a non-canonical branch and still report “synced.”

So just changing the target from finalized to head isn’t enough, we also need to handle those competing branches. We’ve discussed this before, and Hans is already working on it.

@shariqnaiyer, I tagged you to help coordinate the overlap with our EPF work.

@perfogic so you guys are going to make a PR for this?

Yes, I'm working on this topic and the PR will be open on Ream soon. I opened ream-collective/ream#19 for this. I'm testing and in the last steps as well

@alok-108

Copy link
Copy Markdown
Author

Thanks for working on this. @vuonghuuhung is already working on the same issue in ream-collective/ream#19 as part of our EPF Cohort 7 project and plans to open a PR here soon.
On the PR as well, there’s still a problem with head sync here. sync_target_slot switches between finalized and head targets, but we’re still fetching ranges from any eligible peer without checking which unfinalized chain they’re serving.
Two peers can agree on the finalized checkpoint but have different heads. Since the completion check only looks at the slot, we could end up on a non-canonical branch and still report “synced.”
So just changing the target from finalized to head isn’t enough, we also need to handle those competing branches. We’ve discussed this before, and Hans is already working on it.
@shariqnaiyer, I tagged you to help coordinate the overlap with our EPF work.

@perfogic so you guys are going to make a PR for this?

Thanks for the review. I understand the concern about competing unfinalized branches — just switching the target from finalized to head isn’t enough if we’re still fetching from any eligible peer without checking which unfinalized chain they’re serving.

@vuonghuuhung — I saw your PR ream-collective#19 and the review discussion with @perfogic. I don’t want to duplicate work, happy to collaborate instead. I can help with one or both of the open items:

  1. NoQuorum transition:
    Make sure the Finalized → Head switch doesn’t happen prematurely when the finalized target hasn’t settled. I can add a settled/quorum guard and retry/backoff so it falls back to finalized sync instead of getting stuck in Head NoQuorum.

  2. Integration test for head-fork recovery:
    Simulate a node syncing branch A while the network favors branch B, without gossip. Verify that missing parents are fetched and the head switches when votes favor B.

I can either open a PR against your branch or push a branch based on yours — which do you prefer?

In the meantime, on my side, I’ll update this PR to:

  • track the canonical head root,
  • validate that fetched ranges descend from the finalized checkpoint,
  • change the completion check to compare head roots rather than just slots,
  • add tests for forked heads agreeing on the finalized checkpoint.

Should I close #1577 or keep it as reference? Happy to coordinate with @perfogic and @shariqnaiyer as well.

@alok-108
alok-108 marked this pull request as draft September 24, 2026 11:57

This branch has not been deployed

No deployments
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.

Implement head sync in the range syncer for Beacon client

4 participants