diff --git a/src/chain.h b/src/chain.h --- a/src/chain.h +++ b/src/chain.h @@ -195,11 +195,8 @@ /** Set/initialize a chain with a given tip. */ void SetTip(CBlockIndex *pindex); - /** - * Return a CBlockLocator that refers to a block in this chain (by default - * the tip). - */ - CBlockLocator GetLocator(const CBlockIndex *pindex = nullptr) const; + /** Return a CBlockLocator that refers to the tip of this chain */ + CBlockLocator GetLocator() const; /** * Find the last common block between this chain and a block index entry. @@ -213,4 +210,10 @@ CBlockIndex *FindEarliestAtLeast(int64_t nTime, int height) const; }; +/** Get a locator for a block index entry. */ +CBlockLocator GetLocator(const CBlockIndex *index); + +/** Construct a list of hash entries to put in a locator. */ +std::vector LocatorEntries(const CBlockIndex *index); + #endif // BITCOIN_CHAIN_H diff --git a/src/chain.cpp b/src/chain.cpp --- a/src/chain.cpp +++ b/src/chain.cpp @@ -18,35 +18,36 @@ } } -CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const { - int nStep = 1; - std::vector vHave; - vHave.reserve(32); - - if (!pindex) { - pindex = Tip(); +std::vector LocatorEntries(const CBlockIndex *index) { + int step = 1; + std::vector have; + if (index == nullptr) { + return have; } - while (pindex) { - vHave.push_back(pindex->GetBlockHash()); - // Stop when we have added the genesis block. - if (pindex->nHeight == 0) { + + have.reserve(32); + while (index) { + have.emplace_back(index->GetBlockHash()); + if (index->nHeight == 0) { break; } // Exponentially larger steps back, plus the genesis block. - int nHeight = std::max(pindex->nHeight - nStep, 0); - if (Contains(pindex)) { - // Use O(1) CChain index if possible. - pindex = (*this)[nHeight]; - } else { - // Otherwise, use O(log n) skiplist. - pindex = pindex->GetAncestor(nHeight); - } - if (vHave.size() > 10) { - nStep *= 2; + int height = std::max(index->nHeight - step, 0); + // Use skiplist. + index = index->GetAncestor(height); + if (have.size() > 10) { + step *= 2; } } + return have; +} + +CBlockLocator GetLocator(const CBlockIndex *index) { + return CBlockLocator{std::move(LocatorEntries(index))}; +} - return CBlockLocator(vHave); +CBlockLocator CChain::GetLocator() const { + return ::GetLocator(Tip()); } const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const { diff --git a/src/index/base.cpp b/src/index/base.cpp --- a/src/index/base.cpp +++ b/src/index/base.cpp @@ -221,8 +221,7 @@ if (m_best_block_index == nullptr) { return false; } - GetDB().WriteBestBlock( - batch, m_chainstate->m_chain.GetLocator(m_best_block_index)); + GetDB().WriteBestBlock(batch, GetLocator(m_best_block_index)); return true; } diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3251,10 +3251,8 @@ nodestate->nUnconnectingHeaders++; // Try to fill in the missing headers. - if (MaybeSendGetHeaders( - pfrom, - m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), - peer)) { + if (MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), + peer)) { LogPrint( BCLog::NET, "received header %s: missing prev block %s, sending getheaders " @@ -3510,13 +3508,12 @@ return; } } + Assume(pindexLast); // Consider fetching more headers. if (nCount == MAX_HEADERS_RESULTS) { - LOCK(cs_main); // Headers message had its maximum size; the peer may have more headers. - if (MaybeSendGetHeaders( - pfrom, m_chainman.ActiveChain().GetLocator(pindexLast), peer)) { + if (MaybeSendGetHeaders(pfrom, GetLocator(pindexLast), peer)) { LogPrint( BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n", @@ -4527,10 +4524,8 @@ 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)) { + if (MaybeSendGetHeaders( + pfrom, 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()); @@ -5017,10 +5012,8 @@ // Doesn't connect (or is genesis), instead of DoSing in // AcceptBlockHeader, request deeper headers if (!m_chainman.ActiveChainstate().IsInitialBlockDownload()) { - MaybeSendGetHeaders(pfrom, - m_chainman.ActiveChain().GetLocator( - m_chainman.m_best_header), - *peer); + MaybeSendGetHeaders( + pfrom, GetLocator(m_chainman.m_best_header), *peer); } return; } @@ -6592,9 +6585,7 @@ // getheaders in-flight already, in which case the peer should // still respond to us with a sufficiently high work chain tip. MaybeSendGetHeaders( - pto, - m_chainman.ActiveChain().GetLocator( - state.m_chain_sync.m_work_header->pprev), + pto, GetLocator(state.m_chain_sync.m_work_header->pprev), peer); LogPrint( BCLog::NET, @@ -7117,9 +7108,7 @@ if (pindexStart->pprev) { pindexStart = pindexStart->pprev; } - if (MaybeSendGetHeaders( - *pto, m_chainman.ActiveChain().GetLocator(pindexStart), - *peer)) { + if (MaybeSendGetHeaders(*pto, GetLocator(pindexStart), *peer)) { LogPrint( BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -388,6 +388,7 @@ if (block.m_in_active_chain) { *block.m_in_active_chain = active[index->nHeight] == index; } + // TODO backport core#25494 with change from core#25717 if (block.m_next_block) { FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] @@ -536,6 +537,7 @@ const CChain &active = Assert(m_node.chainman)->ActiveChain(); return active.GetLocator(); } + // TODO: backport core#25036 with changes from core#25717 std::optional findLocatorFork(const CBlockLocator &locator) override { LOCK(cs_main); diff --git a/src/test/skiplist_tests.cpp b/src/test/skiplist_tests.cpp --- a/src/test/skiplist_tests.cpp +++ b/src/test/skiplist_tests.cpp @@ -92,7 +92,7 @@ int r = InsecureRandRange(150000); CBlockIndex *tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000]; - CBlockLocator locator = chain.GetLocator(tip); + CBlockLocator locator = GetLocator(tip); // The first result must be the block itself, the last one must be // genesis.