@@ -3193,7 +3193,8 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
3193
3193
// that the best block hash is non-null.
3194
3194
if (m_chainman.m_interrupt ) break ;
3195
3195
} while (pindexNewTip != pindexMostWork);
3196
- CheckBlockIndex ();
3196
+
3197
+ m_chainman.CheckBlockIndex ();
3197
3198
3198
3199
// Write changes periodically to disk, after relay.
3199
3200
if (!FlushStateToDisk (state, FlushStateMode::PERIODIC)) {
@@ -3339,7 +3340,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
3339
3340
to_mark_failed = invalid_walk_tip;
3340
3341
}
3341
3342
3342
- CheckBlockIndex ();
3343
+ m_chainman. CheckBlockIndex ();
3343
3344
3344
3345
{
3345
3346
LOCK (cs_main);
@@ -3882,7 +3883,7 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>&
3882
3883
for (const CBlockHeader& header : headers) {
3883
3884
CBlockIndex *pindex = nullptr ; // Use a temp pindex instead of ppindex to avoid a const_cast
3884
3885
bool accepted{AcceptBlockHeader (header, state, &pindex, min_pow_checked)};
3885
- ActiveChainstate (). CheckBlockIndex ();
3886
+ CheckBlockIndex ();
3886
3887
3887
3888
if (!accepted) {
3888
3889
return false ;
@@ -3940,7 +3941,7 @@ bool ChainstateManager::AcceptBlock(const std::shared_ptr<const CBlock>& pblock,
3940
3941
CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy;
3941
3942
3942
3943
bool accepted_header{AcceptBlockHeader (block, state, &pindex, min_pow_checked)};
3943
- ActiveChainstate (). CheckBlockIndex ();
3944
+ CheckBlockIndex ();
3944
3945
3945
3946
if (!accepted_header)
3946
3947
return false ;
@@ -4017,7 +4018,7 @@ bool ChainstateManager::AcceptBlock(const std::shared_ptr<const CBlock>& pblock,
4017
4018
// background validation yet).
4018
4019
ActiveChainstate ().FlushStateToDisk (state, FlushStateMode::NONE);
4019
4020
4020
- ActiveChainstate (). CheckBlockIndex ();
4021
+ CheckBlockIndex ();
4021
4022
4022
4023
return true ;
4023
4024
}
@@ -4676,9 +4677,9 @@ void ChainstateManager::LoadExternalBlockFile(
4676
4677
LogPrintf (" Loaded %i blocks from external file in %dms\n " , nLoaded, Ticks<std::chrono::milliseconds>(SteadyClock::now () - start));
4677
4678
}
4678
4679
4679
- void Chainstate ::CheckBlockIndex ()
4680
+ void ChainstateManager ::CheckBlockIndex ()
4680
4681
{
4681
- if (!m_chainman. ShouldCheckBlockIndex ()) {
4682
+ if (!ShouldCheckBlockIndex ()) {
4682
4683
return ;
4683
4684
}
4684
4685
@@ -4687,7 +4688,7 @@ void Chainstate::CheckBlockIndex()
4687
4688
// During a reindex, we read the genesis block and call CheckBlockIndex before ActivateBestChain,
4688
4689
// so we have the genesis block in m_blockman.m_block_index but no active chain. (A few of the
4689
4690
// tests when iterating the block tree require that m_chain has been initialized.)
4690
- if (m_chain .Height () < 0 ) {
4691
+ if (ActiveChain () .Height () < 0 ) {
4691
4692
assert (m_blockman.m_block_index .size () <= 1 );
4692
4693
return ;
4693
4694
}
@@ -4751,8 +4752,12 @@ void Chainstate::CheckBlockIndex()
4751
4752
// Begin: actual consistency checks.
4752
4753
if (pindex->pprev == nullptr ) {
4753
4754
// Genesis block checks.
4754
- assert (pindex->GetBlockHash () == m_chainman.GetConsensus ().hashGenesisBlock ); // Genesis block's hash must match.
4755
- assert (pindex == m_chain.Genesis ()); // The current active chain's genesis block must be this block.
4755
+ assert (pindex->GetBlockHash () == GetConsensus ().hashGenesisBlock ); // Genesis block's hash must match.
4756
+ for (auto c : GetAll ()) {
4757
+ if (c->m_chain .Genesis () != nullptr ) {
4758
+ assert (pindex == c->m_chain .Genesis ()); // The chain's genesis block must be this block.
4759
+ }
4760
+ }
4756
4761
}
4757
4762
if (!pindex->HaveTxsDownloaded ()) assert (pindex->nSequenceId <= 0 ); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
4758
4763
// VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).
@@ -4798,27 +4803,32 @@ void Chainstate::CheckBlockIndex()
4798
4803
// Checks for not-invalid blocks.
4799
4804
assert ((pindex->nStatus & BLOCK_FAILED_MASK) == 0 ); // The failed mask cannot be set for blocks without invalid parents.
4800
4805
}
4801
- if (!CBlockIndexWorkComparator ()(pindex, m_chain.Tip ()) && pindexFirstNeverProcessed == nullptr ) {
4802
- if (pindexFirstInvalid == nullptr ) {
4803
- const bool is_active = this == &m_chainman.ActiveChainstate ();
4804
-
4805
- // If this block sorts at least as good as the current tip and
4806
- // is valid and we have all data for its parents, it must be in
4807
- // setBlockIndexCandidates. m_chain.Tip() must also be there
4808
- // even if some data has been pruned.
4809
- //
4810
- // Don't perform this check for the background chainstate since
4811
- // its setBlockIndexCandidates shouldn't have some entries (i.e. those past the
4812
- // snapshot block) which do exist in the block index for the active chainstate.
4813
- if (is_active && (pindexFirstMissing == nullptr || pindex == m_chain.Tip ())) {
4814
- assert (setBlockIndexCandidates.count (pindex));
4806
+ // Chainstate-specific checks on setBlockIndexCandidates
4807
+ for (auto c : GetAll ()) {
4808
+ if (c->m_chain .Tip () == nullptr ) continue ;
4809
+ if (!CBlockIndexWorkComparator ()(pindex, c->m_chain .Tip ()) && pindexFirstNeverProcessed == nullptr ) {
4810
+ if (pindexFirstInvalid == nullptr ) {
4811
+ const bool is_active = c == &ActiveChainstate ();
4812
+ // If this block sorts at least as good as the current tip and
4813
+ // is valid and we have all data for its parents, it must be in
4814
+ // setBlockIndexCandidates. m_chain.Tip() must also be there
4815
+ // even if some data has been pruned.
4816
+ //
4817
+ if ((pindexFirstMissing == nullptr || pindex == c->m_chain .Tip ())) {
4818
+ // The active chainstate should always have this block
4819
+ // as a candidate, but a background chainstate should
4820
+ // only have it if it is an ancestor of the snapshot base.
4821
+ if (is_active || GetSnapshotBaseBlock ()->GetAncestor (pindex->nHeight ) == pindex) {
4822
+ assert (c->setBlockIndexCandidates .count (pindex));
4823
+ }
4824
+ }
4825
+ // If some parent is missing, then it could be that this block was in
4826
+ // setBlockIndexCandidates but had to be removed because of the missing data.
4827
+ // In this case it must be in m_blocks_unlinked -- see test below.
4815
4828
}
4816
- // If some parent is missing, then it could be that this block was in
4817
- // setBlockIndexCandidates but had to be removed because of the missing data.
4818
- // In this case it must be in m_blocks_unlinked -- see test below.
4829
+ } else { // If this block sorts worse than the current tip or some ancestor's block has never been seen, it cannot be in setBlockIndexCandidates.
4830
+ assert (c->setBlockIndexCandidates .count (pindex) == 0 );
4819
4831
}
4820
- } else { // If this block sorts worse than the current tip or some ancestor's block has never been seen, it cannot be in setBlockIndexCandidates.
4821
- assert (setBlockIndexCandidates.count (pindex) == 0 );
4822
4832
}
4823
4833
// Check whether this block is in m_blocks_unlinked.
4824
4834
std::pair<std::multimap<CBlockIndex*,CBlockIndex*>::iterator,std::multimap<CBlockIndex*,CBlockIndex*>::iterator> rangeUnlinked = m_blockman.m_blocks_unlinked .equal_range (pindex->pprev );
@@ -4846,16 +4856,16 @@ void Chainstate::CheckBlockIndex()
4846
4856
// - we tried switching to that descendant but were missing
4847
4857
// data for some intermediate block between m_chain and the
4848
4858
// tip.
4849
- // So if this block is itself better than m_chain.Tip() and it wasn't in
4859
+ // So if this block is itself better than any m_chain.Tip() and it wasn't in
4850
4860
// setBlockIndexCandidates, then it must be in m_blocks_unlinked.
4851
- if (! CBlockIndexWorkComparator ()(pindex, m_chain. Tip ()) && setBlockIndexCandidates. count (pindex) == 0 ) {
4852
- if (pindexFirstInvalid == nullptr && pindexFirstAssumeValid == nullptr ) {
4853
- // If this is a chain based on an assumeutxo snapshot, then
4854
- // this block could either be in mapBlocksUnlinked or in
4855
- // setBlockIndexCandidates; it may take a call to
4856
- // FindMostWorkChain() to figure out whether all the blocks
4857
- // between the tip and this block are actually available.
4858
- assert (foundInUnlinked);
4861
+ for ( auto c : GetAll () ) {
4862
+ const bool is_active = c == & ActiveChainstate ();
4863
+ if (! CBlockIndexWorkComparator ()(pindex, c-> m_chain . Tip ()) && c-> setBlockIndexCandidates . count (pindex) == 0 ) {
4864
+ if (pindexFirstInvalid == nullptr ) {
4865
+ if (is_active || GetSnapshotBaseBlock ()-> GetAncestor (pindex-> nHeight ) == pindex) {
4866
+ assert (foundInUnlinked);
4867
+ }
4868
+ }
4859
4869
}
4860
4870
}
4861
4871
}
0 commit comments