From c68a8cb47c0bfcf5bfc8ab9a328c22bbceca5243 Mon Sep 17 00:00:00 2001 From: Sami Ahmed Date: Sun, 12 Jul 2026 04:02:28 -0700 Subject: [PATCH] fix(ibd): allow getblocks/getheaders on OneShot peers during IBD The version-handler fShouldAsk gate at main.cpp:4547 excluded OneShot peers (those added via -addnode= and the hardcoded onion/i2p seed list). On a fresh wallet, every peer arrives as fOneShot=1, so getblocks was never sent from the version handler. The wallet fell back to the control-loop getheaders planner, which walks the first ~2000-4000 headers from one peer and then stalls because no getblocks was issued to fan out the request across peers. Empirically verified against SAMI-PC debug.log (v6.1.7.0): - 715 getheaders requests, all stuck at 3 distinct locators (genesis, ~block 2000, ~block 4000) - 0 getblocks sent from version-handler (every shouldAsk=0 due to fOneShot=1) - 3-4 batches of 2000 headers received from one peer (6ygpphp2...onion) - Wallet stuck at 4000/2,221,278 blocks With this fix, the version handler issues getblocks to every fOneShot peer during IBD, allowing multi-peer concurrent sync from genesis. Verified on DNS2 with master binary against fresh datadir: - 11 shouldAsk=1 events (was 0) - 11 'sent getblocks+getheaders from height 0' events (was 0) - headers accepted: 3 batches (6000+) (was 0) --- src/main.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 4684307..c240154 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4544,7 +4544,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) bool fIBD = IsInitialBlockDownload(); // During IBD: ask every non-client peer unconditionally to maximise // download sources. Post-IBD: use traditional height-check logic. - bool fShouldAsk = !pfrom->fClient && !pfrom->fOneShot && + // During IBD we need to ask EVERY peer for blocks, including OneShot peers + // (those added via -addnode= and the hardcoded onion/i2p seed list). The previous + // `!pfrom->fOneShot` clause prevents getblocks/getheaders from being sent to these + // peers, which is exactly what fresh-from-genesis wallets need. Without this, a + // clean datadir syncs the first ~2000-4000 headers from one peer via the + // control-loop getheaders planner, then stalls because no version-handler + // getblocks was ever issued to fan out block requests. + bool fShouldAsk = !pfrom->fClient && (fIBD || pfrom->nStartingHeight > (nBestHeight - 144) || pfrom->nStartingHeight > nBestHeight) &&