@@ -370,6 +370,9 @@ struct Peer {
370
370
/* * Set of txids to reconsider once their parent transactions have been accepted **/
371
371
std::set<uint256> m_orphan_work_set GUARDED_BY (g_cs_orphans);
372
372
373
+ /* * Whether we've sent this peer a getheaders in response to an inv prior to initial-headers-sync completing */
374
+ bool m_inv_triggered_getheaders_before_sync{false };
375
+
373
376
/* * Protects m_getdata_requests **/
374
377
Mutex m_getdata_requests_mutex;
375
378
/* * Work queue of items requested by this peer **/
@@ -664,6 +667,9 @@ class PeerManagerImpl final : public PeerManager
664
667
/* * Number of nodes with fSyncStarted. */
665
668
int nSyncStarted GUARDED_BY (cs_main) = 0;
666
669
670
+ /* * Hash of the last block we received via INV */
671
+ uint256 m_last_block_inv_triggering_headers_sync{};
672
+
667
673
/* *
668
674
* Sources of received blocks, saved to be able punish them when processing
669
675
* happens afterwards.
@@ -3939,8 +3945,9 @@ void PeerManagerImpl::ProcessMessage(
3939
3945
UpdateBlockAvailability (pfrom.GetId (), inv.hash );
3940
3946
if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count (inv.hash )) {
3941
3947
// Headers-first is the primary method of announcement on
3942
- // the network. If a node fell back to sending blocks by inv,
3943
- // it's probably for a re-org. The final block hash
3948
+ // the network. If a node fell back to sending blocks by
3949
+ // inv, it may be for a re-org, or because we haven't
3950
+ // completed initial headers sync. The final block hash
3944
3951
// provided should be the highest, so send a getheaders and
3945
3952
// then fetch the blocks we need to catch up.
3946
3953
best_block = &inv.hash ;
@@ -3979,11 +3986,31 @@ void PeerManagerImpl::ProcessMessage(
3979
3986
}
3980
3987
}
3981
3988
if (best_block != nullptr ) {
3982
- std::string msg_type = UsesCompressedHeaders (*peer) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS;
3983
- if (MaybeSendGetHeaders (pfrom, msg_type, m_chainman.ActiveChain ().GetLocator (m_chainman.m_best_header ), *peer)) {
3984
- LogPrint (BCLog::NET, " %s (%d) %s to peer=%d\n " ,
3985
- msg_type, m_chainman.m_best_header ->nHeight , best_block->ToString (),
3986
- pfrom.GetId ());
3989
+ // If we haven't started initial headers-sync with this peer, then
3990
+ // consider sending a getheaders now. On initial startup, there's a
3991
+ // reliability vs bandwidth tradeoff, where we are only trying to do
3992
+ // initial headers sync with one peer at a time, with a long
3993
+ // timeout (at which point, if the sync hasn't completed, we will
3994
+ // disconnect the peer and then choose another). In the meantime,
3995
+ // as new blocks are found, we are willing to add one new peer per
3996
+ // block to sync with as well, to sync quicker in the case where
3997
+ // our initial peer is unresponsive (but less bandwidth than we'd
3998
+ // use if we turned on sync with all peers).
3999
+ CNodeState& state{*Assert (State (pfrom.GetId ()))};
4000
+ if (state.fSyncStarted || (!peer->m_inv_triggered_getheaders_before_sync && *best_block != m_last_block_inv_triggering_headers_sync)) {
4001
+ std::string msg_type = UsesCompressedHeaders (*peer) ? NetMsgType::GETHEADERS2 : NetMsgType::GETHEADERS;
4002
+ if (MaybeSendGetHeaders (pfrom, msg_type, m_chainman.ActiveChain ().GetLocator (m_chainman.m_best_header ), *peer)) {
4003
+ LogPrint (BCLog::NET, " %s (%d) %s to peer=%d\n " ,
4004
+ msg_type, m_chainman.m_best_header ->nHeight , best_block->ToString (),
4005
+ pfrom.GetId ());
4006
+ }
4007
+ if (!state.fSyncStarted ) {
4008
+ peer->m_inv_triggered_getheaders_before_sync = true ;
4009
+ // Update the last block hash that triggered a new headers
4010
+ // sync, so that we don't turn on headers sync with more
4011
+ // than 1 new peer every new block.
4012
+ m_last_block_inv_triggering_headers_sync = *best_block;
4013
+ }
3987
4014
}
3988
4015
}
3989
4016
0 commit comments