diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -106,7 +106,7 @@ //! Construct wallet TxOut struct. static WalletTxOut MakeWalletTxOut(CWallet &wallet, const CWalletTx &wtx, int n, int depth) - EXCLUSIVE_LOCKS_REQUIRED(cs_main) { + EXCLUSIVE_LOCKS_REQUIRED(cs_main, wallet.cs_wallet) { WalletTxOut result; result.txout = wtx.tx->vout[n]; result.time = wtx.GetTxTime(); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -227,9 +227,10 @@ return EncodeDestination(dest, config); } -CTxDestination GetLabelDestination(CWallet *const pwallet, - const std::string &label, - bool bForceNew = false) { +static CTxDestination GetLabelDestination(CWallet *const pwallet, + const std::string &label, + bool bForceNew = false) + EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) { CTxDestination dest; if (!pwallet->GetLabelDestination(dest, label, bForceNew)) { throw JSONRPCError( @@ -1751,7 +1752,7 @@ static UniValue ListReceived(const Config &config, CWallet *const pwallet, const UniValue ¶ms, bool by_label) - EXCLUSIVE_LOCKS_REQUIRED(cs_main) { + EXCLUSIVE_LOCKS_REQUIRED(cs_main, pwallet->cs_wallet) { // Minimum confirmations int nMinDepth = 1; if (!params[0].isNull()) { diff --git a/src/wallet/test/psbt_wallet_tests.cpp b/src/wallet/test/psbt_wallet_tests.cpp --- a/src/wallet/test/psbt_wallet_tests.cpp +++ b/src/wallet/test/psbt_wallet_tests.cpp @@ -17,6 +17,8 @@ BOOST_FIXTURE_TEST_SUITE(psbt_wallet_tests, WalletTestingSetup) BOOST_AUTO_TEST_CASE(psbt_updater_test) { + LOCK(m_wallet.cs_wallet); + // Create prevtxs and add to wallet CDataStream s_prev_tx1( ParseHex("020000000158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f54" diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -487,9 +487,14 @@ Amount GetImmatureCredit(bool fUseCache = true) const EXCLUSIVE_LOCKS_REQUIRED(cs_main); Amount + // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct + // annotation "EXCLUSIVE_LOCKS_REQUIRED(cs_main, pwallet->cs_wallet)". The + // annotation "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid + // having to resolve the issue of member access into incomplete type + // CWallet. GetAvailableCredit(bool fUseCache = true, const isminefilter &filter = ISMINE_SPENDABLE) const - EXCLUSIVE_LOCKS_REQUIRED(cs_main); + NO_THREAD_SAFETY_ANALYSIS; Amount GetImmatureWatchOnlyCredit(const bool fUseCache = true) const EXCLUSIVE_LOCKS_REQUIRED(cs_main); Amount GetChange() const; @@ -529,7 +534,13 @@ bool AcceptToMemoryPool(const Amount nAbsurdFee, CValidationState &state) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - std::set GetConflicts() const; + // TODO: Remove "NO_THREAD_SAFETY_ANALYSIS" and replace it with the correct + // annotation "EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)". The annotation + // "NO_THREAD_SAFETY_ANALYSIS" was temporarily added to avoid having to + // resolve the issue of member access into incomplete type CWallet. Note + // that we still have the runtime check "AssertLockHeld(pwallet->cs_wallet)" + // in place. + std::set GetConflicts() const NO_THREAD_SAFETY_ANALYSIS; }; class COutput { @@ -728,7 +739,7 @@ std::mutex mutexScanning; friend class WalletRescanReserver; - WalletBatch *encrypted_batch = nullptr; + WalletBatch *encrypted_batch GUARDED_BY(cs_wallet) = nullptr; //! the current wallet version: clients below this version are not able to //! load the wallet @@ -736,7 +747,7 @@ //! the maximum wallet format version: memory-only variable that specifies //! to what version this wallet may be upgraded - int nWalletMaxVersion = FEATURE_BASE; + int nWalletMaxVersion GUARDED_BY(cs_wallet) = FEATURE_BASE; int64_t nNextResend = 0; int64_t nLastResend = 0; @@ -747,9 +758,10 @@ * (double-spends or mutated transactions where the mutant gets mined). */ typedef std::multimap TxSpends; - TxSpends mapTxSpends; - void AddToSpends(const COutPoint &outpoint, const TxId &wtxid); - void AddToSpends(const TxId &wtxid); + TxSpends mapTxSpends GUARDED_BY(cs_wallet); + void AddToSpends(const COutPoint &outpoint, const TxId &wtxid) + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + void AddToSpends(const TxId &wtxid) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** * Add a transaction to the wallet, or update it. pIndex and posInBlock @@ -781,9 +793,11 @@ * Mark a transaction's inputs dirty, thus forcing the outputs to be * recomputed */ - void MarkInputsDirty(const CTransactionRef &tx); + void MarkInputsDirty(const CTransactionRef &tx) + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - void SyncMetaData(std::pair); + void SyncMetaData(std::pair) + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** * Used by @@ -805,13 +819,13 @@ EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); std::set setInternalKeyPool; - std::set setExternalKeyPool; + std::set setExternalKeyPool GUARDED_BY(cs_wallet); std::set set_pre_split_keypool; - int64_t m_max_keypool_index = 0; + int64_t m_max_keypool_index GUARDED_BY(cs_wallet) = 0; std::map m_pool_key_to_index; std::atomic m_wallet_flags{0}; - int64_t nTimeFirstKey = 0; + int64_t nTimeFirstKey GUARDED_BY(cs_wallet) = 0; /** * Private version of AddWatchOnly method which does not accept a timestamp, @@ -869,7 +883,7 @@ std::set &setCoinsRet, Amount &nValueRet, const CCoinControl &coin_control, CoinSelectionParams &coin_selection_params, - bool &bnb_used) const; + bool &bnb_used) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); const WalletLocation &GetLocation() const { return m_location; } @@ -880,13 +894,13 @@ void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - void MarkPreSplitKeys(); + void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); // Map from Key ID to key metadata. - std::map mapKeyMetadata; + std::map mapKeyMetadata GUARDED_BY(cs_wallet); // Map from Script ID to key metadata (for watch-only keys). - std::map m_script_metadata; + std::map m_script_metadata GUARDED_BY(cs_wallet); typedef std::map MasterKeyMap; MasterKeyMap mapMasterKeys; @@ -903,19 +917,19 @@ encrypted_batch = nullptr; } - std::map mapWallet; + std::map mapWallet GUARDED_BY(cs_wallet); std::list laccentries; typedef std::pair TxPair; typedef std::multimap TxItems; TxItems wtxOrdered; - int64_t nOrderPosNext = 0; + int64_t nOrderPosNext GUARDED_BY(cs_wallet) = 0; uint64_t nAccountingEntryNumber = 0; std::map mapAddressBook; - std::set setLockedCoins; + std::set setLockedCoins GUARDED_BY(cs_wallet); const CWalletTx *GetWalletTx(const TxId &txid) const; @@ -951,7 +965,8 @@ * Find non-change parent output. */ const CTxOut &FindNonChangeParentOutput(const CTransaction &tx, - int output) const; + int output) const + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** * Shuffle and select coins until nTargetValue is reached while avoiding @@ -968,7 +983,7 @@ bool &bnb_used) const; bool IsSpent(const COutPoint &outpoint) const - EXCLUSIVE_LOCKS_REQUIRED(cs_main); + EXCLUSIVE_LOCKS_REQUIRED(cs_main, cs_wallet); std::vector GroupOutputs(const std::vector &outputs, bool single_coin) const; @@ -1080,11 +1095,13 @@ const Amount nAmount, std::string strComment = "") EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool GetLabelDestination(CTxDestination &dest, const std::string &label, - bool bForceNew = false); + bool bForceNew = false) + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void MarkDirty(); bool AddToWallet(const CWalletTx &wtxIn, bool fFlushOnClose = true); - void LoadToWallet(const CWalletTx &wtxIn); + void LoadToWallet(const CWalletTx &wtxIn) + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); void TransactionAddedToMempool(const CTransactionRef &tx) override; void BlockConnected(const std::shared_ptr &pblock, @@ -1281,7 +1298,8 @@ //! Get wallet transactions that conflict with given transaction (spend same //! outputs) - std::set GetConflicts(const TxId &txid) const; + std::set GetConflicts(const TxId &txid) const + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! Check if a given transaction has any of its outputs spent by another //! transaction in the wallet @@ -1553,7 +1571,8 @@ // be IsAllFromMe). int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, - bool use_max_sig = false); + bool use_max_sig = false) + EXCLUSIVE_LOCKS_REQUIRED(wallet->cs_wallet); int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector &txouts, diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4692,7 +4692,7 @@ // Try to top up keypool. No-op if the wallet is locked. walletInstance->TopUpKeyPool(); - LOCK(cs_main); + LOCK2(cs_main, walletInstance->cs_wallet); CBlockIndex *pindexRescan = chainActive.Genesis(); if (!gArgs.GetBoolArg("-rescan", false)) { @@ -4789,7 +4789,6 @@ walletInstance->SetBroadcastTransactions( gArgs.GetBoolArg("-walletbroadcast", DEFAULT_WALLETBROADCAST)); - LOCK(walletInstance->cs_wallet); walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize()); walletInstance->WalletLogPrintf("mapWallet.size() = %u\n",