Skip to content

Commit 7e6fe4a

Browse files
committed
Don't let header syncing get too far ahead of block syncing
1 parent f5c7995 commit 7e6fe4a

File tree

1 file changed

+46
-10
lines changed

1 file changed

+46
-10
lines changed

src/net_processing.cpp

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ static constexpr auto UNCONDITIONAL_RELAY_DELAY = 2min;
4848
/** Headers download timeout.
4949
* Timeout = base + per_header * (expected number of headers) */
5050
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_BASE = 15min;
51-
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1ms;
51+
static constexpr auto HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 2ms;
5252
/** Protect at least this many outbound peers from disconnection due to slow/
5353
* behind headers chain.
5454
*/
@@ -2084,14 +2084,47 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
20842084
nodestate->m_last_block_announcement = GetTime();
20852085
}
20862086

2087-
if (nCount == MAX_HEADERS_RESULTS && !all_duplicate) {
2088-
// Headers message had its maximum size; the peer may have more headers.
2089-
// TODO: optimize: if pindexLast is an ancestor of m_chainman.ActiveChain().Tip or pindexBestHeader, continue
2090-
// from there instead.
2091-
// HOWEVER, if all headers we got this time were duplicates that we already had, don't ask for any more.
2092-
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
2093-
pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height);
2094-
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexLast), uint256()));
2087+
uint64_t headers_ahead = pindexLast->nHeight - m_chainman.ActiveHeight();
2088+
bool got_enough_headers = fTrimHeaders && (headers_ahead >= nHeaderDownloadBuffer);
2089+
2090+
// If a peer gives us as many headers as possible, this is implicitly a signal that the
2091+
// peer has more headers to send us. In Bitcoin Core, the node always asks for more
2092+
// headers at this point. Our logic is slightly more complex, because:
2093+
// (1) There is an apparent bug in the Bitcoin Core state machine here, where we can
2094+
// end up downloading headers from lots of peers at the same time by accident, which we
2095+
// work around rather than truly fix;
2096+
// (2) For various reasons we may want to avoid letting the header downloads get "too
2097+
// far ahead" of block downloads, so we may pause syncing for that reasons.
2098+
if (nCount == MAX_HEADERS_RESULTS) {
2099+
if (all_duplicate && !nodestate->fSyncStarted) {
2100+
// In this case two things are true:
2101+
// 1) This node's most recent batch of headers only included ones we already had.
2102+
// 2) We don't have this node marked as a peer to header-sync from.
2103+
// This happens when some exogenous event, like an INV of a new block, causes us
2104+
// to ask a peer for an unbounded number of headers, when we're already in the
2105+
// process of downloading the headers from a different peer.
2106+
// In this case the right thing to do is simply stop syncing headers from this
2107+
// peer; it's redundant. Here we do nothing; since we don't ask the peer for
2108+
// more headers, it will stop sending them.
2109+
} else if (got_enough_headers) {
2110+
// If we're trying to save memory on headers, and we've already got plenty of headers,
2111+
// pause until we're ready for more.
2112+
LogPrint(BCLog::NET, "Pausing header sync from peer=%d, because the last one was too far ahead of block sync (%d >> %d)\n", pfrom.GetId(), pindexLast->nHeight, m_chainman.ActiveHeight());
2113+
if (nodestate->fSyncStarted) {
2114+
// Cancel sync from this node, so we don't penalize it later.
2115+
// This will cause us to automatically start syncing from a different node (or restart syncing from the same node) later,
2116+
// if we still need to sync headers.
2117+
nSyncStarted--;
2118+
nodestate->fSyncStarted = false;
2119+
nodestate->m_headers_sync_timeout = 0us;
2120+
}
2121+
} else {
2122+
// TODO: optimize: if pindexLast is an ancestor of m_chainman.ActiveChain().Tip or pindexBestHeader, continue
2123+
// from there instead.
2124+
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
2125+
pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height);
2126+
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, m_chainman.ActiveChain().GetLocator(pindexLast), uint256()));
2127+
}
20952128
}
20962129

20972130
// If this set of headers is valid and ends in a block with at least as
@@ -4476,7 +4509,10 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
44764509
if (pindexBestHeader == nullptr)
44774510
pindexBestHeader = m_chainman.ActiveChain().Tip();
44784511
bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->IsAddrFetchConn()); // Download if this is a nice peer, or we have no nice peers and this one might do.
4479-
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex) {
4512+
uint64_t headers_ahead = pindexBestHeader->nHeight - m_chainman.ActiveHeight();
4513+
// ELEMENTS: Only download if our headers aren't "too far ahead" of our blocks.
4514+
bool got_enough_headers = fTrimHeaders && (headers_ahead >= nHeaderDownloadBuffer);
4515+
if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex && !got_enough_headers) {
44804516
// Only actively request headers from a single peer, unless we're close to today.
44814517
if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) {
44824518
state.fSyncStarted = true;

0 commit comments

Comments
 (0)