Skip to content

Commit c55027b

Browse files
committed
merge bitcoin#24515: Only load BlockMan in BlockMan member functions
1 parent 47ec98e commit c55027b

File tree

10 files changed

+152
-126
lines changed

10 files changed

+152
-126
lines changed

src/index/coinstatsindex.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* n
272272

273273
{
274274
LOCK(cs_main);
275-
CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip->GetBlockHash())};
275+
const CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip->GetBlockHash())};
276276
const auto& consensus_params{Params().GetConsensus()};
277277

278278
do {

src/miner.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParam
5757
return nNewTime - nOldTime;
5858
}
5959

60-
BlockAssembler::Options::Options() {
60+
BlockAssembler::Options::Options()
61+
{
6162
blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
6263
nBlockMaxSize = DEFAULT_BLOCK_MAX_SIZE;
6364
}

src/node/blockstorage.cpp

Lines changed: 50 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,45 @@ bool fAddressIndex = DEFAULT_ADDRESSINDEX;
3333
bool fTimestampIndex = DEFAULT_TIMESTAMPINDEX;
3434
bool fSpentIndex = DEFAULT_SPENTINDEX;
3535

36+
bool CBlockIndexWorkComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
37+
{
38+
// First sort by most total work, ...
39+
if (pa->nChainWork > pb->nChainWork) return false;
40+
if (pa->nChainWork < pb->nChainWork) return true;
41+
42+
// ... then by earliest time received, ...
43+
if (pa->nSequenceId < pb->nSequenceId) return false;
44+
if (pa->nSequenceId > pb->nSequenceId) return true;
45+
46+
// Use pointer address as tie breaker (should only happen with blocks
47+
// loaded from disk, as those all have id 0).
48+
if (pa < pb) return false;
49+
if (pa > pb) return true;
50+
51+
// Identical blocks.
52+
return false;
53+
}
54+
55+
bool CBlockIndexHeightOnlyComparator::operator()(const CBlockIndex* pa, const CBlockIndex* pb) const
56+
{
57+
return pa->nHeight < pb->nHeight;
58+
}
59+
3660
static FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false);
3761
static FlatFileSeq BlockFileSeq();
3862
static FlatFileSeq UndoFileSeq();
3963

64+
std::vector<CBlockIndex*> BlockManager::GetAllBlockIndices()
65+
{
66+
AssertLockHeld(cs_main);
67+
std::vector<CBlockIndex*> rv;
68+
rv.reserve(m_block_index.size());
69+
for (auto& [_, block_index] : m_block_index) {
70+
rv.push_back(&block_index);
71+
}
72+
return rv;
73+
}
74+
4075
CBlockIndex* BlockManager::LookupBlockIndex(const uint256& hash)
4176
{
4277
AssertLockHeld(cs_main);
@@ -220,60 +255,34 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
220255
return nullptr;
221256
}
222257

223-
// Return existing or create new
224-
auto [mi, inserted] = m_block_index.try_emplace(hash);
258+
const auto [mi, inserted]{m_block_index.try_emplace(hash)};
225259
CBlockIndex* pindex = &(*mi).second;
226260
if (inserted) {
227261
pindex->phashBlock = &((*mi).first);
228262
}
229263
return pindex;
230264
}
231265

232-
bool BlockManager::LoadBlockIndex(
233-
const Consensus::Params& consensus_params,
234-
ChainstateManager& chainman)
266+
bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
235267
{
236268
if (!m_block_tree_db->LoadBlockIndexGuts(consensus_params, [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); })) {
237269
return false;
238270
}
239271

240-
// Calculate nChainWork
241-
std::vector<std::pair<int, CBlockIndex*>> vSortedByHeight;
242-
vSortedByHeight.reserve(m_block_index.size());
243272
for (auto& [_, block_index] : m_block_index) {
244-
CBlockIndex* pindex = &block_index;
245-
vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex));
246-
247273
// build m_blockman.m_prev_block_index
248-
if (pindex->pprev) {
249-
m_prev_block_index.emplace(pindex->pprev->GetBlockHash(), pindex);
274+
if (block_index.pprev) {
275+
m_prev_block_index.emplace(block_index.pprev->GetBlockHash(), &block_index);
250276
}
251277
}
252-
sort(vSortedByHeight.begin(), vSortedByHeight.end());
253-
254-
// Find start of assumed-valid region.
255-
int first_assumed_valid_height = std::numeric_limits<int>::max();
256278

