diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp index fe01527bb62..70a76e5091a 100644 --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -39,11 +39,17 @@ namespace interfaces { namespace { -class LockImpl : public Chain::Lock, public UniqueLock +class LockImpl : public Chain::Lock { + CCriticalSection& m_mutex; + +public: + LockImpl(CCriticalSection& mutex) : m_mutex(mutex) + { + } Optional getHeight() override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); int height = ::ChainActive().Height(); if (height >= 0) { return height; @@ -52,7 +58,7 @@ class LockImpl : public Chain::Lock, public UniqueLock } Optional getBlockHeight(const uint256& hash) override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); CBlockIndex* block = LookupBlockIndex(hash); if (block && ::ChainActive().Contains(block)) { return block->nHeight; @@ -67,34 +73,34 @@ class LockImpl : public Chain::Lock, public UniqueLock } uint256 getBlockHash(int height) override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockHash(); } int64_t getBlockTime(int height) override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetBlockTime(); } int64_t getBlockMedianTimePast(int height) override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); CBlockIndex* block = ::ChainActive()[height]; assert(block != nullptr); return block->GetMedianTimePast(); } bool haveBlockOnDisk(int height) override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); CBlockIndex* block = ::ChainActive()[height]; return block && ((block->nStatus & BLOCK_HAVE_DATA) != 0) && block->nTx > 0; } Optional findFirstBlockWithTimeAndHeight(int64_t time, int height, uint256* hash) override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); CBlockIndex* block = ::ChainActive().FindEarliestAtLeast(time, height); if (block) { if (hash) *hash = block->GetBlockHash(); @@ -104,7 +110,7 @@ class LockImpl : public Chain::Lock, public UniqueLock } Optional findPruned(int start_height, Optional stop_height) override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); if (::fPruneMode) { CBlockIndex* block = stop_height ? ::ChainActive()[*stop_height] : ::ChainActive().Tip(); while (block && block->nHeight >= start_height) { @@ -118,7 +124,7 @@ class LockImpl : public Chain::Lock, public UniqueLock } Optional findFork(const uint256& hash, Optional* height) override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); const CBlockIndex* block = LookupBlockIndex(hash); const CBlockIndex* fork = block ? ::ChainActive().FindFork(block) : nullptr; if (height) { @@ -135,12 +141,12 @@ class LockImpl : public Chain::Lock, public UniqueLock } CBlockLocator getTipLocator() override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); return ::ChainActive().GetLocator(); } Optional findLocatorFork(const CBlockLocator& locator) override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); if (CBlockIndex* fork = FindForkInGlobalIndex(::ChainActive(), locator)) { return fork->nHeight; } @@ -148,11 +154,13 @@ class LockImpl : public Chain::Lock, public UniqueLock } bool checkFinalTx(const CTransaction& tx) override { - LockAssertion lock(::cs_main); + LockAssertion lock(m_mutex); return CheckFinalTx(tx); } - - using UniqueLock::UniqueLock; + CCriticalSection& mutex() override + { + return m_mutex; + } }; class NotificationsHandlerImpl : public Handler, CValidationInterface @@ -240,13 +248,9 @@ class RpcHandlerImpl : public Handler class ChainImpl : public Chain { public: - std::unique_ptr lock(bool try_lock) override + std::unique_ptr lock() override { - auto result = MakeUnique(::cs_main, "cs_main", __FILE__, __LINE__, try_lock); - if (try_lock && result && !*result) return {}; - // std::move necessary on some compilers due to conversion from - // LockImpl to Lock pointer - return std::move(result); + return MakeUnique(::cs_main); } bool findBlock(const uint256& hash, CBlock* block, int64_t* time, int64_t* time_max) override { diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h index 12157a2275c..8c904912bd8 100644 --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -7,6 +7,7 @@ #include // For Optional and nullopt #include // For CTransactionRef +#include #include #include @@ -124,11 +125,14 @@ class Chain //! Check if transaction will be final given chain height current time. virtual bool checkFinalTx(const CTransaction& tx) = 0; + + //! Assosiated mutex accessor + virtual CCriticalSection& mutex() = 0; }; - //! Return Lock interface. Chain is locked when this is called, and - //! unlocked when the returned interface is freed. - virtual std::unique_ptr lock(bool try_lock = false) = 0; + //! Return Lock interface. Chain is NOT locked when this is called, + //! it's defered to caller + virtual std::unique_ptr lock() = 0; //! Return whether node has the block and optionally return block metadata //! or contents. diff --git a/src/masternodes/mn_rpc.cpp b/src/masternodes/mn_rpc.cpp index a73d38fa495..88d45864dcd 100644 --- a/src/masternodes/mn_rpc.cpp +++ b/src/masternodes/mn_rpc.cpp @@ -208,6 +208,7 @@ std::string ScriptToString(CScript const& script) { int chainHeight(interfaces::Chain::Lock& locked_chain) { + LOCK(locked_chain.mutex()); if (auto height = locked_chain.getHeight()) return *height; return 0; @@ -252,7 +253,7 @@ static boost::optional GetAuthInputOnly(CWallet* const pwallet, CTxDestin cctl.m_tokenFilter = {DCT_ID{0}}; auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); pwallet->AvailableCoins(*locked_chain, vecOutputs, true, &cctl, 1, MAX_MONEY, MAX_MONEY, 1); diff --git a/src/masternodes/rpc_masternodes.cpp b/src/masternodes/rpc_masternodes.cpp index 7866b6768b1..fa33811b356 100644 --- a/src/masternodes/rpc_masternodes.cpp +++ b/src/masternodes/rpc_masternodes.cpp @@ -657,6 +657,7 @@ UniValue listanchors(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); auto confirms = pcustomcsview->CAnchorConfirmsView::GetAnchorConfirmData(); diff --git a/src/masternodes/rpc_oracles.cpp b/src/masternodes/rpc_oracles.cpp index 84bc16d2f93..b8f95890405 100644 --- a/src/masternodes/rpc_oracles.cpp +++ b/src/masternodes/rpc_oracles.cpp @@ -717,11 +717,12 @@ UniValue listlatestrawprices(const JSONRPCRequest &request) { tokenPair = DecodeTokenCurrencyPair(request.params[0]); } - auto lock = pwallet->chain().lock(); + auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); - auto optHeight = lock->getHeight(); + auto optHeight = locked_chain->getHeight(); int lastHeight = optHeight ? *optHeight : 0; - auto lastBlockTime = lock->getBlockTime(lastHeight); + auto lastBlockTime = locked_chain->getBlockTime(lastHeight); CCustomCSView mnview(*pcustomcsview); @@ -859,11 +860,12 @@ UniValue getprice(const JSONRPCRequest &request) { auto tokenPair = DecodeTokenCurrencyPair(request.params[0]); - auto lock = pwallet->chain().lock(); + auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); - auto optHeight = lock->getHeight(); + auto optHeight = locked_chain->getHeight(); int lastHeight = optHeight ? *optHeight : 0; - auto lastBlockTime = lock->getBlockTime(lastHeight); + auto lastBlockTime = locked_chain->getBlockTime(lastHeight); CCustomCSView view(*pcustomcsview); auto result = GetAggregatePrice(view, tokenPair.first, tokenPair.second, lastBlockTime); @@ -897,11 +899,12 @@ UniValue listprices(const JSONRPCRequest& request) { RPCTypeCheck(request.params, {}, false); - auto lock = pwallet->chain().lock(); + auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); - auto optHeight = lock->getHeight(); + auto optHeight = locked_chain->getHeight(); int lastHeight = optHeight ? *optHeight : 0; - auto lastBlockTime = lock->getBlockTime(lastHeight); + auto lastBlockTime = locked_chain->getBlockTime(lastHeight); CCustomCSView view(*pcustomcsview); return GetAllAggregatePrices(view, lastBlockTime); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 7b75c16ff14..ead0b9c5942 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -630,8 +630,7 @@ static UniValue combinerawtransaction(const JSONRPCRequest& request) CCoinsView viewDummy; CCoinsViewCache view(&viewDummy); { - LOCK(cs_main); - LOCK(mempool.cs); + LOCK2(cs_main, mempool.cs); CCoinsViewCache &viewChain = ::ChainstateActive().CoinsTip(); CCoinsViewMemPool viewMempool(&viewChain, mempool); view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view diff --git a/src/spv/spv_rpc.cpp b/src/spv/spv_rpc.cpp index 8f2db04dcb2..b314f315442 100644 --- a/src/spv/spv_rpc.cpp +++ b/src/spv/spv_rpc.cpp @@ -145,6 +145,7 @@ UniValue spv_createanchor(const JSONRPCRequest& request) CAnchor anchor; { auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); anchor = panchorauths->CreateBestAnchor(rewardDest); prevAnchorHeight = panchors->GetActiveAnchor() ? panchors->GetActiveAnchor()->anchor.height : 0; @@ -233,6 +234,7 @@ UniValue spv_createanchortemplate(const JSONRPCRequest& request) CAnchor anchor; { auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); anchor = panchorauths->CreateBestAnchor(rewardDest); prevAnchorHeight = panchors->GetActiveAnchor() ? panchors->GetActiveAnchor()->anchor.height : 0; @@ -297,6 +299,7 @@ UniValue spv_estimateanchorcost(const JSONRPCRequest& request) } auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); // it is unable to create "pure" dummy anchor, cause it needs signing with real key CAnchor const anchor = panchorauths->CreateBestAnchor(CTxDestination(PKHash())); @@ -390,6 +393,7 @@ UniValue spv_gettxconfirmations(const JSONRPCRequest& request) // uint32_t const spvLastHeight = spv::pspv ? spv::pspv->GetLastBlockHeight() : 0; auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); // panchors->UpdateLastHeight(spvLastHeight); return UniValue(panchors->GetAnchorConfirmations(txHash)); } @@ -453,6 +457,7 @@ UniValue spv_listanchors(const JSONRPCRequest& request) uint32_t const tmp = spv::pspv->GetLastBlockHeight(); auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); panchors->UpdateLastHeight(tmp); // may be unnecessary but for sure auto const * cur = panchors->GetActiveAnchor(); @@ -503,6 +508,7 @@ UniValue spv_listanchorspending(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_REQUEST, "spv module disabled"); auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); UniValue result(UniValue::VARR); panchors->ForEachPending([&result](uint256 const &, CAnchorIndex::AnchorRec & rec) @@ -535,6 +541,7 @@ UniValue spv_listanchorauths(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); UniValue result(UniValue::VARR); CAnchorAuthIndex::Auth const * prev = nullptr; @@ -639,6 +646,7 @@ UniValue spv_listanchorrewardconfirms(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); UniValue result(UniValue::VARR); @@ -705,6 +713,7 @@ UniValue spv_listanchorrewards(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); UniValue result(UniValue::VARR); @@ -737,6 +746,7 @@ UniValue spv_listanchorsunrewarded(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); UniValue result(UniValue::VARR); @@ -1205,7 +1215,7 @@ static UniValue spv_dumpprivkey(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); std::string strAddress = request.params[0].get_str(); @@ -1275,7 +1285,7 @@ static UniValue spv_sendtoaddress(const JSONRPCRequest& request) } auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); std::string address = request.params[0].get_str(); diff --git a/src/spv/spv_wrapper.cpp b/src/spv/spv_wrapper.cpp index 0859a566b4f..acda48a0a5b 100644 --- a/src/spv/spv_wrapper.cpp +++ b/src/spv/spv_wrapper.cpp @@ -424,25 +424,28 @@ void CSpvWrapper::OnTxUpdated(const UInt256 txHashes[], size_t txCount, uint32_t for (size_t i = 0; i < txCount; ++i) { uint256 const txHash{to_uint256(txHashes[i])}; const uint256 btcHash{to_uint256(blockHash)}; - UpdateTx(txHash, blockHeight, timestamp, btcHash); - LogPrint(BCLog::SPV, "tx updated, hash: %s, blockHeight: %d, timestamp: %d\n", txHash.ToString(), blockHeight, timestamp); - LOCK(cs_main); - - CAnchorIndex::AnchorRec oldPending; - if (panchors->GetPendingByBtcTx(txHash, oldPending)) { - LogPrint(BCLog::SPV, "updating anchor pending %s\n", txHash.ToString()); - if (panchors->AddToAnchorPending(oldPending.anchor, txHash, blockHeight, true)) { - LogPrint(BCLog::ANCHORING, "Anchor pending added/updated %s\n", txHash.ToString()); + LOCK(cs_main); + + UpdateTx(txHash, blockHeight, timestamp, btcHash); + LogPrint(BCLog::SPV, "tx updated, hash: %s, blockHeight: %d, timestamp: %d\n", txHash.ToString(), blockHeight, timestamp); + + CAnchorIndex::AnchorRec oldPending; + if (panchors->GetPendingByBtcTx(txHash, oldPending)) + { + LogPrint(BCLog::SPV, "updating anchor pending %s\n", txHash.ToString()); + if (panchors->AddToAnchorPending(oldPending.anchor, txHash, blockHeight, true)) { + LogPrint(BCLog::ANCHORING, "Anchor pending added/updated %s\n", txHash.ToString()); + } } - } - else if (auto exist = panchors->GetAnchorByBtcTx(txHash)) // update index. no any checks nor validations - { - LogPrint(BCLog::SPV, "updating anchor %s\n", txHash.ToString()); - CAnchor oldAnchor{exist->anchor}; - if (panchors->AddAnchor(oldAnchor, txHash, blockHeight, true)) { - LogPrint(BCLog::ANCHORING, "Anchor added/updated %s\n", txHash.ToString()); + else if (auto exist = panchors->GetAnchorByBtcTx(txHash)) // update index. no any checks nor validations + { + LogPrint(BCLog::SPV, "updating anchor %s\n", txHash.ToString()); + CAnchor oldAnchor{exist->anchor}; + if (panchors->AddAnchor(oldAnchor, txHash, blockHeight, true)) { + LogPrint(BCLog::ANCHORING, "Anchor added/updated %s\n", txHash.ToString()); + } } } @@ -456,9 +459,11 @@ void CSpvWrapper::OnTxDeleted(UInt256 txHash, int notifyUser, int recommendResca uint256 const hash(to_uint256(txHash)); EraseTx(hash); - LOCK(cs_main); - panchors->DeleteAnchorByBtcTx(hash); - panchors->DeletePendingByBtcTx(hash); + { + LOCK(cs_main); + panchors->DeleteAnchorByBtcTx(hash); + panchors->DeletePendingByBtcTx(hash); + } OnTxNotify(txHash); diff --git a/src/sync.h b/src/sync.h index 4241cdcb29c..301033386b3 100644 --- a/src/sync.h +++ b/src/sync.h @@ -63,14 +63,8 @@ void DeleteLock(void* cs); */ extern bool g_debug_lockorder_abort; #else -void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} -void static inline LeaveCritical() {} -void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) ASSERT_EXCLUSIVE_LOCK(cs) {} -void static inline AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs) {} -void static inline DeleteLock(void* cs) {} +#define DeleteLock(cs) #endif -#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) -#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs) /** * Template mixin that adds -Wthread-safety locking annotations and lock order @@ -107,14 +101,17 @@ class LOCKABLE AnnotatedMixin : public PARENT * TODO: We should move away from using the recursive lock by default. */ using RecursiveMutex = AnnotatedMixin; -typedef AnnotatedMixin CCriticalSection; +using CCriticalSection = RecursiveMutex; /** Wrapped mutex: supports waiting but not recursive locking */ -typedef AnnotatedMixin Mutex; +using Mutex = AnnotatedMixin; #ifdef DEBUG_LOCKCONTENTION + +#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs) +#define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs) + void PrintLockContention(const char* pszName, const char* pszFile, int nLine); -#endif /** Wrapper around std::unique_lock style lock for Mutex. */ template @@ -124,14 +121,10 @@ class SCOPED_LOCKABLE UniqueLock : public Base void Enter(const char* pszName, const char* pszFile, int nLine) { EnterCritical(pszName, pszFile, nLine, (void*)(Base::mutex())); -#ifdef DEBUG_LOCKCONTENTION if (!Base::try_lock()) { PrintLockContention(pszName, pszFile, nLine); -#endif Base::lock(); -#ifdef DEBUG_LOCKCONTENTION } -#endif } bool TryEnter(const char* pszName, const char* pszFile, int nLine) @@ -178,10 +171,7 @@ class SCOPED_LOCKABLE UniqueLock : public Base template using DebugLock = UniqueLock::type>::type>; -#define PASTE(x, y) x ## y -#define PASTE2(x, y) PASTE(x, y) - -#define LOCK(cs) DebugLock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__) +#define LOCK(cs) DebugLock criticalblock1(cs, #cs, __FILE__, __LINE__) #define LOCK2(cs1, cs2) \ DebugLock criticalblock1(cs1, #cs1, __FILE__, __LINE__); \ DebugLock criticalblock2(cs2, #cs2, __FILE__, __LINE__); @@ -200,6 +190,27 @@ using DebugLock = UniqueLock +using unique_lock_type = typename std::decay::type::UniqueLock; + +#define LOCK(cs) unique_lock_type criticalblock1(cs) +#define LOCK2(cs1, cs2) \ + unique_lock_type criticalblock1(cs1, std::defer_lock); \ + unique_lock_type criticalblock2(cs2, std::defer_lock); \ + std::lock(criticalblock1, criticalblock2) + +#define TRY_LOCK(cs, name) unique_lock_type name(cs, std::try_to_lock) +#define WAIT_LOCK(cs, name) unique_lock_type name(cs) + +#define ENTER_CRITICAL_SECTION(cs) (cs).lock() +#define LEAVE_CRITICAL_SECTION(cs) (cs).unlock() + +#endif //! Run code while locking a mutex. //! //! Examples: diff --git a/src/test/sync_tests.cpp b/src/test/sync_tests.cpp index e7abb31b00f..33c00c49b85 100644 --- a/src/test/sync_tests.cpp +++ b/src/test/sync_tests.cpp @@ -5,48 +5,49 @@ #include #include +#include + #include -namespace { -template -void TestPotentialDeadLockDetected(MutexType& mutex1, MutexType& mutex2) +template +void TryPotentialDeadlock(MutexType& mutex1, MutexType& mutex2) { + std::promise threadFinished; + auto futureFinished = threadFinished.get_future(); { LOCK2(mutex1, mutex2); + std::promise threadStarted; + // start new thread + std::thread([&]() { + // secondary thread started + threadStarted.set_value(); + // simulate deadlock + LOCK2(mutex2, mutex1); + // secondary thread is about to finish + threadFinished.set_value(); + }).detach(); + // wait secondary thread to start + threadStarted.get_future().wait(); + // keep mutex for an extra while + futureFinished.wait_for(std::chrono::milliseconds{50}); } - bool error_thrown = false; - try { - LOCK2(mutex2, mutex1); - } catch (const std::logic_error& e) { - BOOST_CHECK_EQUAL(e.what(), "potential deadlock detected"); - error_thrown = true; - } - #ifdef DEBUG_LOCKORDER - BOOST_CHECK(error_thrown); - #else - BOOST_CHECK(!error_thrown); - #endif + // wait secondary thread to finish + futureFinished.wait(); } -} // namespace BOOST_FIXTURE_TEST_SUITE(sync_tests, BasicTestingSetup) -BOOST_AUTO_TEST_CASE(potential_deadlock_detected) +BOOST_AUTO_TEST_CASE(simulate_potential_deadlock) { - #ifdef DEBUG_LOCKORDER - bool prev = g_debug_lockorder_abort; - g_debug_lockorder_abort = false; - #endif - - CCriticalSection rmutex1, rmutex2; - TestPotentialDeadLockDetected(rmutex1, rmutex2); - - Mutex mutex1, mutex2; - TestPotentialDeadLockDetected(mutex1, mutex2); + { + CCriticalSection rmutex1, rmutex2; + TryPotentialDeadlock(rmutex1, rmutex2); + } - #ifdef DEBUG_LOCKORDER - g_debug_lockorder_abort = prev; - #endif + { + Mutex mutex1, mutex2; + TryPotentialDeadlock(mutex1, mutex2); + } } BOOST_AUTO_TEST_CASE(lock_free) @@ -62,7 +63,7 @@ BOOST_AUTO_TEST_CASE(lock_free) CLockFreeGuard lock(cs_lock); context++; - while (threads > 0); // wait all therads to be here + while (threads > 0); // wait all threads to be here BOOST_CHECK_EQUAL(threads.load(), 0); // now they wait for lock BOOST_CHECK_EQUAL(context.load(), 1); // but only one operates context--; diff --git a/src/validation.cpp b/src/validation.cpp index 7179ff12217..02c1ca6b9a4 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2942,7 +2942,7 @@ bool CChainState::FlushStateToDisk( int nManualPruneHeight) { int64_t nMempoolUsage = mempool.DynamicMemoryUsage(); - LOCK(cs_main); + LOCK2(cs_main, cs_LastBlockFile); assert(this->CanFlushToDisk()); static int64_t nLastWrite = 0; static int64_t nLastFlush = 0; @@ -2952,7 +2952,6 @@ bool CChainState::FlushStateToDisk( { bool fFlushForPrune = false; bool fDoFullFlush = false; - LOCK(cs_LastBlockFile); if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) { if (nManualPruneHeight > 0) { FindFilesToPruneManual(setFilesToPrune, nManualPruneHeight); @@ -3847,8 +3846,7 @@ bool CChainState::InvalidateBlock(CValidationState& state, const CChainParams& c // Make sure the queue of validation callbacks doesn't grow unboundedly. LimitValidationInterfaceQueue(); - LOCK(cs_main); - LOCK(::mempool.cs); // Lock for as long as disconnectpool is in scope to make sure UpdateMempoolForReorg is called after DisconnectTip without unlocking in between + LOCK2(cs_main, ::mempool.cs); // Lock for as long as disconnectpool is in scope to make sure UpdateMempoolForReorg is called after DisconnectTip without unlocking in between if (!m_chain.Contains(pindex)) break; pindex_was_in_chain = true; CBlockIndex *invalid_walk_tip = m_chain.Tip(); diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp index af14e8b5d44..78ec00cb91e 100644 --- a/src/wallet/feebumper.cpp +++ b/src/wallet/feebumper.cpp @@ -63,7 +63,7 @@ namespace feebumper { bool TransactionCanBeBumped(const CWallet* wallet, const uint256& txid) { auto locked_chain = wallet->chain().lock(); - LOCK(wallet->cs_wallet); + LOCK2(wallet->cs_wallet, locked_chain->mutex()); const CWalletTx* wtx = wallet->GetWalletTx(txid); if (wtx == nullptr) return false; @@ -78,7 +78,7 @@ Result CreateTotalBumpTransaction(const CWallet* wallet, const uint256& txid, co new_fee = total_fee; auto locked_chain = wallet->chain().lock(); - LOCK(wallet->cs_wallet); + LOCK2(wallet->cs_wallet, locked_chain->mutex()); errors.clear(); const CWalletTx* wtx = wallet->GetWalletTx(txid); if (!wtx) { @@ -203,7 +203,7 @@ Result CreateRateBumpTransaction(CWallet* wallet, const uint256& txid, const CCo CCoinControl new_coin_control(coin_control); auto locked_chain = wallet->chain().lock(); - LOCK(wallet->cs_wallet); + LOCK2(wallet->cs_wallet, locked_chain->mutex()); errors.clear(); const CWalletTx* wtx = wallet->GetWalletTx(txid); if (!wtx) { @@ -296,14 +296,14 @@ Result CreateRateBumpTransaction(CWallet* wallet, const uint256& txid, const CCo bool SignTransaction(CWallet* wallet, CMutableTransaction& mtx) { auto locked_chain = wallet->chain().lock(); - LOCK(wallet->cs_wallet); + LOCK2(wallet->cs_wallet, locked_chain->mutex()); return wallet->SignTransaction(mtx); } Result CommitTransaction(CWallet* wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector& errors, uint256& bumped_txid) { auto locked_chain = wallet->chain().lock(); - LOCK(wallet->cs_wallet); + LOCK2(wallet->cs_wallet, locked_chain->mutex()); if (!errors.empty()) { return Result::MISC_ERROR; } diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 65e8646fa79..b73bddf5e13 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -144,7 +144,7 @@ UniValue importprivkey(const JSONRPCRequest& request) bool fRescan = true; { auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); EnsureWalletIsUnlocked(pwallet); @@ -295,7 +295,7 @@ UniValue importaddress(const JSONRPCRequest& request) { auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); CTxDestination dest = DecodeDestination(request.params[0].get_str()); if (IsValidDestination(dest)) { @@ -327,7 +327,7 @@ UniValue importaddress(const JSONRPCRequest& request) RescanWallet(*pwallet, reserver); { auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); pwallet->ReacceptWalletTransactions(*locked_chain); } } @@ -367,9 +367,12 @@ UniValue importprunedfunds(const JSONRPCRequest& request) std::vector vMatch; std::vector vIndex; unsigned int txnIndex = 0; + + auto locked_chain = pwallet->chain().lock(); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); + if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) { - auto locked_chain = pwallet->chain().lock(); if (locked_chain->getBlockHeight(merkleBlock.header.GetHash()) == nullopt) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); } @@ -388,9 +391,6 @@ UniValue importprunedfunds(const JSONRPCRequest& request) wtx.nIndex = txnIndex; wtx.hashBlock = merkleBlock.header.GetHash(); - auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); - if (pwallet->IsMine(*wtx.tx)) { pwallet->AddToWallet(wtx, false); return NullUniValue; @@ -421,7 +421,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); uint256 hash(ParseHashV(request.params[0], "txid")); std::vector vHash; @@ -500,7 +500,7 @@ UniValue importpubkey(const JSONRPCRequest& request) { auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); std::set script_pub_keys; for (const auto& dest : GetAllDestinationsForKey(pubKey)) { @@ -518,7 +518,7 @@ UniValue importpubkey(const JSONRPCRequest& request) RescanWallet(*pwallet, reserver); { auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); pwallet->ReacceptWalletTransactions(*locked_chain); } } @@ -569,7 +569,7 @@ UniValue importwallet(const JSONRPCRequest& request) std::set spvPubKeys; { auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); EnsureWalletIsUnlocked(pwallet); @@ -726,7 +726,7 @@ UniValue dumpprivkey(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); EnsureWalletIsUnlocked(pwallet); @@ -775,7 +775,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); EnsureWalletIsUnlocked(pwallet); @@ -1382,7 +1382,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) UniValue response(UniValue::VARR); { auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); EnsureWalletIsUnlocked(pwallet); // Verify all timestamps are present before importing any keys. @@ -1424,7 +1424,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */); { auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); pwallet->ReacceptWalletTransactions(*locked_chain); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c2bed9302c1..2132af6e66a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -413,7 +413,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); CTxDestination dest = DecodeDestination(request.params[0].get_str()); if (!IsValidDestination(dest)) { @@ -498,7 +498,7 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); UniValue jsonGroupings(UniValue::VARR); std::map balances = pwallet->GetAddressBalances(*locked_chain); @@ -553,7 +553,7 @@ static UniValue signmessage(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); EnsureWalletIsUnlocked(pwallet); @@ -622,7 +622,7 @@ static UniValue getreceivedbyaddress(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); // Defi address CTxDestination dest = DecodeDestination(request.params[0].get_str()); @@ -691,7 +691,7 @@ static UniValue getreceivedbylabel(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); // Minimum confirmations int nMinDepth = 1; @@ -774,7 +774,7 @@ static UniValue getbalance(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); const UniValue& dummy_value = request.params[0]; if (!dummy_value.isNull() && dummy_value.get_str() != "*") { @@ -820,7 +820,7 @@ static UniValue getunconfirmedbalance(const JSONRPCRequest &request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); bool with_tokens = request.params[0].isNull() ? false : request.params[0].get_bool(); @@ -885,7 +885,7 @@ static UniValue sendmany(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); if (!request.params[0].isNull() && !request.params[0].get_str().empty()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\""); @@ -996,7 +996,7 @@ static UniValue addmultisigaddress(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); std::string label; if (!request.params[2].isNull()) @@ -1235,7 +1235,7 @@ static UniValue listreceivedbyaddress(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); return ListReceived(*locked_chain, pwallet, request.params, false); } @@ -1279,7 +1279,7 @@ static UniValue listreceivedbylabel(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); return ListReceived(*locked_chain, pwallet, request.params, true); } @@ -1477,7 +1477,7 @@ UniValue listtransactions(const JSONRPCRequest& request) { auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); const auto & txOrdered = pwallet->mapWallet.get(); std::vector metadata; @@ -1587,7 +1587,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); // The way the 'height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0. Optional height = MakeOptional(false, int()); // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain. @@ -1722,7 +1722,7 @@ static UniValue gettransaction(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); uint256 hash(ParseHashV(request.params[0], "txid")); @@ -1790,7 +1790,7 @@ static UniValue abandontransaction(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); uint256 hash(ParseHashV(request.params[0], "txid")); @@ -1831,7 +1831,7 @@ static UniValue backupwallet(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); std::string strDest = request.params[0].get_str(); if (!pwallet->BackupWallet(strDest)) { @@ -1869,7 +1869,7 @@ static UniValue keypoolrefill(const JSONRPCRequest& request) } auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool unsigned int kpSize = 0; @@ -1921,7 +1921,7 @@ static UniValue walletpassphrase(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called."); @@ -1997,7 +1997,7 @@ static UniValue walletpassphrasechange(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called."); @@ -2053,7 +2053,7 @@ static UniValue walletlock(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); if (!pwallet->IsCrypted()) { throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called."); @@ -2100,7 +2100,7 @@ static UniValue encryptwallet(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet does not contain private keys, nothing to encrypt."); @@ -2179,7 +2179,7 @@ static UniValue lockunspent(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); RPCTypeCheckArgument(request.params[0], UniValue::VBOOL); @@ -2289,7 +2289,7 @@ static UniValue listlockunspent(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); std::vector vOutpts; pwallet->ListLockedCoins(vOutpts); @@ -2331,7 +2331,7 @@ static UniValue settxfee(const JSONRPCRequest& request) }.Check(request); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); CAmount nAmount = AmountFromValue(request.params[0]); CFeeRate tx_fee_rate(nAmount, 1000); @@ -2385,7 +2385,7 @@ static UniValue getbalances(const JSONRPCRequest& request) wallet.BlockUntilSyncedToCurrentChain(); auto locked_chain = wallet.chain().lock(); - LOCK(wallet.cs_wallet); + LOCK2(wallet.cs_wallet, locked_chain->mutex()); bool with_tokens = request.params[0].isNull() ? false : request.params[0].get_bool(); @@ -2468,7 +2468,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); bool with_tokens = request.params[0].isNull() ? false : request.params[0].get_bool(); @@ -2971,7 +2971,7 @@ static UniValue listunspent(const JSONRPCRequest& request) cctl.m_tokenFilter.insert(DCT_ID{(uint32_t) nOnlyTokensId}); } auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount); } @@ -3333,7 +3333,7 @@ UniValue signrawtransactionwithwallet(const JSONRPCRequest& request) // Sign the transaction auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); EnsureWalletIsUnlocked(pwallet); // Fetch previous transactions (inputs): @@ -3451,7 +3451,7 @@ static UniValue bumpfee(const JSONRPCRequest& request) pwallet->BlockUntilSyncedToCurrentChain(); auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); EnsureWalletIsUnlocked(pwallet); @@ -3546,6 +3546,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request) uint256 start_block, stop_block; { auto locked_chain = pwallet->chain().lock(); + LOCK(locked_chain->mutex()); Optional tip_height = locked_chain->getHeight(); if (!request.params[0].isNull()) { @@ -3990,7 +3991,7 @@ UniValue sethdseed(const JSONRPCRequest& request) } auto locked_chain = pwallet->chain().lock(); - LOCK(pwallet->cs_wallet); + LOCK2(pwallet->cs_wallet, locked_chain->mutex()); // Do not do anything to non-HD wallets if (!pwallet->CanSupportFeature(FEATURE_HD)) { diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp index ce321311dff..897cc32a95a 100644 --- a/src/wallet/test/wallet_tests.cpp +++ b/src/wallet/test/wallet_tests.cpp @@ -296,7 +296,7 @@ static int64_t AddTx(CWallet& wallet, uint32_t lockTime, int64_t mockTime, int64 CBlockIndex* block = nullptr; if (blockTime > 0) { auto locked_chain = wallet.chain().lock(); - LockAssertion lock(::cs_main); + LOCK(locked_chain->mutex()); auto inserted = ::BlockIndex().emplace(GetRandHash(), new CBlockIndex); assert(inserted.second); const uint256& hash = inserted.first->first; @@ -406,8 +406,7 @@ class ListCoinsTestingSetup : public TestChain100Setup } CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey()), masternodesID); - LOCK(cs_main); - LOCK(wallet->cs_wallet); + LOCK2(cs_main, wallet->cs_wallet); auto& byHash = wallet->mapWallet.get(); auto it = byHash.find(tx->GetHash()); BOOST_CHECK(it != byHash.end()); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 7ef5c55ace1..0cfa927e9f9 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1265,7 +1265,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, const uint256 bool CWallet::TransactionCanBeAbandoned(const uint256& hashTx) const { auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); const CWalletTx* wtx = GetWalletTx(hashTx); return wtx && !wtx->isAbandoned() && wtx->GetDepthInMainChain(*locked_chain) == 0 && !wtx->InMempool(); } @@ -1285,7 +1285,7 @@ void CWallet::MarkInputsDirty(const CTransactionRef& tx) bool CWallet::AbandonTransaction(interfaces::Chain::Lock& locked_chain, const uint256& hashTx) { auto locked_chain_recursive = chain().lock(); // Temporary. Removed in upcoming lock cleanup - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain_recursive->mutex()); WalletBatch batch(*database, "r+"); @@ -1342,7 +1342,7 @@ bool CWallet::AbandonTransaction(interfaces::Chain::Lock& locked_chain, const ui void CWallet::MarkConflicted(const uint256& hashBlock, const uint256& hashTx) { auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); int conflictconfirms = -locked_chain->getBlockDepth(hashBlock); // If number of conflict confirms cannot be determined, this means @@ -1405,7 +1405,7 @@ void CWallet::SyncTransaction(const CTransactionRef& ptx, const uint256& block_h void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) { auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */); auto it = mapWallet.find(ptx->GetHash()); @@ -1417,7 +1417,8 @@ void CWallet::TransactionAddedToMempool(const CTransactionRef& ptx) { } void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) { - LOCK(cs_wallet); + auto locked_chain = chain().lock(); + LOCK2(cs_wallet, locked_chain->mutex()); auto it = mapWallet.find(ptx->GetHash()); if (it != mapWallet.end()) { mapWallet.modify(it, [](CWalletTx& wtx) { @@ -1429,7 +1430,7 @@ void CWallet::TransactionRemovedFromMempool(const CTransactionRef &ptx) { void CWallet::BlockConnected(const CBlock& block, const std::vector& vtxConflicted) { const uint256& block_hash = block.GetHash(); auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); // TODO: Temporarily ensure that mempool removals are notified before // connected transactions. This shouldn't matter, but the abandoned // state of transactions in our wallet is currently cleared when we @@ -1452,7 +1453,7 @@ void CWallet::BlockConnected(const CBlock& block, const std::vectormutex()); for (const CTransactionRef& ptx : block.vtx) { SyncTransaction(ptx, {} /* block hash */, 0 /* position in block */); @@ -2000,6 +2001,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, const WalletRescanReserver& r uint256 start_block; { auto locked_chain = chain().lock(); + LOCK(locked_chain->mutex()); const Optional start_height = locked_chain->findFirstBlockWithTimeAndHeight(startTime - TIMESTAMP_WINDOW, 0, &start_block); const Optional tip_height = locked_chain->getHeight(); WalletLogPrintf("%s: Rescanning last %i blocks\n", __func__, tip_height && start_height ? *tip_height - *start_height + 1 : 0); @@ -2060,6 +2062,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc double progress_end; { auto locked_chain = chain().lock(); + LOCK(locked_chain->mutex()); if (Optional tip_height = locked_chain->getHeight()) { tip_hash = locked_chain->getBlockHash(*tip_height); } @@ -2078,7 +2081,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc CBlock block; if (chain().findBlock(block_hash, &block) && !block.IsNull()) { auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); if (!locked_chain->getBlockHeight(block_hash)) { // Abort scan if current block is no longer active, to prevent // marking transactions as coming from the wrong block. @@ -2104,6 +2107,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc } { auto locked_chain = chain().lock(); + LOCK(locked_chain->mutex()); Optional tip_height = locked_chain->getHeight(); if (!tip_height || *tip_height <= block_height || !locked_chain->getBlockHeight(block_hash)) { // break successfully when rescan has reached the tip, or @@ -2403,7 +2407,7 @@ void CWallet::ResendWalletTransactions() { // locked_chain and cs_wallet scope auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); // Relay transactions auto& byTime = mapWallet.get(); @@ -2446,7 +2450,7 @@ CWallet::Balance CWallet::GetBalance(const int min_depth, bool avoid_reuse) cons isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED; { auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); for (const auto& wtx : mapWallet.get()) { const bool is_trusted{wtx.IsTrusted(*locked_chain)}; @@ -2472,7 +2476,7 @@ CWallet::Balance CWallet::GetBalance(const int min_depth, bool avoid_reuse) cons CAmount CWallet::GetAvailableBalance(const CCoinControl* coinControl) const { auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); CAmount balance = 0; std::vector vCoins; @@ -2869,7 +2873,7 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount& nFeeRet, int& nC // Acquire the locks to prevent races to the new locked unspents between the // CreateTransaction call and LockCoin calls (when lockUnspents is true). auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); CTransactionRef tx_new; if (!CreateTransaction(*locked_chain, vecSend, tx_new, nFeeRet, nChangePosInOut, strFailReason, coinControl, false)) { @@ -3031,7 +3035,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std std::set tokenCoins; { auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); for (auto it = vTokenValues.begin(); it != vTokenValues.end(); ++it) { @@ -3095,7 +3099,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std { std::set setCoins; auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); { std::vector vAvailableCoins; AvailableCoins(*locked_chain, vAvailableCoins, true, &coin_control, 1, MAX_MONEY, MAX_MONEY, 0); @@ -3435,7 +3439,7 @@ bool CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, CValida { { auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); CWalletTx wtxNew(this, std::move(tx)); wtxNew.mapValue = std::move(mapValue); @@ -4743,7 +4747,7 @@ void CWallet::handleNotifications() void CWallet::postInitProcess() { auto locked_chain = chain().lock(); - LOCK(cs_wallet); + LOCK2(cs_wallet, locked_chain->mutex()); // Add wallet transactions that aren't already in a block to mempool // Do this here as mempool requires genesis block to be loaded