From 666ff7bff94ac90a21b9e440741a017f42c692c0 Mon Sep 17 00:00:00 2001 From: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Date: Sat, 10 Sep 2022 02:15:39 +0300 Subject: [PATCH] merge bitcoin#14193: Add missing mempool locks Co-authored-by: "UdjinM6 " --- src/governance/governance.cpp | 12 ++- src/governance/object.cpp | 5 +- src/net_processing.cpp | 2 +- src/rpc/governance.cpp | 2 +- src/rpc/mining.cpp | 3 +- src/test/validation_block_tests.cpp | 157 +++++++++++++++++++++++++++- src/txmempool.cpp | 20 ++-- src/txmempool.h | 36 +++---- src/validation.cpp | 18 ++-- src/validation.h | 7 +- 10 files changed, 206 insertions(+), 56 deletions(-) diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 4a351f8257..b023ea707c 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -142,7 +142,8 @@ void CGovernanceManager::ProcessMessage(CNode* pfrom, const std::string& msg_typ return; } - LOCK2(cs_main, cs); + LOCK2(cs_main, ::mempool.cs); // Lock mempool because of GetTransaction deep inside + LOCK(cs); if (mapObjects.count(nHash) || mapPostponedObjects.count(nHash) || mapErasedGovernanceObjects.count(nHash)) { // TODO - print error code? what if it's GOVOBJ_ERROR_IMMATURE? @@ -261,7 +262,8 @@ void CGovernanceManager::AddGovernanceObject(CGovernanceObject& govobj, CConnman govobj.UpdateSentinelVariables(); //this sets local vars in object - LOCK2(cs_main, cs); + LOCK2(cs_main, ::mempool.cs); // Lock mempool because of GetTransaction deep inside + LOCK(cs); std::string strError; // MAKE SURE THIS OBJECT IS OK @@ -320,7 +322,8 @@ void CGovernanceManager::UpdateCachesAndClean() std::vector vecDirtyHashes = mmetaman.GetAndClearDirtyGovernanceObjectHashes(); - LOCK2(cs_main, cs); + LOCK2(cs_main, ::mempool.cs); // Lock mempool because of GetTransaction deep inside + LOCK(cs); for (const uint256& nHash : vecDirtyHashes) { auto it = mapObjects.find(nHash); @@ -835,7 +838,8 @@ void CGovernanceManager::CheckPostponedObjects(CConnman& connman) { if (!masternodeSync.IsSynced()) return; - LOCK2(cs_main, cs); + LOCK2(cs_main, ::mempool.cs); // Lock mempool because of GetTransaction deep inside + LOCK(cs); // Check postponed proposals for (auto it = mapPostponedObjects.begin(); it != mapPostponedObjects.end();) { diff --git a/src/governance/object.cpp b/src/governance/object.cpp index d8b3b67782..49ae94ec80 100644 --- a/src/governance/object.cpp +++ b/src/governance/object.cpp @@ -438,7 +438,7 @@ UniValue CGovernanceObject::ToJson() const void CGovernanceObject::UpdateLocalValidity() { - LOCK(cs_main); + AssertLockHeld(cs_main); // THIS DOES NOT CHECK COLLATERAL, THIS IS CHECKED UPON ORIGINAL ARRIVAL fCachedLocalValidity = IsValidLocally(strLocalValidityError, false); } @@ -526,6 +526,9 @@ CAmount CGovernanceObject::GetMinCollateralFee(bool fork_active) const bool CGovernanceObject::IsCollateralValid(std::string& strError, bool& fMissingConfirmations) const { + AssertLockHeld(cs_main); + AssertLockHeld(::mempool.cs); // because of GetTransaction + strError = ""; fMissingConfirmations = false; uint256 nExpectedHash = GetHash(); diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 452cfa2fb0..a9470f2c93 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -4629,7 +4629,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) // std::vector vInv; { - LOCK(pto->cs_inventory); + LOCK2(mempool.cs, pto->cs_inventory); size_t reserve = std::min(pto->setInventoryTxToSend.size(), INVENTORY_BROADCAST_MAX_PER_1MB_BLOCK * MaxBlockSize() / 1000000); reserve = std::max(reserve, pto->vInventoryBlockToSend.size()); diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index 996349e00c..22751687eb 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -392,7 +392,7 @@ static UniValue gobject_submit(const JSONRPCRequest& request) g_txindex->BlockUntilSyncedToCurrentChain(); } - LOCK(cs_main); + LOCK2(cs_main, ::mempool.cs); if (!govobj.IsValidLocally(strError, fMissingConfirmations, true) && !fMissingConfirmations) { LogPrintf("gobject(submit) -- Object submission rejected because object is not valid - hash = %s, strError = %s\n", strHash, strError); throw JSONRPCError(RPC_INTERNAL_ERROR, "Governance object is not valid - " + strHash + " - " + strError); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index e28aacfe8a..bbad597799 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -501,7 +501,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) nTransactionsUpdatedLastLP = nTransactionsUpdatedLast; } - // Release the wallet and main lock while waiting + // Release lock while waiting LEAVE_CRITICAL_SECTION(cs_main); { checktxtime = std::chrono::steady_clock::now() + std::chrono::minutes(1); @@ -512,6 +512,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) if (g_best_block_cv.wait_until(lock, checktxtime) == std::cv_status::timeout) { // Timeout: Check transactions for update + // without holding ::mempool.cs to avoid deadlocks if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) break; checktxtime += std::chrono::seconds(10); diff --git a/src/test/validation_block_tests.cpp b/src/test/validation_block_tests.cpp index 99d3c4beb8..f5d59fccb5 100644 --- a/src/test/validation_block_tests.cpp +++ b/src/test/validation_block_tests.cpp @@ -5,11 +5,13 @@ #include #include +#include #include #include #include #include #include +#include