Set the same best tip on restart if two candidates have the same work

Before this, if we had two (or more) same work tip candidates and restarted our node,
it could be the case that the block set as tip after bootstrap didn't match the one
before stopping. That's because the work and `nSequenceId` of both block will be the same
(the latter is only kept in memory), so the active chain after restart would have depended
on what tip candidate was loaded first.

This makes sure that we are consistent over reboots.
This commit is contained in:
Sergi Delgado Segura
2024-03-14 13:48:43 -04:00
parent 5370bed21e
commit 8b91883a23
4 changed files with 26 additions and 8 deletions

View File

@@ -4680,7 +4680,7 @@ bool Chainstate::LoadChainTip()
AssertLockHeld(cs_main);
const CCoinsViewCache& coins_cache = CoinsTip();
assert(!coins_cache.GetBestBlock().IsNull()); // Never called when the coins view is empty
const CBlockIndex* tip = m_chain.Tip();
CBlockIndex* tip = m_chain.Tip();
if (tip && tip->GetBlockHash() == coins_cache.GetBestBlock()) {
return true;
@@ -4692,6 +4692,20 @@ bool Chainstate::LoadChainTip()
return false;
}
m_chain.SetTip(*pindex);
tip = m_chain.Tip();
// Make sure our chain tip before shutting down scores better than any other candidate
// to maintain a consistent best tip over reboots in case of a tie.
auto target = tip;
while (target) {
target->nSequenceId = 0;
target = target->pprev;
}
// Block index candidates are loaded before the chain tip, so we need to replace this entry
// Otherwise the scoring will be based on the memory address location instead of the nSequenceId
setBlockIndexCandidates.erase(tip);
TryAddBlockIndexCandidate(tip);
PruneBlockIndexCandidates();
tip = m_chain.Tip();
@@ -5343,7 +5357,7 @@ void ChainstateManager::CheckBlockIndex() const
}
}
}
if (!pindex->HaveNumChainTxs()) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
if (!pindex->HaveNumChainTxs()) assert(pindex->nSequenceId <= 1); // nSequenceId can't be set higher than 1 for blocks that aren't linked (negative is used for preciousblock, 0 for active chain)
// VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).
// HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
if (!m_blockman.m_have_pruned) {