aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJesse Cohen <jc@jc.lol>2018-05-10 15:57:16 -0400
committerMarcoFalke <falke.marco@gmail.com>2018-05-24 13:55:57 -0400
commitbb79aaf93af93d5f9f5097cff4fbb2791af86875 (patch)
tree39d1687e8d28107e254fd68d8c2c30a36ce11f08 /src
parent0948153ea62ff4921daef326da0fddb8425cd866 (diff)
downloadbitcoin-bb79aaf93af93d5f9f5097cff4fbb2791af86875.tar.xz
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. Github-Pull: #13023 Rebased-From: a3ae8e68739023e5dba9e5cb190e707ed4603316
Diffstat (limited to 'src')
-rw-r--r--src/validation.cpp13
1 files changed, 13 insertions, 0 deletions
diff --git a/src/validation.cpp b/src/validation.cpp
index 6866605f27..7c4c84c3f9 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -144,6 +144,12 @@ private:
*/
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:
CChain chainActive;
BlockMap mapBlockIndex;
@@ -2451,6 +2457,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)
{
AssertLockHeld(cs_main);
+
const CBlockIndex *pindexOldTip = chainActive.Tip();
const CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
@@ -2562,6 +2569,12 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
// sanely for performance or correctness!
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 *pindexNewTip = nullptr;
int nStopAtHeight = gArgs.GetArg("-stopatheight", DEFAULT_STOPATHEIGHT);