Fix elements multiple-header-download issue.

This fixes an issue which causes Elements to download the blockchain headers
multiple times during initial block download.

In particular: each time we receive an INV P2P message with a new block
(about once a minute), we start downloading the headers, again, in parallel
with any existing download(s) in progress.

With this change, after we receive each batch of headers, we check whether
any of the headers in it were new to us. If not (they were all duplicates),
we stop there, and do not ask the peer for another batch. This reduces the
maximum amount of duplication to about 2x, which is not ideal, but a HUGE
improvement.
This commit is contained in:
Glenn Willen 2021-11-09 21:06:42 -08:00
parent 04cedf3f6b
commit cdfb4c9c6c
3 changed files with 23 additions and 7 deletions

View file

@ -1843,7 +1843,8 @@ void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHe
}
BlockValidationState state;
if (!m_chainman.ProcessNewBlockHeaders(headers, state, m_chainparams, &pindexLast)) {
bool all_duplicate = false;
if (!m_chainman.ProcessNewBlockHeaders(headers, state, m_chainparams, &pindexLast, &all_duplicate)) {
if (state.IsInvalid()) {
MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");
return;
@ -1869,10 +1870,11 @@ void PeerManager::ProcessHeadersMessage(CNode& pfrom, const std::vector<CBlockHe
nodestate->m_last_block_announcement = GetTime();
}
if (nCount == MAX_HEADERS_RESULTS) {
if (nCount == MAX_HEADERS_RESULTS && !all_duplicate) {
// Headers message had its maximum size; the peer may have more headers.
// TODO: optimize: if pindexLast is an ancestor of ::ChainActive().Tip or pindexBestHeader, continue
// from there instead.
// HOWEVER, if all headers we got this time were duplicates that we already had, don't ask for any more.
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", pindexLast->nHeight, pfrom.GetId(), pfrom.nStartingHeight);
m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexLast), uint256()));
}