Skip to content

Commit a3ae8e6

Browse files
committed
Fix concurrency-related bugs in ActivateBestChain
If multiple threads are invoking ActivateBestChain, it was possible to have them working towards different tips, and we could arrive at a less work tip than we should. Fix this by introducing a ChainState lock which must be held for the entire duration of ActivateBestChain to enforce exclusion in ABC.
1 parent ecc3c4a commit a3ae8e6

File tree

1 file changed

+13
-0
lines changed

1 file changed

+13
-0
lines changed

src/validation.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ class CChainState {
144144
*/
145145
std::set<CBlockIndex*> g_failed_blocks;
146146

147+
/**
148+
* the ChainState CriticalSection
149+
* A lock that must be held when modifying this ChainState - held in ActivateBestChain()
150+
*/
151+
CCriticalSection m_cs_chainstate;
152+
147153
public:
148154
CChain chainActive;
149155
BlockMap mapBlockIndex;
@@ -2542,6 +2548,7 @@ void CChainState::PruneBlockIndexCandidates() {
25422548
bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
25432549
{
25442550
AssertLockHeld(cs_main);
2551+
25452552
const CBlockIndex *pindexOldTip = chainActive.Tip();
25462553
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
25472554

@@ -2653,6 +2660,12 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
26532660
// sanely for performance or correctness!
26542661
AssertLockNotHeld(cs_main);
26552662

2663+
// ABC maintains a fair degree of expensive-to-calculate internal state
2664+
// because this function periodically releases cs_main so that it does not lock up other threads for too long
2665+
// during large connects - and to allow for e.g. the callback queue to drain
2666+
// we use m_cs_chainstate to enforce mutual exclusion so that only one caller may execute this function at a time
2667+
LOCK(m_cs_chainstate);
2668+
26562669
CBlockIndex *pindexMostWork = nullptr;
26572670
CBlockIndex *pindexNewTip = nullptr;
26582671
int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT);

0 commit comments

Comments
 (0)