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)
This commit is contained in:
Sami Ahmed
2026-07-12 04:02:28 -07:00
parent 540c889fa1
commit c68a8cb47c
+8 -1
View File
@@ -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) &&