@@ -369,6 +369,9 @@ struct Peer {
369369 /* * Set of txids to reconsider once their parent transactions have been accepted **/
370370 std::set<uint256> m_orphan_work_set GUARDED_BY (g_cs_orphans);
371371
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+
372375 /* * Protects m_getdata_requests **/
373376 Mutex m_getdata_requests_mutex;
374377 /* * Work queue of items requested by this peer **/
@@ -681,6 +684,9 @@ class PeerManagerImpl final : public PeerManager
681684 /* * Number of nodes with fSyncStarted. */
682685 int nSyncStarted GUARDED_BY (cs_main) = 0;
683686
687+ /* * Hash of the last block we received via INV */
688+ uint256 m_last_block_inv_triggering_headers_sync{};
689+
684690 /* *
685691 * Sources of received blocks, saved to be able punish them when processing
686692 * happens afterwards.
@@ -3239,8 +3245,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
32393245 UpdateBlockAvailability (pfrom.GetId (), inv.hash );
32403246 if (!fAlreadyHave && !fImporting && !fReindex && !IsBlockRequested (inv.hash )) {
32413247 // 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
32443251 // provided should be the highest, so send a getheaders and
32453252 // then fetch the blocks we need to catch up.
32463253 best_block = &inv.hash ;
@@ -3265,10 +3272,30 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
32653272 }
32663273
32673274 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+ }
32723299 }
32733300 }
32743301
0 commit comments