Skip to content

Commit ed47094

Browse files
sipasdaftuar
authored andcommitted
Add functions to construct locators without CChain
This introduces an insignificant performance penalty, as it means locator construction needs to use the skiplist-based CBlockIndex::GetAncestor() function instead of the lookup-based CChain, but avoids the need for callers to have access to a relevant CChain object.
1 parent 84852bb commit ed47094

File tree

5 files changed

+42
-35
lines changed

5 files changed

+42
-35
lines changed

src/chain.cpp

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -28,32 +28,33 @@ void CChain::SetTip(CBlockIndex& block)
2828
}
2929
}
3030

31-
CBlockLocator CChain::GetLocator(const CBlockIndex *pindex) const {
32-
int nStep = 1;
33-
std::vector<uint256> vHave;
34-
vHave.reserve(32);
35-
36-
if (!pindex)
37-
pindex = Tip();
38-
while (pindex) {
39-
vHave.push_back(pindex->GetBlockHash());
40-
// Stop when we have added the genesis block.
41-
if (pindex->nHeight == 0)
42-
break;
31+
std::vector<uint256> LocatorEntries(const CBlockIndex* index)
32+
{
33+
int step = 1;
34+
std::vector<uint256> have;
35+
if (index == nullptr) return have;
36+
37+
have.reserve(32);
38+
while (index) {
39+
have.emplace_back(index->GetBlockHash());
40+
if (index->nHeight == 0) break;
4341
// Exponentially larger steps back, plus the genesis block.
44-
int nHeight = std::max(pindex->nHeight - nStep, 0);
45-
if (Contains(pindex)) {
46-
// Use O(1) CChain index if possible.
47-
pindex = (*this)[nHeight];
48-
} else {
49-
// Otherwise, use O(log n) skiplist.
50-
pindex = pindex->GetAncestor(nHeight);
51-
}
52-
if (vHave.size() > 10)
53-
nStep *= 2;
42+
int height = std::max(index->nHeight - step, 0);
43+
// Use skiplist.
44+
index = index->GetAncestor(height);
45+
if (have.size() > 10) step *= 2;
5446
}
47+
return have;
48+
}
5549

56-
return CBlockLocator(vHave);
50+
CBlockLocator GetLocator(const CBlockIndex* index)
51+
{
52+
return CBlockLocator{std::move(LocatorEntries(index))};
53+
}
54+
55+
CBlockLocator CChain::GetLocator() const
56+
{
57+
return ::GetLocator(Tip());
5758
}
5859

5960
const CBlockIndex *CChain::FindFork(const CBlockIndex *pindex) const {

src/chain.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,8 +473,8 @@ class CChain
473473
/** Set/initialize a chain with a given tip. */
474474
void SetTip(CBlockIndex& block);
475475

476-
/** Return a CBlockLocator that refers to a block in this chain (by default the tip). */
477-
CBlockLocator GetLocator(const CBlockIndex* pindex = nullptr) const;
476+
/** Return a CBlockLocator that refers to the tip in of this chain. */
477+
CBlockLocator GetLocator() const;
478478

479479
/** Find the last common block between this chain and a block index entry. */
480480
const CBlockIndex* FindFork(const CBlockIndex* pindex) const;
@@ -483,4 +483,10 @@ class CChain
483483
CBlockIndex* FindEarliestAtLeast(int64_t nTime, int height) const;
484484
};
485485

486+
/** Get a locator for a block index entry. */
487+
CBlockLocator GetLocator(const CBlockIndex* index);
488+
489+
/** Construct a list of hash entries to put in a locator. */
490+
std::vector<uint256> LocatorEntries(const CBlockIndex* index);
491+
486492
#endif // BITCOIN_CHAIN_H

src/net_processing.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,7 +2285,7 @@ void PeerManagerImpl::HandleFewUnconnectingHeaders(CNode& pfrom, Peer& peer,
22852285

22862286
nodestate->nUnconnectingHeaders++;
22872287
// Try to fill in the missing headers.
2288-
if (MaybeSendGetHeaders(pfrom, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), peer)) {
2288+
if (MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), peer)) {
22892289
LogPrint(BCLog::NET, "received header %s: missing prev block %s, sending getheaders (%d) to end (peer=%d, nUnconnectingHeaders=%d)\n",
22902290
headers[0].GetHash().ToString(),
22912291
headers[0].hashPrevBlock.ToString(),
@@ -2506,11 +2506,12 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, Peer& peer,
25062506
return;
25072507
}
25082508
}
2509+
Assume(pindexLast);
25092510

25102511
// Consider fetching more headers.
25112512
if (nCount == MAX_HEADERS_RESULTS) {
25122513
// Headers message had its maximum size; the peer may have more headers.
2513-
if (MaybeSendGetHeaders(pfrom, WITH_LOCK(m_chainman.GetMutex(), return m_chainman.ActiveChain().GetLocator(pindexLast)), peer)) {
2514+
if (MaybeSendGetHeaders(pfrom, GetLocator(pindexLast), peer)) {
25142515
LogPrint(BCLog::NET, "more getheaders (%d) to end to peer=%d (startheight:%d)\n",
25152516
pindexLast->nHeight, pfrom.GetId(), peer.m_starting_height);
25162517
}
@@ -3285,7 +3286,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
32853286
// use if we turned on sync with all peers).
32863287
CNodeState& state{*Assert(State(pfrom.GetId()))};
32873288
if (state.fSyncStarted || (!peer->m_inv_triggered_getheaders_before_sync && *best_block != m_last_block_inv_triggering_headers_sync)) {
3288-
if (MaybeSendGetHeaders(pfrom, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *peer)) {
3289+
if (MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), *peer)) {
32893290
LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n",
32903291
m_chainman.m_best_header->nHeight, best_block->ToString(),
32913292
pfrom.GetId());
@@ -3752,7 +3753,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
37523753
if (!m_chainman.m_blockman.LookupBlockIndex(cmpctblock.header.hashPrevBlock)) {
37533754
// Doesn't connect (or is genesis), instead of DoSing in AcceptBlockHeader, request deeper headers
37543755
if (!m_chainman.ActiveChainstate().IsInitialBlockDownload()) {
3755-
MaybeSendGetHeaders(pfrom, m_chainman.ActiveChain().GetLocator(m_chainman.m_best_header), *peer);
3756+
MaybeSendGetHeaders(pfrom, GetLocator(m_chainman.m_best_header), *peer);
37563757
}
37573758
return;
37583759
}
@@ -4502,7 +4503,7 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, Peer& peer, std::chrono::seco
45024503
// getheaders in-flight already, in which case the peer should
45034504
// still respond to us with a sufficiently high work chain tip.
45044505
MaybeSendGetHeaders(pto,
4505-
m_chainman.ActiveChain().GetLocator(state.m_chain_sync.m_work_header->pprev),
4506+
GetLocator(state.m_chain_sync.m_work_header->pprev),
45064507
peer);
45074508
LogPrint(BCLog::NET, "sending getheaders to outbound peer=%d to verify chain work (current best known block:%s, benchmark blockhash: %s)\n", pto.GetId(), state.pindexBestKnownBlock != nullptr ? state.pindexBestKnownBlock->GetBlockHash().ToString() : "<none>", state.m_chain_sync.m_work_header->GetBlockHash().ToString());
45084509
state.m_chain_sync.m_sent_getheaders = true;
@@ -4924,7 +4925,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
49244925
got back an empty response. */
49254926
if (pindexStart->pprev)
49264927
pindexStart = pindexStart->pprev;
4927-
if (MaybeSendGetHeaders(*pto, m_chainman.ActiveChain().GetLocator(pindexStart), *peer)) {
4928+
if (MaybeSendGetHeaders(*pto, GetLocator(pindexStart), *peer)) {
49284929
LogPrint(BCLog::NET, "initial getheaders (%d) to peer=%d (startheight:%d)\n", pindexStart->nHeight, pto->GetId(), peer->m_starting_height);
49294930

49304931
state.fSyncStarted = true;

src/node/interfaces.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<Rec
400400
if (block.m_max_time) *block.m_max_time = index->GetBlockTimeMax();
401401
if (block.m_mtp_time) *block.m_mtp_time = index->GetMedianTimePast();
402402
if (block.m_in_active_chain) *block.m_in_active_chain = active[index->nHeight] == index;
403-
if (block.m_locator) { *block.m_locator = active.GetLocator(index); }
403+
if (block.m_locator) { *block.m_locator = GetLocator(index); }
404404
if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active);
405405
if (block.m_data) {
406406
REVERSE_LOCK(lock);
@@ -527,8 +527,7 @@ class ChainImpl : public Chain
527527
{
528528
LOCK(::cs_main);
529529
const CBlockIndex* index = chainman().m_blockman.LookupBlockIndex(block_hash);
530-
if (!index) return {};
531-
return chainman().ActiveChain().GetLocator(index);
530+
return GetLocator(index);
532531
}
533532
std::optional<int> findLocatorFork(const CBlockLocator& locator) override
534533
{

src/test/skiplist_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(getlocator_test)
7878
for (int n=0; n<100; n++) {
7979
int r = InsecureRandRange(150000);
8080
CBlockIndex* tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000];
81-
CBlockLocator locator = chain.GetLocator(tip);
81+
CBlockLocator locator = GetLocator(tip);
8282

8383
// The first result must be the block itself, the last one must be genesis.
8484
BOOST_CHECK(locator.vHave.front() == tip->GetBlockHash());

0 commit comments

Comments
 (0)