mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-24 22:45:41 +01:00
Fix initialization of setBlockIndexCandidates when working with multiple chainstates
When using assumeutxo and multiple chainstates are active, the background chainstate should consider all HAVE_DATA blocks that are ancestors of the snapshotted block and that have more work than the tip as potential candidates.
This commit is contained in:
@@ -4432,62 +4432,19 @@ bool ChainstateManager::LoadBlockIndex()
|
||||
std::sort(vSortedByHeight.begin(), vSortedByHeight.end(),
|
||||
CBlockIndexHeightOnlyComparator());
|
||||
|
||||
// Find start of assumed-valid region.
|
||||
int first_assumed_valid_height = std::numeric_limits<int>::max();
|
||||
|
||||
for (const CBlockIndex* block : vSortedByHeight) {
|
||||
if (block->IsAssumedValid()) {
|
||||
auto chainstates = GetAll();
|
||||
|
||||
// If we encounter an assumed-valid block index entry, ensure that we have
|
||||
// one chainstate that tolerates assumed-valid entries and another that does
|
||||
// not (i.e. the background validation chainstate), since assumed-valid
|
||||
// entries should always be pending validation by a fully-validated chainstate.
|
||||
auto any_chain = [&](auto fnc) { return std::any_of(chainstates.cbegin(), chainstates.cend(), fnc); };
|
||||
assert(any_chain([](auto chainstate) { return chainstate->reliesOnAssumedValid(); }));
|
||||
assert(any_chain([](auto chainstate) { return !chainstate->reliesOnAssumedValid(); }));
|
||||
|
||||
first_assumed_valid_height = block->nHeight;
|
||||
LogPrintf("Saw first assumedvalid block at height %d (%s)\n",
|
||||
first_assumed_valid_height, block->ToString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (CBlockIndex* pindex : vSortedByHeight) {
|
||||
if (m_interrupt) return false;
|
||||
if (pindex->IsAssumedValid() ||
|
||||
// If we have an assumeutxo-based chainstate, then the snapshot
|
||||
// block will be a candidate for the tip, but it may not be
|
||||
// VALID_TRANSACTIONS (eg if we haven't yet downloaded the block),
|
||||
// so we special-case the snapshot block as a potential candidate
|
||||
// here.
|
||||
if (pindex == GetSnapshotBaseBlock() ||
|
||||
(pindex->IsValid(BLOCK_VALID_TRANSACTIONS) &&
|
||||
(pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))) {
|
||||
|
||||
// Fill each chainstate's block candidate set. Only add assumed-valid
|
||||
// blocks to the tip candidate set if the chainstate is allowed to rely on
|
||||
// assumed-valid blocks.
|
||||
//
|
||||
// If all setBlockIndexCandidates contained the assumed-valid blocks, the
|
||||
// background chainstate's ActivateBestChain() call would add assumed-valid
|
||||
// blocks to the chain (based on how FindMostWorkChain() works). Obviously
|
||||
// we don't want this since the purpose of the background validation chain
|
||||
// is to validate assued-valid blocks.
|
||||
//
|
||||
// Note: This is considering all blocks whose height is greater or equal to
|
||||
// the first assumed-valid block to be assumed-valid blocks, and excluding
|
||||
// them from the background chainstate's setBlockIndexCandidates set. This
|
||||
// does mean that some blocks which are not technically assumed-valid
|
||||
// (later blocks on a fork beginning before the first assumed-valid block)
|
||||
// might not get added to the background chainstate, but this is ok,
|
||||
// because they will still be attached to the active chainstate if they
|
||||
// actually contain more work.
|
||||
//
|
||||
// Instead of this height-based approach, an earlier attempt was made at
|
||||
// detecting "holistically" whether the block index under consideration
|
||||
// relied on an assumed-valid ancestor, but this proved to be too slow to
|
||||
// be practical.
|
||||
for (Chainstate* chainstate : GetAll()) {
|
||||
if (chainstate->reliesOnAssumedValid() ||
|
||||
pindex->nHeight < first_assumed_valid_height) {
|
||||
chainstate->setBlockIndexCandidates.insert(pindex);
|
||||
}
|
||||
chainstate->TryAddBlockIndexCandidate(pindex);
|
||||
}
|
||||
}
|
||||
if (pindex->nStatus & BLOCK_FAILED_MASK && (!m_best_invalid || pindex->nChainWork > m_best_invalid->nChainWork)) {
|
||||
|
||||
Reference in New Issue
Block a user