Skip to content

Commit ecc3c4a

Browse files
TheBlueMattskeees
authored andcommitted
Do not unlock cs_main in ABC unless we've actually made progress.
Technically, some internal datastructures may be in an inconsistent state if we do this, though there are no known bugs there. Still, for future safety, its much better to only unlock cs_main if we've made progress (not just tried a reorg which may make progress).
1 parent 8b262eb commit ecc3c4a

File tree

2 files changed

+42
-29
lines changed

2 files changed

+42
-29
lines changed

src/validation.cpp

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2666,45 +2666,53 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
26662666
SyncWithValidationInterfaceQueue();
26672667
}
26682668

2669-
const CBlockIndex *pindexFork;
2670-
bool fInitialDownload;
26712669
{
26722670
LOCK(cs_main);
2673-
ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked
2671+
CBlockIndex* starting_tip = chainActive.Tip();
2672+
bool blocks_connected = false;
2673+
do {
2674+
// We absolutely may not unlock cs_main until we've made forward progress
2675+
// (with the exception of shutdown due to hardware issues, low disk space, etc).
2676+
ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked
2677+
2678+
if (pindexMostWork == nullptr) {
2679+
pindexMostWork = FindMostWorkChain();
2680+
}
26742681

2675-
CBlockIndex *pindexOldTip = chainActive.Tip();
2676-
if (pindexMostWork == nullptr) {
2677-
pindexMostWork = FindMostWorkChain();
2678-
}
2682+
// Whether we have anything to do at all.
2683+
if (pindexMostWork == nullptr || pindexMostWork == chainActive.Tip()) {
2684+
break;
2685+
}
26792686

2680-
// Whether we have anything to do at all.
2681-
if (pindexMostWork == nullptr || pindexMostWork == chainActive.Tip())
2682-
return true;
2687+
bool fInvalidFound = false;
2688+
std::shared_ptr<const CBlock> nullBlockPtr;
2689+
if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace))
2690+
return false;
2691+
blocks_connected = true;
26832692

2684-
bool fInvalidFound = false;
2685-
std::shared_ptr<const CBlock> nullBlockPtr;
2686-
if (!ActivateBestChainStep(state, chainparams, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace))
2687-
return false;
2693+
if (fInvalidFound) {
2694+
// Wipe cache, we may need another branch now.
2695+
pindexMostWork = nullptr;
2696+
}
2697+
pindexNewTip = chainActive.Tip();
26882698

2689-
if (fInvalidFound) {
2690-
// Wipe cache, we may need another branch now.
2691-
pindexMostWork = nullptr;
2692-
}
2693-
pindexNewTip = chainActive.Tip();
2694-
pindexFork = chainActive.FindFork(pindexOldTip);
2695-
fInitialDownload = IsInitialBlockDownload();
2699+
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
2700+
assert(trace.pblock && trace.pindex);
2701+
GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
2702+
}
2703+
} while (!chainActive.Tip() || (starting_tip && CBlockIndexWorkComparator()(chainActive.Tip(), starting_tip)));
2704+
if (!blocks_connected) return true;
26962705

2697-
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
2698-
assert(trace.pblock && trace.pindex);
2699-
GetMainSignals().BlockConnected(trace.pblock, trace.pindex, trace.conflictedTxs);
2700-
}
2706+
const CBlockIndex* pindexFork = chainActive.FindFork(starting_tip);
2707+
bool fInitialDownload = IsInitialBlockDownload();
27012708

27022709
// Notify external listeners about the new tip.
27032710
// Enqueue while holding cs_main to ensure that UpdatedBlockTip is called in the order in which blocks are connected
2704-
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
2705-
2706-
// Always notify the UI if a new block tip was connected
27072711
if (pindexFork != pindexNewTip) {
2712+
// Notify ValidationInterface subscribers
2713+
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
2714+
2715+
// Always notify the UI if a new block tip was connected
27082716
uiInterface.NotifyBlockTip(fInitialDownload, pindexNewTip);
27092717
}
27102718
}
@@ -2728,6 +2736,7 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
27282736

27292737
return true;
27302738
}
2739+
27312740
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {
27322741
return g_chainstate.ActivateBestChain(state, chainparams, std::move(pblock));
27332742
}

src/validationinterface.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ class CValidationInterface {
6161
*/
6262
~CValidationInterface() = default;
6363
/**
64-
* Notifies listeners of updated block chain tip
64+
* Notifies listeners when the block chain tip advances.
65+
*
66+
* When multiple blocks are connected at once, UpdatedBlockTip will be called on the final tip
67+
* but may not be called on every intermediate tip. If the latter behavior is desired,
68+
* subscribe to BlockConnected() instead.
6569
*
6670
* Called on a background thread.
6771
*/

0 commit comments

Comments
 (0)