aboutsummaryrefslogtreecommitdiff
path: root/src/net_processing.cpp
diff options
context:
space:
mode:
authorAndrew Chow <achow101-github@achow101.com>2022-08-15 15:43:35 -0400
committerAndrew Chow <achow101-github@achow101.com>2022-08-15 15:43:41 -0400
commit22d96d76ab02fc73e7fe0d810bacee4c982df085 (patch)
treee6407655b32556d1247196d82d1900d2e235a1ba /src/net_processing.cpp
parent6d4889a694da12e03ef4d18bef2ff60d1d170f18 (diff)
parentf6a916683d75ed5489666dbfbd711f000ad0707f (diff)
downloadbitcoin-22d96d76ab02fc73e7fe0d810bacee4c982df085.tar.xz
Merge bitcoin/bitcoin#25720: p2p: Reduce bandwidth during initial headers sync when a block is found
f6a916683d75ed5489666dbfbd711f000ad0707f Add functional test for block announcements during initial headers sync (Suhas Daftuar) 05f7f31598b8bb06acb12e1e2a3ccf324b035ea8 Reduce bandwidth during initial headers sync when a block is found (Suhas Daftuar) Pull request description: On startup, if our headers chain is more than a day behind current time, we'll pick one peer to sync headers with until our best headers chain is caught up (at that point, we'll try to sync headers with all peers). However, if an INV for a block is received before our headers chain is caught up, we'll then start to sync headers from each peer announcing the block. This can result in doing a big headers sync with many (if not all) of our peers simultaneously, which wastes bandwidth. This PR would reduce that overhead by picking (at most) one new peer to try syncing headers with whenever a new block is announced, prior to our headers chain being caught up. ACKs for top commit: LarryRuane: ACK f6a916683d75ed5489666dbfbd711f000ad0707f ajtowns: ACK f6a916683d75ed5489666dbfbd711f000ad0707f mzumsande: ACK f6a916683d75ed5489666dbfbd711f000ad0707f dergoegge: Code review ACK f6a916683d75ed5489666dbfbd711f000ad0707f achow101: ACK f6a916683d75ed5489666dbfbd711f000ad0707f Tree-SHA512: 0662000bd68db146f55981de4adc2e2b07cbfda222b1176569d61c22055e5556752ffd648426f69687ed1cc203105515e7304c12b915d6270df8e41a4a0e1eaa
Diffstat (limited to 'src/net_processing.cpp')
-rw-r--r--src/net_processing.cpp39
1 files changed, 33 insertions, 6 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 64c2a29245..ed78ae5a81 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -370,6 +370,9 @@ struct Peer {
/** Set of txids to reconsider once their parent transactions have been accepted **/
std::set<uint256> m_orphan_work_set GUARDED_BY(g_cs_orphans);
+ /** Whether we've sent this peer a getheaders in response to an inv prior to initial-headers-sync completing */
+ bool m_inv_triggered_getheaders_before_sync{false};
+
/** Protects m_getdata_requests **/
Mutex m_getdata_requests_mutex;
/** Work queue of items requested by this peer **/
@@ -682,6 +685,9 @@ private:
/** Number of nodes with fSyncStarted. */
int nSyncStarted GUARDED_BY(cs_main) = 0;
+ /** Hash of the last block we received via INV */
+ uint256 m_last_block_inv_triggering_headers_sync{};
+
/**
* Sources of received blocks, saved to be able punish them when processing
* happens afterwards.
@@ -3240,8 +3246,9 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
UpdateBlockAvailability(pfrom.GetId(), inv.hash);
if (!fAlreadyHave && !fImporting && !fReindex && !IsBlockRequested(inv.hash)) {
// Headers-first is the primary method of announcement on
- // the network. If a node fell back to sending blocks by inv,
- // it's probably for a re-org. The final block hash
+ // the network. If a node fell back to sending blocks by
+ // inv, it may be for a re-org, or because we haven't
+ // completed initial headers sync. The final block hash
// provided should be the highest, so send a getheaders and
// then fetch the blocks we need to catch up.
best_block = &inv.hash;
@@ -3266,10 +3273,30 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
}
if (best_block != nullptr) {
- if (MaybeSendGetHeaders(pfrom, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *peer)) {
- LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n",
- m_chainman.m_best_header->nHeight, best_block->ToString(),
- pfrom.GetId());
+ // If we haven't started initial headers-sync with this peer, then
+ // consider sending a getheaders now. On initial startup, there's a
+ // reliability vs bandwidth tradeoff, where we are only trying to do
+ // initial headers sync with one peer at a time, with a long
+ // timeout (at which point, if the sync hasn't completed, we will
+ // disconnect the peer and then choose another). In the meantime,
+ // as new blocks are found, we are willing to add one new peer per
+ // block to sync with as well, to sync quicker in the case where
+ // our initial peer is unresponsive (but less bandwidth than we'd
+ // use if we turned on sync with all peers).
+ CNodeState& state{*Assert(State(pfrom.GetId()))};
+ if (state.fSyncStarted || (!peer->m_inv_triggered_getheaders_before_sync && *best_block != m_last_block_inv_triggering_headers_sync)) {
+ if (MaybeSendGetHeaders(pfrom, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *peer)) {
+ LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n",
+ m_chainman.m_best_header->nHeight, best_block->ToString(),
+ pfrom.GetId());
+ }
+ if (!state.fSyncStarted) {
+ peer->m_inv_triggered_getheaders_before_sync = true;
+ // Update the last block hash that triggered a new headers
+ // sync, so that we don't turn on headers sync with more
+ // than 1 new peer every new block.
+ m_last_block_inv_triggering_headers_sync = *best_block;
+ }
}
}