From 0569b5c4bbf8f725e3969d76f7cb081cdf1e4195 Mon Sep 17 00:00:00 2001 From: Suhas Daftuar Date: Wed, 26 Jan 2022 15:40:09 -0500 Subject: Sync chain more readily from inbound peers during IBD When in IBD, if the honest chain is only known by inbound peers, then we must eventually sync from them in order to learn it. This change allows us to perform initial headers sync and fetch blocks from inbound peers, if we have no blocks in flight. The restriction on having no blocks in flight means that we will naturally throttle our block downloads to any such inbound peers that we may be downloading from, until we leave IBD. This is a tradeoff between preferring outbound peers for most of our block download, versus making sure we always eventually will get blocks we need that are only known by inbound peers even during IBD, as otherwise we may be stuck in IBD indefinitely (which could have cascading failure on the network, if a large fraction of the network managed to get stuck in IBD). --- src/net_processing.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'src/net_processing.cpp') diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 590ce8e839..b525f759e2 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -4681,10 +4681,31 @@ bool PeerManagerImpl::SendMessages(CNode* pto) if (m_chainman.m_best_header == nullptr) { m_chainman.m_best_header = m_chainman.ActiveChain().Tip(); } - bool fFetch = state.fPreferredDownload || (m_num_preferred_download_peers == 0 && !pto->fClient && !pto->IsAddrFetchConn()); // Download if this is a nice peer, or we have no nice peers and this one might do. + + // Determine whether we might try initial headers sync or parallel + // block download from this peer -- this mostly affects behavior while + // in IBD (once out of IBD, we sync from all peers). + bool sync_blocks_and_headers_from_peer = false; + if (state.fPreferredDownload) { + sync_blocks_and_headers_from_peer = true; + } else if (!pto->fClient && !pto->IsAddrFetchConn()) { + // Typically this is an inbound peer. If we don't have any outbound + // peers, or if we aren't downloading any blocks from such peers, + // then allow block downloads from this peer, too. + // We prefer downloading blocks from outbound peers to avoid + // putting undue load on (say) some home user who is just making + // outbound connections to the network, but if our only source of + // the latest blocks is from an inbound peer, we have to be sure to + // eventually download it (and not just wait indefinitely for an + // outbound peer to have it). + if (m_num_preferred_download_peers == 0 || mapBlocksInFlight.empty()) { + sync_blocks_and_headers_from_peer = true; + } + } + if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) { // Only actively request headers from a single peer, unless we're close to today. - if ((nSyncStarted == 0 && fFetch) || m_chainman.m_best_header->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { + if ((nSyncStarted == 0 && sync_blocks_and_headers_from_peer) || m_chainman.m_best_header->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { state.fSyncStarted = true; state.m_headers_sync_timeout = current_time + HEADERS_DOWNLOAD_TIMEOUT_BASE + ( @@ -5063,7 +5084,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) // Message: getdata (blocks) // std::vector vGetData; - if (!pto->fClient && ((fFetch && !pto->m_limited_node) || !m_chainman.ActiveChainstate().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { + if (!pto->fClient && ((sync_blocks_and_headers_from_peer && !pto->m_limited_node) || !m_chainman.ActiveChainstate().IsInitialBlockDownload()) && state.nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { std::vector vToDownload; NodeId staller = -1; FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller); -- cgit v1.2.3