257-
for (const auto& [height, block] : vSortedByHeight) {
258-
if (block->IsAssumedValid()) {
259-
auto chainstates = chainman.GetAll();
260-
261-
// If we encounter an assumed-valid block index entry, ensure that we have
262-
// one chainstate that tolerates assumed-valid entries and another that does
263-
// not (i.e. the background validation chainstate), since assumed-valid
264-
// entries should always be pending validation by a fully-validated chainstate.
265-
auto any_chain = [&](auto fnc) { return std::any_of(chainstates.cbegin(), chainstates.cend(), fnc); };
266-
assert(any_chain([](auto chainstate) { return chainstate->reliesOnAssumedValid(); }));
267-
assert(any_chain([](auto chainstate) { return !chainstate->reliesOnAssumedValid(); }));
268-
269-
first_assumed_valid_height = height;
270-
break;
271-
}
272-
}
279+
// Calculate nChainWork
280+
std::vector<CBlockIndex*> vSortedByHeight{GetAllBlockIndices()};
281+
std::sort(vSortedByHeight.begin(), vSortedByHeight.end(),
282+
CBlockIndexHeightOnlyComparator());
273283

274-
for (const std::pair<int, CBlockIndex*>& item : vSortedByHeight) {
284+
for (CBlockIndex* pindex : vSortedByHeight) {
275285
if (ShutdownRequested()) return false;
276-
CBlockIndex* pindex = item.second;
277286
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
278287
pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
279288

@@ -297,43 +306,6 @@ bool BlockManager::LoadBlockIndex(
297306
pindex->nStatus |= BLOCK_FAILED_CHILD;
298307
m_dirty_blockindex.insert(pindex);
299308
}
300-
if (pindex->IsAssumedValid() ||
301-
(pindex->IsValid(BLOCK_VALID_TRANSACTIONS) &&
302-
(pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))) {
303-
304-
// Fill each chainstate's block candidate set. Only add assumed-valid
305-
// blocks to the tip candidate set if the chainstate is allowed to rely on
306-
// assumed-valid blocks.
307-
//
308-
// If all setBlockIndexCandidates contained the assumed-valid blocks, the
309-
// background chainstate's ActivateBestChain() call would add assumed-valid
310-
// blocks to the chain (based on how FindMostWorkChain() works). Obviously
311-
// we don't want this since the purpose of the background validation chain
312-
// is to validate assued-valid blocks.
313-
//
314-
// Note: This is considering all blocks whose height is greater or equal to
315-
// the first assumed-valid block to be assumed-valid blocks, and excluding
316-
// them from the background chainstate's setBlockIndexCandidates set. This
317-
// does mean that some blocks which are not technically assumed-valid
318-
// (later blocks on a fork beginning before the first assumed-valid block)
319-
// might not get added to the the background chainstate, but this is ok,
320-
// because they will still be attached to the active chainstate if they
321-
// actually contain more work.
322-
//
323-
// Instad of this height-based approach, an earlier attempt was made at
324-
// detecting "holistically" whether the block index under consideration
325-
// relied on an assumed-valid ancestor, but this proved to be too slow to
326-
// be practical.
327-
for (CChainState* chainstate : chainman.GetAll()) {
328-
if (chainstate->reliesOnAssumedValid() ||
329-
pindex->nHeight < first_assumed_valid_height) {
330-
chainstate->setBlockIndexCandidates.insert(pindex);
331-
}
332-
}
333-
}
334-
if (pindex->nStatus & BLOCK_FAILED_MASK && (!chainman.m_best_invalid || pindex->nChainWork > chainman.m_best_invalid->nChainWork)) {
335-
chainman.m_best_invalid = pindex;
336-
}
337309
if (pindex->pprev) {
338310
pindex->BuildSkip();
339311
}
@@ -377,9 +349,9 @@ bool BlockManager::WriteBlockIndexDB()
377349
return true;
378350
}
379351

380-
bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
352+
bool BlockManager::LoadBlockIndexDB()
381353
{
382-
if (!LoadBlockIndex(::Params().GetConsensus(), chainman)) {
354+
if (!LoadBlockIndex(::Params().GetConsensus())) {
383355
return false;
384356
}
385357

@@ -404,9 +376,8 @@ bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
404376
LogPrintf("Checking all blk files are present...\n");
405377
std::set<int> setBlkDataFiles;
406378
for (const auto& [_, block_index] : m_block_index) {
407-
const CBlockIndex* pindex = &block_index;
408-
if (pindex->nStatus & BLOCK_HAVE_DATA) {
409-
setBlkDataFiles.insert(pindex->nFile);
379+
if (block_index.nStatus & BLOCK_HAVE_DATA) {
380+
setBlkDataFiles.insert(block_index.nFile);
410381
}
411382
}
412383
for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) {
@@ -442,13 +413,13 @@ bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
442413
return true;
443414
}
444415

445-
CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
416+
const CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
446417
{
447418
const MapCheckpoints& checkpoints = data.mapCheckpoints;
448419

449420
for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints)) {
450421
const uint256& hash = i.second;
451-
CBlockIndex* pindex = LookupBlockIndex(hash);
422+
const CBlockIndex* pindex = LookupBlockIndex(hash);
452423
if (pindex) {
453424
return pindex;
454425
}

src/node/blockstorage.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ struct CBlockIndexWorkComparator {
7474
bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const;
7575
};
7676

77+
struct CBlockIndexHeightOnlyComparator {
78+
/* Only compares the height of two block indices, doesn't try to tie-break */
79+
bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const;
80+
};
81+
7782
/**
7883
* Maintains a tree of blocks (stored in `m_block_index`) which is consulted
7984
* to determine where the most-work tip is.
@@ -131,6 +136,8 @@ class BlockManager
131136
BlockMap m_block_index GUARDED_BY(cs_main);
132137
PrevBlockMap m_prev_block_index GUARDED_BY(cs_main);
133138

139+
std::vector<CBlockIndex*> GetAllBlockIndices() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
140+
134141
/**
135142
* All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
136143
* Pruned nodes may have entries where B is missing data.
@@ -140,16 +147,15 @@ class BlockManager
140147
std::unique_ptr<CBlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main);
141148

142149
bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
143-
bool LoadBlockIndexDB(ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
150+
bool LoadBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
144151

145152
/**
146153
* Load the blocktree off disk and into memory. Populate certain metadata
147154
* per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral
148155
* collections like m_dirty_blockindex.
149156
*/
150-
bool LoadBlockIndex(
151-
const Consensus::Params& consensus_params,
152-
ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
157+
bool LoadBlockIndex(const Consensus::Params& consensus_params)
158+
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
153159

154160
/** Clear all data members. */
155161
void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -176,7 +182,7 @@ class BlockManager
176182
uint64_t CalculateCurrentUsage();
177183

178184
//! Returns last CBlockIndex* that is a checkpoint
179-
CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
185+
const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
180186

181187
/**
182188
* Return the spend height, which is one more than the inputs.GetBestBlock().

src/node/interfaces.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -763,7 +763,7 @@ class ChainImpl : public Chain
763763
{
764764
LOCK(cs_main);
765765
const CChainState& active = Assert(m_node.chainman)->ActiveChainstate();
766-
if (CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
766+
if (const CBlockIndex* fork = active.FindForkInGlobalIndex(locator)) {
767767
return fork->nHeight;
768768
}
769769
return std::nullopt;
@@ -861,7 +861,7 @@ class ChainImpl : public Chain
861861
// used to limit the range, and passing min_height that's too low or
862862
// max_height that's too high will not crash or change the result.
863863
LOCK(::cs_main);
864-
if (CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
864+
if (const CBlockIndex* block = chainman().m_blockman.LookupBlockIndex(block_hash)) {
865865
if (max_height && block->nHeight >= *max_height) block = block->GetAncestor(*max_height);
866866
for (; block->nStatus & BLOCK_HAVE_DATA; block = block->pprev) {
867867
// Check pprev to not segfault if min_height is too low

src/rest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,8 @@ static bool rest_block(const CoreContext& context,
271271
return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr);
272272

273273
CBlock block;
274-
CBlockIndex* pblockindex = nullptr;
275-
CBlockIndex* tip = nullptr;
274+
const CBlockIndex* pblockindex = nullptr;
275+
const CBlockIndex* tip = nullptr;
276276
{
277277
ChainstateManager* maybe_chainman = GetChainman(context, req);
278278
if (!maybe_chainman) return false;

src/rpc/blockchain.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ static int ComputeNextBlockAndDepth(const CBlockIndex* tip, const CBlockIndex* b
9696
return blockindex == tip ? 1 : -1;
9797
}
9898

99-
CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman) {
99+
static const CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainman)
100+
{
100101
LOCK(::cs_main);
101102
CChain& active_chain = chainman.ActiveChain();
102103

@@ -113,7 +114,7 @@ CBlockIndex* ParseHashOrHeight(const UniValue& param, ChainstateManager& chainma
113114
return active_chain[height];
114115
} else {
115116
const uint256 hash{ParseHashV(param, "hash_or_height")};
116-
CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
117+
const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(hash);
117118

118119
if (!pindex) {
119120
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
@@ -874,7 +875,7 @@ static RPCHelpMan getblockhash()
874875
if (nHeight < 0 || nHeight > active_chain.Height())
875876
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
876877

877-
CBlockIndex* pblockindex = active_chain[nHeight];
878+
const CBlockIndex* pblockindex = active_chain[nHeight];
878879
return pblockindex->GetBlockHash().GetHex();
879880
},
880881
};
@@ -1304,7 +1305,7 @@ static RPCHelpMan pruneblockchain()
13041305
// too low to be a block time (corresponds to timestamp from Sep 2001).
13051306
if (heightParam > 1000000000) {
13061307
// Add a 2 hour buffer to include blocks which might have had old timestamps
1307-
CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
1308+
const CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
13081309
if (!pindex) {
13091310
throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
13101311
}
@@ -1398,7 +1399,7 @@ static RPCHelpMan gettxoutsetinfo()
13981399
{
13991400
UniValue ret(UniValue::VOBJ);
14001401

1401-
CBlockIndex* pindex{nullptr};
1402+
const CBlockIndex* pindex{nullptr};
14021403
const CoinStatsHashType hash_type{request.params[0].isNull() ? CoinStatsHashType::HASH_SERIALIZED : ParseHashType(request.params[0].get_str())};
14031404
CCoinsStats stats{hash_type};
14041405
stats.index_requested = request.params[2].isNull() || request.params[2].get_bool();
@@ -2344,7 +2345,7 @@ static RPCHelpMan getblockstats()
23442345

23452346
ChainstateManager& chainman = EnsureAnyChainman(request.context);
23462347
LOCK(cs_main);
2347-
CBlockIndex* pindex{ParseHashOrHeight(request.params[0], chainman)};
2348+
const CBlockIndex* pindex{ParseHashOrHeight(request.params[0], chainman)};
23482349
CHECK_NONFATAL(pindex != nullptr);
23492350

23502351
std::set<std::string> stats;
@@ -2801,7 +2802,7 @@ static RPCHelpMan scantxoutset()
28012802
g_should_abort_scan = false;
28022803
int64_t count = 0;
28032804
std::unique_ptr<CCoinsViewCursor> pcursor;
2804-
CBlockIndex* tip;
2805+
const CBlockIndex* tip;
28052806
NodeContext& node = EnsureAnyNodeContext(request.context);
28062807
{
28072808
ChainstateManager& chainman = EnsureChainman(node);
@@ -2981,7 +2982,7 @@ UniValue CreateUTXOSnapshot(NodeContext& node, CChainState& chainstate, CAutoFil
29812982
{
29822983
std::unique_ptr<CCoinsViewCursor> pcursor;
29832984
CCoinsStats stats{CoinStatsHashType::NONE};
2984-
CBlockIndex* tip;
2985+
const CBlockIndex* tip;
29852986

29862987
{
29872988
// We need to lock cs_main to ensure that the coinsdb isn't written to

src/rpc/rawtransaction.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ static RPCHelpMan getrawtransaction()
208208

209209
bool in_active_chain = true;
210210
uint256 hash = ParseHashV(request.params[0], "parameter 1");
211-
CBlockIndex* blockindex = nullptr;
211+
const CBlockIndex* blockindex = nullptr;
212212

213213
if (hash == Params().GenesisBlock().hashMerkleRoot) {
214214
// Special exception for the genesis block coinbase transaction
@@ -610,7 +610,7 @@ static RPCHelpMan gettxoutproof()
610610
}
611611
}
612612

613-
CBlockIndex* pblockindex = nullptr;
613+
const CBlockIndex* pblockindex = nullptr;
614614
uint256 hashBlock;
615615
ChainstateManager& chainman = EnsureAnyChainman(request.context);
616616
if (!request.params[1].isNull()) {

0 commit comments

Comments
 (0)