Skip to content

Commit 7721b31

Browse files
committed
Merge #19773: wallet: Avoid recursive lock in IsTrusted
772ea48 wallet: Avoid recursive lock in IsTrusted (João Barbosa) 819f10f wallet, refactor: Immutable CWalletTx::pwallet (João Barbosa) Pull request description: This change moves `CWalletTx::IsTrusted` to `CWallet` in order to have TSAN. So now `CWallet::IsTrusted` requires `cs_wallet` and the recursive lock no longer happens. Motivated by https://github.com/bitcoin/bitcoin/pull/19289/files#r473308226. ACKs for top commit: meshcollider: utACK 772ea48 hebasto: ACK 772ea48, reviewed and tested on Linux Mint 20 (x86_64). Tree-SHA512: 702ffd928b2f42a8b90de398790649a5fd04e1ac3877558da928e94cdeb19134883f06c3a73a6826c11c912facf199173375a70200737e164ccaea1bec515b2a
2 parents 61b8c04 + 772ea48 commit 7721b31

File tree

2 files changed

+18
-17
lines changed

2 files changed

+18
-17
lines changed

src/wallet/wallet.cpp

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,37 +1965,38 @@ bool CWalletTx::InMempool() const
19651965

19661966
bool CWalletTx::IsTrusted() const
19671967
{
1968-
std::set<uint256> s;
1969-
return IsTrusted(s);
1968+
std::set<uint256> trusted_parents;
1969+
LOCK(pwallet->cs_wallet);
1970+
return pwallet->IsTrusted(*this, trusted_parents);
19701971
}
19711972

1972-
bool CWalletTx::IsTrusted(std::set<uint256>& trusted_parents) const
1973+
bool CWallet::IsTrusted(const CWalletTx& wtx, std::set<uint256>& trusted_parents) const
19731974
{
1975+
AssertLockHeld(cs_wallet);
19741976
// Quick answer in most cases
1975-
if (!pwallet->chain().checkFinalTx(*tx)) return false;
1976-
int nDepth = GetDepthInMainChain();
1977+
if (!chain().checkFinalTx(*wtx.tx)) return false;
1978+
int nDepth = wtx.GetDepthInMainChain();
19771979
if (nDepth >= 1) return true;
19781980
if (nDepth < 0) return false;
19791981
// using wtx's cached debit
1980-
if (!pwallet->m_spend_zero_conf_change || !IsFromMe(ISMINE_ALL)) return false;
1982+
if (!m_spend_zero_conf_change || !wtx.IsFromMe(ISMINE_ALL)) return false;
19811983

19821984
// Don't trust unconfirmed transactions from us unless they are in the mempool.
1983-
if (!InMempool()) return false;
1985+
if (!wtx.InMempool()) return false;
19841986

19851987
// Trusted if all inputs are from us and are in the mempool:
1986-
LOCK(pwallet->cs_wallet);
1987-
for (const CTxIn& txin : tx->vin)
1988+
for (const CTxIn& txin : wtx.tx->vin)
19881989
{
19891990
// Transactions not sent by us: not trusted
1990-
const CWalletTx* parent = pwallet->GetWalletTx(txin.prevout.hash);
1991+
const CWalletTx* parent = GetWalletTx(txin.prevout.hash);
19911992
if (parent == nullptr) return false;
19921993
const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
19931994
// Check that this specific input being spent is trusted
1994-
if (pwallet->IsMine(parentOut) != ISMINE_SPENDABLE) return false;
1995+
if (IsMine(parentOut) != ISMINE_SPENDABLE) return false;
19951996
// If we've already trusted this parent, continue
19961997
if (trusted_parents.count(parent->GetHash())) continue;
19971998
// Recurse to check that the parent is also trusted
1998-
if (!parent->IsTrusted(trusted_parents)) return false;
1999+
if (!IsTrusted(*parent, trusted_parents)) return false;
19992000
trusted_parents.insert(parent->GetHash());
20002001
}
20012002
return true;
@@ -2081,7 +2082,7 @@ CWallet::Balance CWallet::GetBalance(const int min_depth, bool avoid_reuse) cons
20812082
for (const auto& entry : mapWallet)
20822083
{
20832084
const CWalletTx& wtx = entry.second;
2084-
const bool is_trusted{wtx.IsTrusted(trusted_parents)};
2085+
const bool is_trusted{IsTrusted(wtx, trusted_parents)};
20852086
const int tx_depth{wtx.GetDepthInMainChain()};
20862087
const CAmount tx_credit_mine{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_SPENDABLE | reuse_filter)};
20872088
const CAmount tx_credit_watchonly{wtx.GetAvailableCredit(/* fUseCache */ true, ISMINE_WATCH_ONLY | reuse_filter)};
@@ -2149,7 +2150,7 @@ void CWallet::AvailableCoins(std::vector<COutput>& vCoins, bool fOnlySafe, const
21492150
if (nDepth == 0 && !wtx.InMempool())
21502151
continue;
21512152

2152-
bool safeTx = wtx.IsTrusted(trusted_parents);
2153+
bool safeTx = IsTrusted(wtx, trusted_parents);
21532154

21542155
// We should not consider coins from transactions that are replacing
21552156
// other transactions.
@@ -3348,7 +3349,7 @@ std::map<CTxDestination, CAmount> CWallet::GetAddressBalances() const
33483349
{
33493350
const CWalletTx& wtx = walletEntry.second;
33503351

3351-
if (!wtx.IsTrusted(trusted_parents))
3352+
if (!IsTrusted(wtx, trusted_parents))
33523353
continue;
33533354

33543355
if (wtx.IsImmatureCoinBase())

src/wallet/wallet.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* pwallet,
275275
class CWalletTx
276276
{
277277
private:
278-
const CWallet* pwallet;
278+
const CWallet* const pwallet;
279279

280280
/** Constant used in hashBlock to indicate tx has been abandoned, only used at
281281
* serialization/deserialization to avoid ambiguity with conflicted.
@@ -502,7 +502,6 @@ class CWalletTx
502502

503503
bool InMempool() const;
504504
bool IsTrusted() const;
505-
bool IsTrusted(std::set<uint256>& trusted_parents) const;
506505

507506
int64_t GetTxTime() const;
508507

@@ -806,6 +805,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
806805
interfaces::Chain& chain() const { assert(m_chain); return *m_chain; }
807806

808807
const CWalletTx* GetWalletTx(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
808+
bool IsTrusted(const CWalletTx& wtx, std::set<uint256>& trusted_parents) 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; }

0 commit comments

Comments
 (0)