55
55
#include < validationinterface.h>
56
56
#include < warnings.h>
57
57
58
+ #include < algorithm>
58
59
#include < numeric>
59
60
#include < optional>
60
61
#include < string>
@@ -3694,7 +3695,7 @@ CBlockIndex * BlockManager::InsertBlockIndex(const uint256& hash)
3694
3695
3695
3696
bool BlockManager::LoadBlockIndex (
3696
3697
const Consensus::Params& consensus_params,
3697
- std::set<CBlockIndex*, CBlockIndexWorkComparator>& block_index_candidates )
3698
+ ChainstateManager& chainman )
3698
3699
{
3699
3700
if (!m_block_tree_db->LoadBlockIndexGuts (consensus_params, [this ](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED (cs_main) { return this ->InsertBlockIndex (hash); })) {
3700
3701
return false ;
@@ -3709,17 +3710,41 @@ bool BlockManager::LoadBlockIndex(
3709
3710
vSortedByHeight.push_back (std::make_pair (pindex->nHeight , pindex));
3710
3711
}
3711
3712
sort (vSortedByHeight.begin (), vSortedByHeight.end ());
3713
+
3714
+ // Find start of assumed-valid region.
3715
+ int first_assumed_valid_height = std::numeric_limits<int >::max ();
3716
+
3717
+ for (const auto & [height, block] : vSortedByHeight) {
3718
+ if (block->IsAssumedValid ()) {
3719
+ auto chainstates = chainman.GetAll ();
3720
+
3721
+ // If we encounter an assumed-valid block index entry, ensure that we have
3722
+ // one chainstate that tolerates assumed-valid entries and another that does
3723
+ // not (i.e. the background validation chainstate), since assumed-valid
3724
+ // entries should always be pending validation by a fully-validated chainstate.
3725
+ auto any_chain = [&](auto fnc) { return std::any_of (chainstates.cbegin (), chainstates.cend (), fnc); };
3726
+ assert (any_chain ([](auto chainstate) { return chainstate->reliesOnAssumedValid (); }));
3727
+ assert (any_chain ([](auto chainstate) { return !chainstate->reliesOnAssumedValid (); }));
3728
+
3729
+ first_assumed_valid_height = height;
3730
+ break ;
3731
+ }
3732
+ }
3733
+
3712
3734
for (const std::pair<int , CBlockIndex*>& item : vSortedByHeight)
3713
3735
{
3714
3736
if (ShutdownRequested ()) return false ;
3715
3737
CBlockIndex* pindex = item.second ;
3716
3738
pindex->nChainWork = (pindex->pprev ? pindex->pprev ->nChainWork : 0 ) + GetBlockProof (*pindex);
3717
3739
pindex->nTimeMax = (pindex->pprev ? std::max (pindex->pprev ->nTimeMax , pindex->nTime ) : pindex->nTime );
3718
- // We can link the chain of blocks for which we've received transactions at some point.
3740
+
3741
+ // We can link the chain of blocks for which we've received transactions at some point, or
3742
+ // blocks that are assumed-valid on the basis of snapshot load (see
3743
+ // PopulateAndValidateSnapshot()).
3719
3744
// Pruned nodes may have deleted the block.
3720
3745
if (pindex->nTx > 0 ) {
3721
3746
if (pindex->pprev ) {
3722
- if (pindex->pprev ->HaveTxsDownloaded () ) {
3747
+ if (pindex->pprev ->nChainTx > 0 ) {
3723
3748
pindex->nChainTx = pindex->pprev ->nChainTx + pindex->nTx ;
3724
3749
} else {
3725
3750
pindex->nChainTx = 0 ;
@@ -3736,7 +3761,36 @@ bool BlockManager::LoadBlockIndex(
3736
3761
if (pindex->IsAssumedValid () ||
3737
3762
(pindex->IsValid (BLOCK_VALID_TRANSACTIONS) &&
3738
3763
(pindex->HaveTxsDownloaded () || pindex->pprev == nullptr ))) {
3739
- block_index_candidates.insert (pindex);
3764
+
3765
+ // Fill each chainstate's block candidate set. Only add assumed-valid
3766
+ // blocks to the tip candidate set if the chainstate is allowed to rely on
3767
+ // assumed-valid blocks.
3768
+ //
3769
+ // If all setBlockIndexCandidates contained the assumed-valid blocks, the
3770
+ // background chainstate's ActivateBestChain() call would add assumed-valid
3771
+ // blocks to the chain (based on how FindMostWorkChain() works). Obviously
3772
+ // we don't want this since the purpose of the background validation chain
3773
+ // is to validate assued-valid blocks.
3774
+ //
3775
+ // Note: This is considering all blocks whose height is greater or equal to
3776
+ // the first assumed-valid block to be assumed-valid blocks, and excluding
3777
+ // them from the background chainstate's setBlockIndexCandidates set. This
3778
+ // does mean that some blocks which are not technically assumed-valid
3779
+ // (later blocks on a fork beginning before the first assumed-valid block)
3780
+ // might not get added to the the background chainstate, but this is ok,
3781
+ // because they will still be attached to the active chainstate if they
3782
+ // actually contain more work.
3783
+ //
3784
+ // Instad of this height-based approach, an earlier attempt was made at
3785
+ // detecting "holistically" whether the block index under consideration
3786
+ // relied on an assumed-valid ancestor, but this proved to be too slow to
3787
+ // be practical.
3788
+ for (CChainState* chainstate : chainman.GetAll ()) {
3789
+ if (chainstate->reliesOnAssumedValid () ||
3790
+ pindex->nHeight < first_assumed_valid_height) {
3791
+ chainstate->setBlockIndexCandidates .insert (pindex);
3792
+ }
3793
+ }
3740
3794
}
3741
3795
if (pindex->nStatus & BLOCK_FAILED_MASK && (!pindexBestInvalid || pindex->nChainWork > pindexBestInvalid->nChainWork ))
3742
3796
pindexBestInvalid = pindex;
@@ -3760,11 +3814,9 @@ void BlockManager::Unload() {
3760
3814
m_block_index.clear ();
3761
3815
}
3762
3816
3763
- bool BlockManager::LoadBlockIndexDB (std::set<CBlockIndex*, CBlockIndexWorkComparator>& setBlockIndexCandidates )
3817
+ bool BlockManager::LoadBlockIndexDB (ChainstateManager& chainman )
3764
3818
{
3765
- if (!LoadBlockIndex (
3766
- ::Params ().GetConsensus(),
3767
- setBlockIndexCandidates)) {
3819
+ if (!LoadBlockIndex (::Params ().GetConsensus (), chainman)) {
3768
3820
return false ;
3769
3821
}
3770
3822
@@ -4110,7 +4162,7 @@ bool ChainstateManager::LoadBlockIndex()
4110
4162
// Load block index from databases
4111
4163
bool needs_init = fReindex ;
4112
4164
if (!fReindex ) {
4113
- bool ret = m_blockman.LoadBlockIndexDB (ActiveChainstate (). setBlockIndexCandidates );
4165
+ bool ret = m_blockman.LoadBlockIndexDB (* this );
4114
4166
if (!ret) return false ;
4115
4167
needs_init = m_blockman.m_block_index .empty ();
4116
4168
}
@@ -4999,7 +5051,14 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
4999
5051
5000
5052
// Fake various pieces of CBlockIndex state:
5001
5053
CBlockIndex* index = nullptr ;
5002
- for (int i = 0 ; i <= snapshot_chainstate.m_chain .Height (); ++i) {
5054
+
5055
+ // Don't make any modifications to the genesis block.
5056
+ // This is especially important because we don't want to erroneously
5057
+ // apply BLOCK_ASSUMED_VALID to genesis, which would happen if we didn't skip
5058
+ // it here (since it apparently isn't BLOCK_VALID_SCRIPTS).
5059
+ constexpr int AFTER_GENESIS_START{1 };
5060
+
5061
+ for (int i = AFTER_GENESIS_START; i <= snapshot_chainstate.m_chain .Height (); ++i) {
5003
5062
index = snapshot_chainstate.m_chain [i];
5004
5063
5005
5064
// Fake nTx so that LoadBlockIndex() loads assumed-valid CBlockIndex
@@ -5008,7 +5067,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
5008
5067
index->nTx = 1 ;
5009
5068
}
5010
5069
// Fake nChainTx so that GuessVerificationProgress reports accurately
5011
- index->nChainTx = index->pprev ? index-> pprev -> nChainTx + index->nTx : 1 ;
5070
+ index->nChainTx = index->pprev -> nChainTx + index->nTx ;
5012
5071
5013
5072
// Mark unvalidated block index entries beneath the snapshot base block as assumed-valid.
5014
5073
if (!index->IsValid (BLOCK_VALID_SCRIPTS)) {
@@ -5019,7 +5078,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
5019
5078
5020
5079
// Fake BLOCK_OPT_WITNESS so that CChainState::NeedsRedownload()
5021
5080
// won't ask to rewind the entire assumed-valid chain on startup.
5022
- if (index-> pprev && DeploymentActiveAt (*index, ::Params ().GetConsensus (), Consensus::DEPLOYMENT_SEGWIT)) {
5081
+ if (DeploymentActiveAt (*index, ::Params ().GetConsensus (), Consensus::DEPLOYMENT_SEGWIT)) {
5023
5082
index->nStatus |= BLOCK_OPT_WITNESS;
5024
5083
}
5025
5084
0 commit comments