67
67
68
68
#include < statsd_client.h>
69
69
70
+ #include < algorithm>
70
71
#include < deque>
71
72
#include < numeric>
72
73
#include < optional>
@@ -4245,7 +4246,7 @@ CBlockIndex * BlockManager::InsertBlockIndex(const uint256& hash)
4245
4246
4246
4247
bool BlockManager::LoadBlockIndex (
4247
4248
const Consensus::Params& consensus_params,
4248
- std::set<CBlockIndex*, CBlockIndexWorkComparator>& block_index_candidates )
4249
+ ChainstateManager& chainman )
4249
4250
{
4250
4251
if (!m_block_tree_db->LoadBlockIndexGuts (consensus_params, [this ](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED (cs_main) { return this ->InsertBlockIndex (hash); })) {
4251
4252
return false ;
@@ -4265,17 +4266,41 @@ bool BlockManager::LoadBlockIndex(
4265
4266
}
4266
4267
}
4267
4268
sort (vSortedByHeight.begin (), vSortedByHeight.end ());
4269
+
4270
+ // Find start of assumed-valid region.
4271
+ int first_assumed_valid_height = std::numeric_limits<int >::max ();
4272
+
4273
+ for (const auto & [height, block] : vSortedByHeight) {
4274
+ if (block->IsAssumedValid ()) {
4275
+ auto chainstates = chainman.GetAll ();
4276
+
4277
+ // If we encounter an assumed-valid block index entry, ensure that we have
4278
+ // one chainstate that tolerates assumed-valid entries and another that does
4279
+ // not (i.e. the background validation chainstate), since assumed-valid
4280
+ // entries should always be pending validation by a fully-validated chainstate.
4281
+ auto any_chain = [&](auto fnc) { return std::any_of (chainstates.cbegin (), chainstates.cend (), fnc); };
4282
+ assert (any_chain ([](auto chainstate) { return chainstate->reliesOnAssumedValid (); }));
4283
+ assert (any_chain ([](auto chainstate) { return !chainstate->reliesOnAssumedValid (); }));
4284
+
4285
+ first_assumed_valid_height = height;
4286
+ break ;
4287
+ }
4288
+ }
4289
+
4268
4290
for (const std::pair<int , CBlockIndex*>& item : vSortedByHeight)
4269
4291
{
4270
4292
if (ShutdownRequested ()) return false ;
4271
4293
CBlockIndex* pindex = item.second ;
4272
4294
pindex->nChainWork = (pindex->pprev ? pindex->pprev ->nChainWork : 0 ) + GetBlockProof (*pindex);
4273
4295
pindex->nTimeMax = (pindex->pprev ? std::max (pindex->pprev ->nTimeMax , pindex->nTime ) : pindex->nTime );
4274
- // We can link the chain of blocks for which we've received transactions at some point.
4296
+
4297
+ // We can link the chain of blocks for which we've received transactions at some point, or
4298
+ // blocks that are assumed-valid on the basis of snapshot load (see
4299
+ // PopulateAndValidateSnapshot()).
4275
4300
// Pruned nodes may have deleted the block.
4276
4301
if (pindex->nTx > 0 ) {
4277
4302
if (pindex->pprev ) {
4278
- if (pindex->pprev ->HaveTxsDownloaded () ) {
4303
+ if (pindex->pprev ->nChainTx > 0 ) {
4279
4304
pindex->nChainTx = pindex->pprev ->nChainTx + pindex->nTx ;
4280
4305
} else {
4281
4306
pindex->nChainTx = 0 ;
@@ -4292,7 +4317,36 @@ bool BlockManager::LoadBlockIndex(
4292
4317
if (pindex->IsAssumedValid () ||
4293
4318
(pindex->IsValid (BLOCK_VALID_TRANSACTIONS) &&
4294
4319
(pindex->HaveTxsDownloaded () || pindex->pprev == nullptr ))) {
4295
- block_index_candidates.insert (pindex);
4320
+
4321
+ // Fill each chainstate's block candidate set. Only add assumed-valid
4322
+ // blocks to the tip candidate set if the chainstate is allowed to rely on
4323
+ // assumed-valid blocks.
4324
+ //
4325
+ // If all setBlockIndexCandidates contained the assumed-valid blocks, the
4326
+ // background chainstate's ActivateBestChain() call would add assumed-valid
4327
+ // blocks to the chain (based on how FindMostWorkChain() works). Obviously
4328
+ // we don't want this since the purpose of the background validation chain
4329
+ // is to validate assued-valid blocks.
4330
+ //
4331
+ // Note: This is considering all blocks whose height is greater or equal to
4332
+ // the first assumed-valid block to be assumed-valid blocks, and excluding
4333
+ // them from the background chainstate's setBlockIndexCandidates set. This
4334
+ // does mean that some blocks which are not technically assumed-valid
4335
+ // (later blocks on a fork beginning before the first assumed-valid block)
4336
+ // might not get added to the the background chainstate, but this is ok,
4337
+ // because they will still be attached to the active chainstate if they
4338
+ // actually contain more work.
4339
+ //
4340
+ // Instad of this height-based approach, an earlier attempt was made at
4341
+ // detecting "holistically" whether the block index under consideration
4342
+ // relied on an assumed-valid ancestor, but this proved to be too slow to
4343
+ // be practical.
4344
+ for (CChainState* chainstate : chainman.GetAll ()) {
4345
+ if (chainstate->reliesOnAssumedValid () ||
4346
+ pindex->nHeight < first_assumed_valid_height) {
4347
+ chainstate->setBlockIndexCandidates .insert (pindex);
4348
+ }
4349
+ }
4296
4350
}
4297
4351
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork ))
4298
4352
pindexBestInvalid = pindex;
@@ -4317,11 +4371,9 @@ void BlockManager::Unload() {
4317
4371
m_prev_block_index.clear ();
4318
4372
}
4319
4373
4320
- bool BlockManager::LoadBlockIndexDB (std::set<CBlockIndex*, CBlockIndexWorkComparator>& setBlockIndexCandidates )
4374
+ bool BlockManager::LoadBlockIndexDB (ChainstateManager& chainman )
4321
4375
{
4322
- if (!LoadBlockIndex (
4323
- ::Params ().GetConsensus(),
4324
- setBlockIndexCandidates)) {
4376
+ if (!LoadBlockIndex (::Params ().GetConsensus (), chainman)) {
4325
4377
return false ;
4326
4378
}
4327
4379
@@ -4758,7 +4810,7 @@ bool ChainstateManager::LoadBlockIndex()
4758
4810
// Load block index from databases
4759
4811
bool needs_init = fReindex ;
4760
4812
if (!fReindex ) {
4761
- bool ret = m_blockman.LoadBlockIndexDB (ActiveChainstate (). setBlockIndexCandidates );
4813
+ bool ret = m_blockman.LoadBlockIndexDB (* this );
4762
4814
if (!ret) return false ;
4763
4815
needs_init = m_blockman.m_block_index .empty ();
4764
4816
}
@@ -5694,7 +5746,14 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
5694
5746
5695
5747
// Fake various pieces of CBlockIndex state:
5696
5748
CBlockIndex* index = nullptr ;
5697
- for (int i = 0 ; i <= snapshot_chainstate.m_chain .Height (); ++i) {
5749
+
5750
+ // Don't make any modifications to the genesis block.
5751
+ // This is especially important because we don't want to erroneously
5752
+ // apply BLOCK_ASSUMED_VALID to genesis, which would happen if we didn't skip
5753
+ // it here (since it apparently isn't BLOCK_VALID_SCRIPTS).
5754
+ constexpr int AFTER_GENESIS_START{1 };
5755
+
5756
+ for (int i = AFTER_GENESIS_START; i <= snapshot_chainstate.m_chain .Height (); ++i) {
5698
5757
index = snapshot_chainstate.m_chain [i];
5699
5758
5700
5759
// Fake nTx so that LoadBlockIndex() loads assumed-valid CBlockIndex
@@ -5703,7 +5762,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
5703
5762
index->nTx = 1 ;
5704
5763
}
5705
5764
// Fake nChainTx so that GuessVerificationProgress reports accurately
5706
- index->nChainTx = index->pprev ? index-> pprev -> nChainTx + index->nTx : 1 ;
5765
+ index->nChainTx = index->pprev -> nChainTx + index->nTx ;
5707
5766
5708
5767
// Mark unvalidated block index entries beneath the snapshot base block as assumed-valid.
5709
5768
if (!index->IsValid (BLOCK_VALID_SCRIPTS)) {
0 commit comments