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.
This commit is contained in:
parent
ecc3c4a019
commit
a3ae8e6873
1 changed files with 13 additions and 0 deletions
|
@ -144,6 +144,12 @@ private:
|
||||||
*/
|
*/
|
||||||
std::set<CBlockIndex*> g_failed_blocks;
|
std::set<CBlockIndex*> g_failed_blocks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the ChainState CriticalSection
|
||||||
|
* A lock that must be held when modifying this ChainState - held in ActivateBestChain()
|
||||||
|
*/
|
||||||
|
CCriticalSection m_cs_chainstate;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CChain chainActive;
|
CChain chainActive;
|
||||||
BlockMap mapBlockIndex;
|
BlockMap mapBlockIndex;
|
||||||
|
@ -2542,6 +2548,7 @@ void CChainState::PruneBlockIndexCandidates() {
|
||||||
bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
|
bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
|
||||||
const CBlockIndex *pindexOldTip = chainActive.Tip();
|
const CBlockIndex *pindexOldTip = chainActive.Tip();
|
||||||
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
|
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
|
||||||
|
|
||||||
|
@ -2653,6 +2660,12 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
|
||||||
// sanely for performance or correctness!
|
// sanely for performance or correctness!
|
||||||
AssertLockNotHeld(cs_main);
|
AssertLockNotHeld(cs_main);
|
||||||
|
|
||||||
|
// ABC maintains a fair degree of expensive-to-calculate internal state
|
||||||
|
// because this function periodically releases cs_main so that it does not lock up other threads for too long
|
||||||
|
// during large connects - and to allow for e.g. the callback queue to drain
|
||||||
|
// we use m_cs_chainstate to enforce mutual exclusion so that only one caller may execute this function at a time
|
||||||
|
LOCK(m_cs_chainstate);
|
||||||
|
|
||||||
CBlockIndex *pindexMostWork = nullptr;
|
CBlockIndex *pindexMostWork = nullptr;
|
||||||
CBlockIndex *pindexNewTip = nullptr;
|
CBlockIndex *pindexNewTip = nullptr;
|
||||||
int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT);
|
int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT);
|
||||||
|
|
Loading…
Reference in a new issue