mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-25 18:53:23 -03:00
Release cs_main during InvalidateBlock iterations
This commit is contained in:
parent
9b1ff5c742
commit
9bb32eb571
1 changed files with 52 additions and 42 deletions
|
@ -2789,64 +2789,74 @@ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIn
|
||||||
|
|
||||||
bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
|
bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex)
|
||||||
{
|
{
|
||||||
LOCK(cs_main);
|
CBlockIndex* to_mark_failed = pindex;
|
||||||
|
|
||||||
// We first disconnect backwards and then mark the blocks as invalid.
|
|
||||||
// This prevents a case where pruned nodes may fail to invalidateblock
|
|
||||||
// and be left unable to start as they have no tip candidates (as there
|
|
||||||
// are no blocks that meet the "have data and are not invalid per
|
|
||||||
// nStatus" criteria for inclusion in setBlockIndexCandidates).
|
|
||||||
|
|
||||||
bool pindex_was_in_chain = false;
|
bool pindex_was_in_chain = false;
|
||||||
CBlockIndex *invalid_walk_tip = chainActive.Tip();
|
|
||||||
|
|
||||||
DisconnectedBlockTransactions disconnectpool;
|
// Disconnect (descendants of) pindex, and mark them invalid.
|
||||||
while (chainActive.Contains(pindex)) {
|
while (true) {
|
||||||
|
if (ShutdownRequested()) break;
|
||||||
|
|
||||||
|
LOCK(cs_main);
|
||||||
|
if (!chainActive.Contains(pindex)) break;
|
||||||
pindex_was_in_chain = true;
|
pindex_was_in_chain = true;
|
||||||
|
CBlockIndex *invalid_walk_tip = chainActive.Tip();
|
||||||
|
|
||||||
// ActivateBestChain considers blocks already in chainActive
|
// ActivateBestChain considers blocks already in chainActive
|
||||||
// unconditionally valid already, so force disconnect away from it.
|
// unconditionally valid already, so force disconnect away from it.
|
||||||
if (!DisconnectTip(state, chainparams, &disconnectpool)) {
|
DisconnectedBlockTransactions disconnectpool;
|
||||||
// It's probably hopeless to try to make the mempool consistent
|
bool ret = DisconnectTip(state, chainparams, &disconnectpool);
|
||||||
// here if DisconnectTip failed, but we can try.
|
// DisconnectTip will add transactions to disconnectpool.
|
||||||
UpdateMempoolForReorg(disconnectpool, false);
|
// Adjust the mempool to be consistent with the new tip, adding
|
||||||
return false;
|
// transactions back to the mempool if disconnecting was succesful.
|
||||||
}
|
UpdateMempoolForReorg(disconnectpool, /* fAddToMempool = */ ret);
|
||||||
}
|
if (!ret) return false;
|
||||||
|
assert(invalid_walk_tip->pprev == chainActive.Tip());
|
||||||
|
|
||||||
// Now mark the blocks we just disconnected as descendants invalid
|
// We immediately mark the disconnected blocks as invalid.
|
||||||
// (note this may not be all descendants).
|
// This prevents a case where pruned nodes may fail to invalidateblock
|
||||||
while (pindex_was_in_chain && invalid_walk_tip != pindex) {
|
// and be left unable to start as they have no tip candidates (as there
|
||||||
|
// are no blocks that meet the "have data and are not invalid per
|
||||||
|
// nStatus" criteria for inclusion in setBlockIndexCandidates).
|
||||||
invalid_walk_tip->nStatus |= BLOCK_FAILED_CHILD;
|
invalid_walk_tip->nStatus |= BLOCK_FAILED_CHILD;
|
||||||
setDirtyBlockIndex.insert(invalid_walk_tip);
|
setDirtyBlockIndex.insert(invalid_walk_tip);
|
||||||
setBlockIndexCandidates.erase(invalid_walk_tip);
|
setBlockIndexCandidates.erase(invalid_walk_tip);
|
||||||
invalid_walk_tip = invalid_walk_tip->pprev;
|
setBlockIndexCandidates.insert(invalid_walk_tip->pprev);
|
||||||
|
|
||||||
|
// If we abort invalidation after this iteration, make sure
|
||||||
|
// the last disconnected block gets marked failed (rather than
|
||||||
|
// just child of failed)
|
||||||
|
to_mark_failed = invalid_walk_tip;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the block itself as invalid.
|
{
|
||||||
pindex->nStatus |= BLOCK_FAILED_VALID;
|
// Mark pindex (or the last disconnected block) as invalid, regardless of whether it was in the main chain or not.
|
||||||
setDirtyBlockIndex.insert(pindex);
|
LOCK(cs_main);
|
||||||
setBlockIndexCandidates.erase(pindex);
|
if (chainActive.Contains(to_mark_failed)) {
|
||||||
m_failed_blocks.insert(pindex);
|
// If the to-be-marked invalid block is in the active chain, something is interfering and we can't proceed.
|
||||||
|
return false;
|
||||||
// DisconnectTip will add transactions to disconnectpool; try to add these
|
|
||||||
// back to the mempool.
|
|
||||||
UpdateMempoolForReorg(disconnectpool, true);
|
|
||||||
|
|
||||||
// The resulting new best tip may not be in setBlockIndexCandidates anymore, so
|
|
||||||
// add it again.
|
|
||||||
BlockMap::iterator it = mapBlockIndex.begin();
|
|
||||||
while (it != mapBlockIndex.end()) {
|
|
||||||
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {
|
|
||||||
setBlockIndexCandidates.insert(it->second);
|
|
||||||
}
|
}
|
||||||
it++;
|
|
||||||
}
|
|
||||||
|
|
||||||
InvalidChainFound(pindex);
|
to_mark_failed->nStatus |= BLOCK_FAILED_VALID;
|
||||||
|
setDirtyBlockIndex.insert(to_mark_failed);
|
||||||
|
setBlockIndexCandidates.erase(to_mark_failed);
|
||||||
|
m_failed_blocks.insert(to_mark_failed);
|
||||||
|
|
||||||
|
// The resulting new best tip may not be in setBlockIndexCandidates anymore, so
|
||||||
|
// add it again.
|
||||||
|
BlockMap::iterator it = mapBlockIndex.begin();
|
||||||
|
while (it != mapBlockIndex.end()) {
|
||||||
|
if (it->second->IsValid(BLOCK_VALID_TRANSACTIONS) && it->second->HaveTxsDownloaded() && !setBlockIndexCandidates.value_comp()(it->second, chainActive.Tip())) {
|
||||||
|
setBlockIndexCandidates.insert(it->second);
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
|
||||||
|
InvalidChainFound(to_mark_failed);
|
||||||
|
}
|
||||||
|
|
||||||
// Only notify about a new block tip if the active chain was modified.
|
// Only notify about a new block tip if the active chain was modified.
|
||||||
if (pindex_was_in_chain) {
|
if (pindex_was_in_chain) {
|
||||||
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
|
uiInterface.NotifyBlockTip(IsInitialBlockDownload(), to_mark_failed->pprev);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue