diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -32,6 +32,7 @@ //! Construct wallet tx struct. WalletTx MakeWalletTx(CWallet &wallet, const CWalletTx &wtx) { + LOCK(wallet.cs_wallet); WalletTx result; result.tx = wtx.tx; result.txin_is_mine.reserve(wtx.tx->vin.size()); @@ -145,6 +146,7 @@ return m_wallet->SignMessage(message, pkhash, str_sig); } bool isSpendable(const CTxDestination &dest) override { + LOCK(m_wallet->cs_wallet); return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; } bool haveWatchOnly() override { diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1254,20 +1254,26 @@ bool GetNewChangeDestination(const OutputType type, CTxDestination &dest, std::string &error); - isminetype IsMine(const CTxDestination &dest) const; - isminetype IsMine(const CScript &script) const; - isminetype IsMine(const CTxIn &txin) const; + isminetype IsMine(const CTxDestination &dest) const + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + isminetype IsMine(const CScript &script) const + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + isminetype IsMine(const CTxIn &txin) const + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** * Returns amount of debit if the input matches the filter, otherwise * returns 0 */ Amount GetDebit(const CTxIn &txin, const isminefilter &filter) const; - isminetype IsMine(const CTxOut &txout) const; + isminetype IsMine(const CTxOut &txout) const + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + ; Amount GetCredit(const CTxOut &txout, const isminefilter &filter) const; bool IsChange(const CTxOut &txout) const; bool IsChange(const CScript &script) const; Amount GetChange(const CTxOut &txout) const; - bool IsMine(const CTransaction &tx) const; + bool IsMine(const CTransaction &tx) const + EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** should probably be renamed to IsRelevantToMe */ bool IsFromMe(const CTransaction &tx) const; Amount GetDebit(const CTransaction &tx, const isminefilter &filter) const; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1317,7 +1317,7 @@ } isminetype CWallet::IsMine(const CTxIn &txin) const { - LOCK(cs_wallet); + AssertLockHeld(cs_wallet); std::map::const_iterator mi = mapWallet.find(txin.prevout.GetTxId()); if (mi != mapWallet.end()) { @@ -1349,14 +1349,17 @@ } isminetype CWallet::IsMine(const CTxOut &txout) const { + AssertLockHeld(cs_wallet); return IsMine(txout.scriptPubKey); } isminetype CWallet::IsMine(const CTxDestination &dest) const { + AssertLockHeld(cs_wallet); return IsMine(GetScriptForDestination(dest)); } isminetype CWallet::IsMine(const CScript &script) const { + AssertLockHeld(cs_wallet); isminetype result = ISMINE_NO; for (const auto &spk_man_pair : m_spk_managers) { result = std::max(result, spk_man_pair.second->IsMine(script)); @@ -1370,7 +1373,7 @@ throw std::runtime_error(std::string(__func__) + ": value out of range"); } - + LOCK(cs_wallet); return (IsMine(txout) & filter) ? txout.nValue : Amount::zero(); } @@ -1387,13 +1390,12 @@ // outputs are 'the send' and which are 'the change' will need to be // implemented (maybe extend CWalletTx to remember which output, if any, was // change). + LOCK(cs_wallet); if (IsMine(script)) { CTxDestination address; if (!ExtractDestination(script, address)) { return true; } - - LOCK(cs_wallet); if (!FindAddressBookEntry(address)) { return true; } @@ -1412,6 +1414,7 @@ } bool CWallet::IsMine(const CTransaction &tx) const { + AssertLockHeld(cs_wallet); for (const CTxOut &txout : tx.vout) { if (IsMine(txout)) { return true; @@ -1730,6 +1733,7 @@ nFee = (nDebit - nValueOut); } + LOCK(pwallet->cs_wallet); // Sent/received. for (unsigned int i = 0; i < tx->vout.size(); ++i) { const CTxOut &txout = tx->vout[i]; @@ -3565,6 +3569,7 @@ const std::string &strName, const std::string &strPurpose) { bool fUpdated = false; + bool is_mine; { LOCK(cs_wallet); std::map::iterator mi = @@ -3575,10 +3580,10 @@ if (!strPurpose.empty()) { m_address_book[address].purpose = strPurpose; } + is_mine = IsMine(address) != ISMINE_NO; } - NotifyAddressBookChanged(this, address, strName, - IsMine(address) != ISMINE_NO, strPurpose, + NotifyAddressBookChanged(this, address, strName, is_mine, strPurpose, (fUpdated ? CT_UPDATED : CT_NEW)); if (!strPurpose.empty() && !batch.WritePurpose(address, strPurpose)) { return false; @@ -3594,33 +3599,33 @@ } bool CWallet::DelAddressBook(const CTxDestination &address) { - // If we want to delete receiving addresses, we need to take care that - // DestData "used" (and possibly newer DestData) gets preserved (and the - // "deleted" address transformed into a change entry instead of actually - // being deleted) - // NOTE: This isn't a problem for sending addresses because they never have - // any DestData yet! When adding new DestData, it should be considered here - // whether to retain or delete it (or move it?). - if (IsMine(address)) { - WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please " - "report this bug! %s\n", - __func__, PACKAGE_BUGREPORT); - return false; - } - + bool is_mine; { LOCK(cs_wallet); - + // If we want to delete receiving addresses, we need to take care that + // DestData "used" (and possibly newer DestData) gets preserved (and the + // "deleted" address transformed into a change entry instead of actually + // being deleted) + // NOTE: This isn't a problem for sending addresses because they never + // have any DestData yet! When adding new DestData, it should be + // considered here whether to retain or delete it (or move it?). + if (IsMine(address)) { + WalletLogPrintf( + "%s called with IsMine address, NOT SUPPORTED. Please " + "report this bug! %s\n", + __func__, PACKAGE_BUGREPORT); + return false; + } // Delete destdata tuples associated with address for (const std::pair &item : m_address_book[address].destdata) { WalletBatch(*database).EraseDestData(address, item.first); } m_address_book.erase(address); + is_mine = IsMine(address) != ISMINE_NO; } - NotifyAddressBookChanged(this, address, "", IsMine(address) != ISMINE_NO, - "", CT_DELETED); + NotifyAddressBookChanged(this, address, "", is_mine, "", CT_DELETED); WalletBatch(*database).ErasePurpose(address); return WalletBatch(*database).EraseName(address);