@@ -369,6 +369,9 @@ struct Peer {
369
369
/* * Set of txids to reconsider once their parent transactions have been accepted **/
370
370
std::set<uint256> m_orphan_work_set GUARDED_BY (g_cs_orphans);
371
371
372
+ /* * Whether we've sent this peer a getheaders in response to an inv prior to initial-headers-sync completing */
373
+ bool m_inv_triggered_getheaders_before_sync{false };
374
+
372
375
/* * Protects m_getdata_requests **/
373
376
Mutex m_getdata_requests_mutex;
374
377
/* * Work queue of items requested by this peer **/
@@ -681,6 +684,9 @@ class PeerManagerImpl final : public PeerManager
681
684
/* * Number of nodes with fSyncStarted. */
682
685
int nSyncStarted GUARDED_BY (cs_main) = 0;
683
686
687
+ /* * Hash of the last block we received via INV */
688
+ uint256 m_last_block_inv_triggering_headers_sync{};
689
+
684
690
/* *
685
691
* Sources of received blocks, saved to be able punish them when processing
686
692
* happens afterwards.
@@ -3239,8 +3245,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3239
3245
UpdateBlockAvailability (pfrom.GetId (), inv.hash );
3240
3246
if (!fAlreadyHave && !fImporting && !fReindex && !IsBlockRequested (inv.hash )) {
3241
3247
// Headers-first is the primary method of announcement on
3242
- // the network. If a node fell back to sending blocks by inv,
3243
- // it's probably for a re-org. The final block hash
3248
+ // the network. If a node fell back to sending blocks by
3249
+ // inv, it may be for a re-org, or because we haven't
3250
+ // completed initial headers sync. The final block hash
3244
3251
// provided should be the highest, so send a getheaders and
3245
3252
// then fetch the blocks we need to catch up.
3246
3253
best_block = &inv.hash ;
@@ -3265,10 +3272,30 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3265
3272
}
3266
3273
3267
3274
if (best_block != nullptr ) {
3268
- if (MaybeSendGetHeaders (pfrom, m_chainman.ActiveChain ().GetLocator (m_chainman.m_best_header ), *peer)) {
3269
- LogPrint (BCLog::NET, " getheaders (%d) %s to peer=%d\n " ,
3270
- m_chainman.m_best_header ->nHeight , best_block->ToString (),
3271
- pfrom.GetId ());
3275
+ // If we haven't started initial headers-sync with this peer, then
3276
+ // consider sending a getheaders now. On initial startup, there's a
3277
+ // reliability vs bandwidth tradeoff, where we are only trying to do
3278
+ // initial headers sync with one peer at a time, with a long
3279
+ // timeout (at which point, if the sync hasn't completed, we will
3280
+ // disconnect the peer and then choose another). In the meantime,
3281
+ // as new blocks are found, we are willing to add one new peer per
3282
+ // block to sync with as well, to sync quicker in the case where
3283
+ // our initial peer is unresponsive (but less bandwidth than we'd
3284
+ // use if we turned on sync with all peers).
3285
+ CNodeState& state{*Assert (State (pfrom.GetId ()))};
3286
+ if (state.fSyncStarted || (!peer->m_inv_triggered_getheaders_before_sync && *best_block != m_last_block_inv_triggering_headers_sync)) {
3287
+ if (MaybeSendGetHeaders (pfrom, m_chainman.ActiveChain ().GetLocator (m_chainman.m_best_header ), *peer)) {
3288
+ LogPrint (BCLog::NET, " getheaders (%d) %s to peer=%d\n " ,
3289
+ m_chainman.m_best_header ->nHeight , best_block->ToString (),
3290
+ pfrom.GetId ());
3291
+ }
3292
+ if (!state.fSyncStarted ) {
3293
+ peer->m_inv_triggered_getheaders_before_sync = true ;
3294
+ // Update the last block hash that triggered a new headers
3295
+ // sync, so that we don't turn on headers sync with more
3296
+ // than 1 new peer every new block.
3297
+ m_last_block_inv_triggering_headers_sync = *best_block;
3298
+ }
3272
3299
}
3273
3300
}
3274
3301
0 commit comments