Skip to content

Commit ae0876e

Browse files
committed
wallet: Keep track of transaction outputs owned by the wallet
When loading transactions to the wallet, check the outputs, and keep track of the ones that are IsMine.
1 parent 0f269bc commit ae0876e

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

src/wallet/transaction.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <primitives/transaction.h>
1111
#include <tinyformat.h>
1212
#include <uint256.h>
13+
#include <util/check.h>
1314
#include <util/overloaded.h>
1415
#include <util/strencodings.h>
1516
#include <util/string.h>
@@ -362,6 +363,30 @@ struct WalletTxOrderComparator {
362363
return a->nOrderPos < b->nOrderPos;
363364
}
364365
};
366+
367+
class WalletTXO
368+
{
369+
private:
370+
const CWalletTx& m_wtx;
371+
const CTxOut& m_output;
372+
isminetype m_ismine;
373+
374+
public:
375+
WalletTXO(const CWalletTx& wtx, const CTxOut& output, const isminetype ismine)
376+
: m_wtx(wtx),
377+
m_output(output),
378+
m_ismine(ismine)
379+
{
380+
Assume(std::ranges::find(wtx.tx->vout, output) != wtx.tx->vout.end());
381+
}
382+
383+
const CWalletTx& GetWalletTx() const { return m_wtx; }
384+
385+
const CTxOut& GetTxOut() const { return m_output; }
386+
387+
isminetype GetIsMine() const { return m_ismine; }
388+
void SetIsMine(isminetype ismine) { m_ismine = ismine; }
389+
};
365390
} // namespace wallet
366391

367392
#endif // BITCOIN_WALLET_TRANSACTION_H

src/wallet/wallet.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,9 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
10941094
// Break debit/credit balance caches:
10951095
wtx.MarkDirty();
10961096

1097+
// Cache the outputs that belong to the wallet
1098+
RefreshTXOsFromTx(wtx);
1099+
10971100
// Notify UI of new or updated transaction
10981101
NotifyTransactionChanged(hash, fInsertedNew ? CT_NEW : CT_UPDATED);
10991102

@@ -1157,6 +1160,8 @@ bool CWallet::LoadToWallet(const Txid& hash, const UpdateWalletTxFn& fill_wtx)
11571160
// Update birth time when tx time is older than it.
11581161
MaybeUpdateBirthTime(wtx.GetTxTime());
11591162

1163+
// Make sure the tx outputs are known by the wallet
1164+
RefreshTXOsFromTx(wtx);
11601165
return true;
11611166
}
11621167

@@ -2324,6 +2329,9 @@ util::Result<void> CWallet::RemoveTxs(WalletBatch& batch, std::vector<Txid>& txs
23242329
wtxOrdered.erase(it->second.m_it_wtxOrdered);
23252330
for (const auto& txin : it->second.tx->vin)
23262331
mapTxSpends.erase(txin.prevout);
2332+
for (unsigned int i = 0; i < it->second.tx->vout.size(); ++i) {
2333+
m_txos.erase(COutPoint(Txid::FromUint256(hash), i));
2334+
}
23272335
mapWallet.erase(it);
23282336
NotifyTransactionChanged(hash, CT_DELETED);
23292337
}
@@ -4425,4 +4433,22 @@ void CWallet::WriteBestBlock() const
44254433
batch.WriteBestBlock(loc);
44264434
}
44274435
}
4436+
4437+
void CWallet::RefreshTXOsFromTx(const CWalletTx& wtx)
4438+
{
4439+
AssertLockHeld(cs_wallet);
4440+
for (uint32_t i = 0; i < wtx.tx->vout.size(); ++i) {
4441+
const CTxOut& txout = wtx.tx->vout.at(i);
4442+
isminetype ismine = IsMine(txout);
4443+
if (ismine == ISMINE_NO) {
4444+
continue;
4445+
}
4446+
COutPoint outpoint(wtx.GetHash(), i);
4447+
if (m_txos.contains(outpoint)) {
4448+
m_txos.at(outpoint).SetIsMine(ismine);
4449+
} else {
4450+
m_txos.emplace(outpoint, WalletTXO{wtx, txout, ismine});
4451+
}
4452+
}
4453+
}
44284454
} // namespace wallet

src/wallet/wallet.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
438438
//! Cache of descriptor ScriptPubKeys used for IsMine. Maps ScriptPubKey to set of spkms
439439
std::unordered_map<CScript, std::vector<ScriptPubKeyMan*>, SaltedSipHasher> m_cached_spks;
440440

441+
//! Set of both spent and unspent transaction outputs owned by this wallet
442+
std::unordered_map<COutPoint, WalletTXO, SaltedOutpointHasher> m_txos GUARDED_BY(cs_wallet);
443+
441444
/**
442445
* Catch wallet up to current chain, scanning new blocks, updating the best
443446
* block locator and m_last_block_processed, and registering for
@@ -520,6 +523,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
520523

521524
std::set<Txid> GetTxConflicts(const CWalletTx& wtx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
522525

526+
/** Cache outputs that belong to the wallet from a single transaction */
527+
void RefreshTXOsFromTx(const CWalletTx& wtx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
528+
523529
/**
524530
* Return depth of transaction in blockchain:
525531
* <0 : conflicts with a transaction this deep in the blockchain

0 commit comments

Comments
 (0)