Skip to content

peer: Sync blocks from multiple peers in parallel - #31

Open
pzafonte wants to merge 1 commit into
kernel-node:masterfrom
pzafonte:multi-peer-ibd-v3
Open

peer: Sync blocks from multiple peers in parallel#31
pzafonte wants to merge 1 commit into
kernel-node:masterfrom
pzafonte:multi-peer-ibd-v3

Conversation

@pzafonte

@pzafonte pzafonte commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

This is the foundation for multi-peer IBD in kernel-node. Refinements can, will, and should follow as separate changes.

Initial block download fetches blocks from a single peer, so the sync runs at that peer's pace and stalls when it is slow or unresponsive.

Connect to several peers at once, four by default, and split the block download between them. A shared queue hands out batches of hashes and an in-flight set keeps two peers from requesting the same block. When a peer disconnects, the blocks it still owed return to the queue.

Peers reply out of order, but the kernel connects blocks in chain order. Arriving blocks are buffered by parent hash and released as an unbroken run once their parent has been handed off. Without this the sync stops the moment one peer holds a block whose parent another peer has not yet delivered.

This PR is following Bitcoin Core's behavior in the following ways:

This PR Bitcoin Core Behavior
DOWNLOAD_BATCH_SIZE = 16 MAX_BLOCKS_IN_TRANSIT_PER_PEER Cap on how many blocks one peer is asked for at a time thus bounding the work lost if it drops
DownloadState::in_flight mapBlocksInFlight Each block is requested from exactly one peer so parallel peers never duplicate a download
requeue_unreceived FinalizeNode A departing peer's outstanding blocks become fetch-able again rather than being stranded

It diverges from Core when it comes to block ordering. Core writes blocks as they arrive and lets chain activation order them, bounded by BLOCK_DOWNLOAD_WINDOW. The kernel needs blocks handed over in chain order, so I am doing buffer_and_drain.

Also of note, recently, shutdown and stale-block detection previously closed the single peer's connection to unblock its read (#90). With several connections there is no one connection to close, so the peer manager signals every thread and exposes the per-peer writers that both paths now use.

Possibly Useful Additions to The Kernel:
btck_ValidationInterfaceActiveTipChange - Tells us when the tip moves allowing the node to follow the kernel instead of keeping a copy.
btck_chainstate_manager_is_initial_block_download - Maybe this would be better than using SynchronizationState, which saves the value from a notification, to tell us whether the node is still catching up?
btck_ValidationInterfaceUpdatedBlockTip - It carries the fork point, but not sure if it's useful beyond that.

@rustaceanrob

Copy link
Copy Markdown
Contributor

Converting to draft because this depends on 65bf637

@rustaceanrob
rustaceanrob marked this pull request as draft March 5, 2026 14:25
@pzafonte
pzafonte force-pushed the multi-peer-ibd-v3 branch from 5e51121 to ca0c06b Compare March 26, 2026 14:51
@pzafonte pzafonte changed the title feat: add shared download queue and per-peer local tip tracking peer: Add shared download queue and per-peer local tip for IBD Mar 26, 2026
@pzafonte
pzafonte marked this pull request as ready for review March 26, 2026 15:43
@pzafonte
pzafonte marked this pull request as draft July 1, 2026 16:24
@pzafonte
pzafonte force-pushed the multi-peer-ibd-v3 branch from ca0c06b to d85b6f7 Compare August 4, 2026 20:01
@pzafonte pzafonte changed the title peer: Add shared download queue and per-peer local tip for IBD peer: Sync blocks from multiple peers in parallel Aug 4, 2026
@pzafonte
pzafonte force-pushed the multi-peer-ibd-v3 branch from d85b6f7 to d646771 Compare August 5, 2026 13:48
Syncing from one peer is only as fast as that peer. Connect to several
at once and share the work of downloading blocks between them, so a slow
or unresponsive peer no longer holds up the whole sync.

A shared queue and an in-flight set coordinate the peers: each block is
fetched by exactly one peer, and any block left behind when a peer drops
returns to the queue for another to fetch, so none is stranded.

Peers fetch blocks out of order, but the kernel must connect them in
chain order. A shared buffer holds each arriving block until its parent
has been handed off, then releases the unbroken run that now extends the
tip. Without it the sync stalls the moment one peer holds a block whose
parent another peer has not yet delivered.
@pzafonte
pzafonte marked this pull request as ready for review August 12, 2026 17:24
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.

2 participants