Skip to content

Commit 91af7ef

Browse files
committed
Merge #19289: wallet: GetWalletTx and IsMine require cs_wallet lock
b8405b8 wallet: IsChange requires cs_wallet lock (João Barbosa) d8441f3 wallet: IsMine overloads require cs_wallet lock (João Barbosa) a13cafc wallet: GetWalletTx requires cs_wallet lock (João Barbosa) Pull request description: This change removes some unlock/lock and lock/lock cases regarding `GetWalletTx` and `IsMine` overloads. ACKs for top commit: laanwj: Code review ACK b8405b8 ryanofsky: Code review ACK b8405b8. Just new commit since last review changing IsChange GetChange locks and adding annotations Tree-SHA512: 40d37c4fe5d10a1407f57d899d5822bb285633d8dbfad8afcf15a9b41b428ed9971a9a7b1aae84318371155132df3002699a15dab56e004527d50c889829187d
2 parents 2562d5d + b8405b8 commit 91af7ef

File tree

3 files changed

+45
-32
lines changed

3 files changed

+45
-32
lines changed

src/interfaces/wallet.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace {
3737
//! Construct wallet tx struct.
3838
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
3939
{
40+
LOCK(wallet.cs_wallet);
4041
WalletTx result;
4142
result.tx = wtx.tx;
4243
result.txin_is_mine.reserve(wtx.tx->vin.size());
@@ -132,7 +133,11 @@ class WalletImpl : public Wallet
132133
{
133134
return m_wallet->SignMessage(message, pkhash, str_sig);
134135
}
135-
bool isSpendable(const CTxDestination& dest) override { return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; }
136+
bool isSpendable(const CTxDestination& dest) override
137+
{
138+
LOCK(m_wallet->cs_wallet);
139+
return m_wallet->IsMine(dest) & ISMINE_SPENDABLE;
140+
}
136141
bool haveWatchOnly() override
137142
{
138143
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();

src/wallet/wallet.cpp

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ std::string COutput::ToString() const
276276

277277
const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const
278278
{
279-
LOCK(cs_wallet);
279+
AssertLockHeld(cs_wallet);
280280
std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash);
281281
if (it == mapWallet.end())
282282
return nullptr;
@@ -1210,15 +1210,13 @@ void CWallet::BlockUntilSyncedToCurrentChain() const {
12101210

12111211
isminetype CWallet::IsMine(const CTxIn &txin) const
12121212
{
1213+
AssertLockHeld(cs_wallet);
1214+
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
1215+
if (mi != mapWallet.end())
12131216
{
1214-
LOCK(cs_wallet);
1215-
std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
1216-
if (mi != mapWallet.end())
1217-
{
1218-
const CWalletTx& prev = (*mi).second;
1219-
if (txin.prevout.n < prev.tx->vout.size())
1220-
return IsMine(prev.tx->vout[txin.prevout.n]);
1221-
}
1217+
const CWalletTx& prev = (*mi).second;
1218+
if (txin.prevout.n < prev.tx->vout.size())
1219+
return IsMine(prev.tx->vout[txin.prevout.n]);
12221220
}
12231221
return ISMINE_NO;
12241222
}
@@ -1243,16 +1241,19 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const
12431241

12441242
isminetype CWallet::IsMine(const CTxOut& txout) const
12451243
{
1244+
AssertLockHeld(cs_wallet);
12461245
return IsMine(txout.scriptPubKey);
12471246
}
12481247

12491248
isminetype CWallet::IsMine(const CTxDestination& dest) const
12501249
{
1250+
AssertLockHeld(cs_wallet);
12511251
return IsMine(GetScriptForDestination(dest));
12521252
}
12531253

12541254
isminetype CWallet::IsMine(const CScript& script) const
12551255
{
1256+
AssertLockHeld(cs_wallet);
12561257
isminetype result = ISMINE_NO;
12571258
for (const auto& spk_man_pair : m_spk_managers) {
12581259
result = std::max(result, spk_man_pair.second->IsMine(script));
@@ -1264,6 +1265,7 @@ CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) cons
12641265
{
12651266
if (!MoneyRange(txout.nValue))
12661267
throw std::runtime_error(std::string(__func__) + ": value out of range");
1268+
LOCK(cs_wallet);
12671269
return ((IsMine(txout) & filter) ? txout.nValue : 0);
12681270
}
12691271

@@ -1281,13 +1283,12 @@ bool CWallet::IsChange(const CScript& script) const
12811283
// a better way of identifying which outputs are 'the send' and which are
12821284
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
12831285
// which output, if any, was change).
1286+
AssertLockHeld(cs_wallet);
12841287
if (IsMine(script))
12851288
{
12861289
CTxDestination address;
12871290
if (!ExtractDestination(script, address))
12881291
return true;
1289-
1290-
LOCK(cs_wallet);
12911292
if (!FindAddressBookEntry(address)) {
12921293
return true;
12931294
}
@@ -1297,13 +1298,15 @@ bool CWallet::IsChange(const CScript& script) const
12971298

12981299
CAmount CWallet::GetChange(const CTxOut& txout) const
12991300
{
1301+
AssertLockHeld(cs_wallet);
13001302
if (!MoneyRange(txout.nValue))
13011303
throw std::runtime_error(std::string(__func__) + ": value out of range");
13021304
return (IsChange(txout) ? txout.nValue : 0);
13031305
}
13041306

13051307
bool CWallet::IsMine(const CTransaction& tx) const
13061308
{
1309+
AssertLockHeld(cs_wallet);
13071310
for (const CTxOut& txout : tx.vout)
13081311
if (IsMine(txout))
13091312
return true;
@@ -1362,6 +1365,7 @@ CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) c
13621365

13631366
CAmount CWallet::GetChange(const CTransaction& tx) const
13641367
{
1368+
LOCK(cs_wallet);
13651369
CAmount nChange = 0;
13661370
for (const CTxOut& txout : tx.vout)
13671371
{
@@ -1597,6 +1601,7 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived,
15971601
nFee = nDebit - nValueOut;
15981602
}
15991603

1604+
LOCK(pwallet->cs_wallet);
16001605
// Sent/received.
16011606
for (unsigned int i = 0; i < tx->vout.size(); ++i)
16021607
{
@@ -1983,6 +1988,7 @@ bool CWalletTx::IsTrusted(std::set<uint256>& trusted_parents) const
19831988
if (!InMempool()) return false;
19841989

19851990
// Trusted if all inputs are from us and are in the mempool:
1991+
LOCK(pwallet->cs_wallet);
19861992
for (const CTxIn& txin : tx->vin)
19871993
{
19881994
// Transactions not sent by us: not trusted
@@ -3194,15 +3200,17 @@ DBErrors CWallet::ZapWalletTx(std::list<CWalletTx>& vWtx)
31943200
bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose)
31953201
{
31963202
bool fUpdated = false;
3203+
bool is_mine;
31973204
{
31983205
LOCK(cs_wallet);
31993206
std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
32003207
fUpdated = (mi != m_address_book.end() && !mi->second.IsChange());
32013208
m_address_book[address].SetLabel(strName);
32023209
if (!strPurpose.empty()) /* update purpose only if requested */
32033210
m_address_book[address].purpose = strPurpose;
3211+
is_mine = IsMine(address) != ISMINE_NO;
32043212
}
3205-
NotifyAddressBookChanged(this, address, strName, IsMine(address) != ISMINE_NO,
3213+
NotifyAddressBookChanged(this, address, strName, is_mine,
32063214
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
32073215
if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose))
32083216
return false;
@@ -3217,27 +3225,27 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
32173225

32183226
bool CWallet::DelAddressBook(const CTxDestination& address)
32193227
{
3220-
// 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)
3221-
// NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
3222-
// When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
3223-
if (IsMine(address)) {
3224-
WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
3225-
return false;
3226-
}
3227-
3228+
bool is_mine;
32283229
{
32293230
LOCK(cs_wallet);
3230-
3231+
// 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)
3232+
// NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
3233+
// When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
3234+
if (IsMine(address)) {
3235+
WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT);
3236+
return false;
3237+
}
32313238
// Delete destdata tuples associated with address
32323239
std::string strAddress = EncodeDestination(address);
32333240
for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata)
32343241
{
32353242
WalletBatch(*database).EraseDestData(strAddress, item.first);
32363243
}
32373244
m_address_book.erase(address);
3245+
is_mine = IsMine(address) != ISMINE_NO;
32383246
}
32393247

3240-
NotifyAddressBookChanged(this, address, "", IsMine(address) != ISMINE_NO, "", CT_DELETED);
3248+
NotifyAddressBookChanged(this, address, "", is_mine, "", CT_DELETED);
32413249

32423250
WalletBatch(*database).ErasePurpose(EncodeDestination(address));
32433251
return WalletBatch(*database).EraseName(EncodeDestination(address));

src/wallet/wallet.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
805805
/** Interface for accessing chain state. */
806806
interfaces::Chain& chain() const { assert(m_chain); return *m_chain; }
807807

808-
const CWalletTx* GetWalletTx(const uint256& hash) const;
808+
const CWalletTx* GetWalletTx(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
809809

810810
//! check whether we are allowed to upgrade (or already support) to the named feature
811811
bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
@@ -1051,20 +1051,20 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
10511051
bool GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, std::string& error);
10521052
bool GetNewChangeDestination(const OutputType type, CTxDestination& dest, std::string& error);
10531053

1054-
isminetype IsMine(const CTxDestination& dest) const;
1055-
isminetype IsMine(const CScript& script) const;
1056-
isminetype IsMine(const CTxIn& txin) const;
1054+
isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
1055+
isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
1056+
isminetype IsMine(const CTxIn& txin) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
10571057
/**
10581058
* Returns amount of debit if the input matches the
10591059
* filter, otherwise returns 0
10601060
*/
10611061
CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const;
1062-
isminetype IsMine(const CTxOut& txout) const;
1062+
isminetype IsMine(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
10631063
CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const;
1064-
bool IsChange(const CTxOut& txout) const;
1065-
bool IsChange(const CScript& script) const;
1066-
CAmount GetChange(const CTxOut& txout) const;
1067-
bool IsMine(const CTransaction& tx) const;
1064+
bool IsChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
1065+
bool IsChange(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
1066+
CAmount GetChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
1067+
bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
10681068
/** should probably be renamed to IsRelevantToMe */
10691069
bool IsFromMe(const CTransaction& tx) const;
10701070
CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const;

0 commit comments

Comments
 (0)