@@ -5050,19 +5050,28 @@ void ChainstateManager::CheckBlockIndex()
5050
5050
return ;
5051
5051
}
5052
5052
5053
- // Build forward-pointing map of the entire block tree.
5053
+ // Build forward-pointing data structure for the entire block tree.
5054
+ // For performance reasons, indexes of the best header chain are stored in a vector (within CChain).
5055
+ // All remaining blocks are stored in a multimap.
5056
+ // The best header chain can differ from the active chain: E.g. its entries may belong to blocks that
5057
+ // are not yet validated.
5058
+ CChain best_hdr_chain;
5059
+ assert (m_best_header);
5060
+ best_hdr_chain.SetTip (*m_best_header);
5061
+
5054
5062
std::multimap<CBlockIndex*,CBlockIndex*> forward;
5055
5063
for (auto & [_, block_index] : m_blockman.m_block_index ) {
5056
- forward.emplace (block_index.pprev , &block_index);
5064
+ // Only save indexes in forward that are not part of the best header chain.
5065
+ if (!best_hdr_chain.Contains (&block_index)) {
5066
+ // Only genesis, which must be part of the best header chain, can have a nullptr parent.
5067
+ assert (block_index.pprev );
5068
+ forward.emplace (block_index.pprev , &block_index);
5069
+ }
5057
5070
}
5071
+ assert (forward.size () + best_hdr_chain.Height () + 1 == m_blockman.m_block_index .size ());
5058
5072
5059
- assert (forward.size () == m_blockman.m_block_index .size ());
5060
-
5061
- std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeGenesis = forward.equal_range (nullptr );
5062
- CBlockIndex *pindex = rangeGenesis.first ->second ;
5063
- rangeGenesis.first ++;
5064
- assert (rangeGenesis.first == rangeGenesis.second ); // There is only one index entry with parent nullptr.
5065
-
5073
+ CBlockIndex* pindex = best_hdr_chain[0 ];
5074
+ assert (pindex);
5066
5075
// Iterate over the entire block tree, using depth-first search.
5067
5076
// Along the way, remember whether there are blocks on the path from genesis
5068
5077
// block being explored which are the first to have certain properties.
@@ -5274,14 +5283,21 @@ void ChainstateManager::CheckBlockIndex()
5274
5283
// assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow
5275
5284
// End: actual consistency checks.
5276
5285
5277
- // Try descending into the first subnode.
5286
+
5287
+ // Try descending into the first subnode. Always process forks first and the best header chain after.
5278
5288
snap_update_firsts ();
5279
5289
std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> range = forward.equal_range (pindex);
5280
5290
if (range.first != range.second ) {
5281
- // A subnode was found.
5291
+ // A subnode not part of the best header chain was found.
5282
5292
pindex = range.first ->second ;
5283
5293
nHeight++;
5284
5294
continue ;
5295
+ } else if (best_hdr_chain.Contains (pindex)) {
5296
+ // Descend further into best header chain.
5297
+ nHeight++;
5298
+ pindex = best_hdr_chain[nHeight];
5299
+ if (!pindex) break ; // we are finished, since the best header chain is always processed last
5300
+ continue ;
5285
5301
}
5286
5302
// This is a leaf node.
5287
5303
// Move upwards until we reach a node of which we have not yet visited the last child.
@@ -5307,9 +5323,15 @@ void ChainstateManager::CheckBlockIndex()
5307
5323
// Proceed to the next one.
5308
5324
rangePar.first ++;
5309
5325
if (rangePar.first != rangePar.second ) {
5310
- // Move to the sibling.
5326
+ // Move to a sibling not part of the best header chain .
5311
5327
pindex = rangePar.first ->second ;
5312
5328
break ;
5329
+ } else if (pindexPar == best_hdr_chain[nHeight - 1 ]) {
5330
+ // Move to pindex's sibling on the best-chain, if it has one.
5331
+ pindex = best_hdr_chain[nHeight];
5332
+ // There will not be a next block if (and only if) parent block is the best header.
5333
+ assert ((pindex == nullptr ) == (pindexPar == best_hdr_chain.Tip ()));
5334
+ break ;
5313
5335
} else {
5314
5336
// Move up further.
5315
5337
pindex = pindexPar;
@@ -5319,8 +5341,8 @@ void ChainstateManager::CheckBlockIndex()
5319
5341
}
5320
5342
}
5321
5343
5322
- // Check that we actually traversed the entire map .
5323
- assert (nNodes == forward.size ());
5344
+ // Check that we actually traversed the entire block index .
5345
+ assert (nNodes == forward.size () + best_hdr_chain. Height () + 1 );
5324
5346
}
5325
5347
5326
5348
std::string Chainstate::ToString ()
0 commit comments