Bitcoin Core 29.99.0
P2P Digital Currency
receive.cpp
Go to the documentation of this file.
1// Copyright (c) 2021-2022 The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <consensus/amount.h>
7#include <util/check.h>
8#include <wallet/receive.h>
10#include <wallet/wallet.h>
11
12namespace wallet {
13bool InputIsMine(const CWallet& wallet, const CTxIn& txin)
14{
15 AssertLockHeld(wallet.cs_wallet);
16 const CWalletTx* prev = wallet.GetWalletTx(txin.prevout.hash);
17 if (prev && txin.prevout.n < prev->tx->vout.size()) {
18 return wallet.IsMine(prev->tx->vout[txin.prevout.n]);
19 }
20 return false;
21}
22
24{
25 LOCK(wallet.cs_wallet);
26 for (const CTxIn& txin : tx.vin) {
27 if (!InputIsMine(wallet, txin)) return false;
28 }
29 return true;
30}
31
33{
34 if (!MoneyRange(txout.nValue))
35 throw std::runtime_error(std::string(__func__) + ": value out of range");
36 LOCK(wallet.cs_wallet);
37 return (wallet.IsMine(txout) ? txout.nValue : 0);
38}
39
41{
42 CAmount nCredit = 0;
43 for (const CTxOut& txout : tx.vout)
44 {
45 nCredit += OutputGetCredit(wallet, txout);
46 if (!MoneyRange(nCredit))
47 throw std::runtime_error(std::string(__func__) + ": value out of range");
48 }
49 return nCredit;
50}
51
53{
54 // TODO: fix handling of 'change' outputs. The assumption is that any
55 // payment to a script that is ours, but is not in the address book
56 // is change. That assumption is likely to break when we implement multisignature
57 // wallets that return change back into a multi-signature-protected address;
58 // a better way of identifying which outputs are 'the send' and which are
59 // 'the change' will need to be implemented (maybe extend CWalletTx to remember
60 // which output, if any, was change).
61 AssertLockHeld(wallet.cs_wallet);
62 if (wallet.IsMine(script))
63 {
64 CTxDestination address;
65 if (!ExtractDestination(script, address))
66 return true;
67 if (!wallet.FindAddressBookEntry(address)) {
68 return true;
69 }
70 }
71 return false;
72}
73
74bool OutputIsChange(const CWallet& wallet, const CTxOut& txout)
75{
76 return ScriptIsChange(wallet, txout.scriptPubKey);
77}
78
80{
81 AssertLockHeld(wallet.cs_wallet);
82 if (!MoneyRange(txout.nValue))
83 throw std::runtime_error(std::string(__func__) + ": value out of range");
84 return (OutputIsChange(wallet, txout) ? txout.nValue : 0);
85}
86
88{
89 LOCK(wallet.cs_wallet);
90 CAmount nChange = 0;
91 for (const CTxOut& txout : tx.vout)
92 {
93 nChange += OutputGetChange(wallet, txout);
94 if (!MoneyRange(nChange))
95 throw std::runtime_error(std::string(__func__) + ": value out of range");
96 }
97 return nChange;
98}
99
100static CAmount GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, bool avoid_reuse)
101{
102 auto& amount = wtx.m_amounts[type];
103 if (!amount.IsCached(avoid_reuse)) {
104 amount.Set(avoid_reuse, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx) : TxGetCredit(wallet, *wtx.tx));
105 wtx.m_is_cache_empty = false;
106 }
107 return amount.Get(avoid_reuse);
108}
109
110CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, bool avoid_reuse)
111{
112 AssertLockHeld(wallet.cs_wallet);
113
114 // Must wait until coinbase is safely deep enough in the chain before valuing it
115 if (wallet.IsTxImmatureCoinBase(wtx))
116 return 0;
117
118 // GetBalance can assume transactions in mapWallet won't change
119 return GetCachableAmount(wallet, wtx, CWalletTx::CREDIT, avoid_reuse);
120}
121
122CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, bool avoid_reuse)
123{
124 if (wtx.tx->vin.empty())
125 return 0;
126
127 return GetCachableAmount(wallet, wtx, CWalletTx::DEBIT, avoid_reuse);
128}
129
131{
132 if (wtx.fChangeCached)
133 return wtx.nChangeCached;
134 wtx.nChangeCached = TxGetChange(wallet, *wtx.tx);
135 wtx.fChangeCached = true;
136 return wtx.nChangeCached;
137}
138
140 std::list<COutputEntry>& listReceived,
141 std::list<COutputEntry>& listSent, CAmount& nFee,
142 bool include_change)
143{
144 nFee = 0;
145 listReceived.clear();
146 listSent.clear();
147
148 // Compute fee:
149 CAmount nDebit = CachedTxGetDebit(wallet, wtx, /*avoid_reuse=*/false);
150 if (nDebit > 0) // debit>0 means we signed/sent this transaction
151 {
152 CAmount nValueOut = wtx.tx->GetValueOut();
153 nFee = nDebit - nValueOut;
154 }
155
156 LOCK(wallet.cs_wallet);
157 // Sent/received.
158 for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i)
159 {
160 const CTxOut& txout = wtx.tx->vout[i];
161 bool ismine = wallet.IsMine(txout);
162 // Only need to handle txouts if AT LEAST one of these is true:
163 // 1) they debit from us (sent)
164 // 2) the output is to us (received)
165 if (nDebit > 0)
166 {
167 if (!include_change && OutputIsChange(wallet, txout))
168 continue;
169 }
170 else if (!ismine)
171 continue;
172
173 // In either case, we need to get the destination address
174 CTxDestination address;
175
176 if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
177 {
178 wallet.WalletLogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
179 wtx.GetHash().ToString());
180 address = CNoDestination();
181 }
182
183 COutputEntry output = {address, txout.nValue, (int)i};
184
185 // If we are debited by the transaction, add the output as a "sent" entry
186 if (nDebit > 0)
187 listSent.push_back(output);
188
189 // If we are receiving the output, add it as a "received" entry
190 if (ismine)
191 listReceived.push_back(output);
192 }
193
194}
195
196bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx)
197{
198 return (CachedTxGetDebit(wallet, wtx, /*avoid_reuse=*/false) > 0);
199}
200
201// NOLINTNEXTLINE(misc-no-recursion)
202bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<Txid>& trusted_parents)
203{
204 AssertLockHeld(wallet.cs_wallet);
205
206 // This wtx is already trusted
207 if (trusted_parents.contains(wtx.GetHash())) return true;
208
209 if (wtx.isConfirmed()) return true;
210 if (wtx.isBlockConflicted()) return false;
211 // using wtx's cached debit
212 if (!wallet.m_spend_zero_conf_change || !CachedTxIsFromMe(wallet, wtx)) return false;
213
214 // Don't trust unconfirmed transactions from us unless they are in the mempool.
215 if (!wtx.InMempool()) return false;
216
217 // Trusted if all inputs are from us and are in the mempool:
218 for (const CTxIn& txin : wtx.tx->vin)
219 {
220 // Transactions not sent by us: not trusted
221 const CWalletTx* parent = wallet.GetWalletTx(txin.prevout.hash);
222 if (parent == nullptr) return false;
223 const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
224 // Check that this specific input being spent is trusted
225 if (!wallet.IsMine(parentOut)) return false;
226 // If we've already trusted this parent, continue
227 if (trusted_parents.count(parent->GetHash())) continue;
228 // Recurse to check that the parent is also trusted
229 if (!CachedTxIsTrusted(wallet, *parent, trusted_parents)) return false;
230 trusted_parents.insert(parent->GetHash());
231 }
232 return true;
233}
234
236{
237 std::set<Txid> trusted_parents;
238 LOCK(wallet.cs_wallet);
239 return CachedTxIsTrusted(wallet, wtx, trusted_parents);
240}
241
242Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
243{
244 Balance ret;
245 bool allow_used_addresses = !avoid_reuse || !wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
246 {
247 LOCK(wallet.cs_wallet);
248 std::set<Txid> trusted_parents;
249 for (const auto& [outpoint, txo] : wallet.GetTXOs()) {
250 const CWalletTx& wtx = txo.GetWalletTx();
251
252 const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)};
253 const int tx_depth{wallet.GetTxDepthInMainChain(wtx)};
254
255 if (!wallet.IsSpent(outpoint) && (allow_used_addresses || !wallet.IsSpentKey(txo.GetTxOut().scriptPubKey))) {
256 // Get the amounts for mine
257 CAmount credit_mine = txo.GetTxOut().nValue;
258
259 // Set the amounts in the return object
260 if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) {
261 ret.m_mine_immature += credit_mine;
262 } else if (is_trusted && tx_depth >= min_depth) {
263 ret.m_mine_trusted += credit_mine;
264 } else if (!is_trusted && wtx.InMempool()) {
265 ret.m_mine_untrusted_pending += credit_mine;
266 }
267 }
268 }
269 }
270 return ret;
271}
272
273std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
274{
275 std::map<CTxDestination, CAmount> balances;
276
277 {
278 LOCK(wallet.cs_wallet);
279 std::set<Txid> trusted_parents;
280 for (const auto& [outpoint, txo] : wallet.GetTXOs()) {
281 const CWalletTx& wtx = txo.GetWalletTx();
282
283 if (!CachedTxIsTrusted(wallet, wtx, trusted_parents)) continue;
284 if (wallet.IsTxImmatureCoinBase(wtx)) continue;
285
286 int nDepth = wallet.GetTxDepthInMainChain(wtx);
287 if (nDepth < (CachedTxIsFromMe(wallet, wtx) ? 0 : 1)) continue;
288
289 CTxDestination addr;
290 Assume(wallet.IsMine(txo.GetTxOut()));
291 if(!ExtractDestination(txo.GetTxOut().scriptPubKey, addr)) continue;
292
293 CAmount n = wallet.IsSpent(outpoint) ? 0 : txo.GetTxOut().nValue;
294 balances[addr] += n;
295 }
296 }
297
298 return balances;
299}
300
301std::set< std::set<CTxDestination> > GetAddressGroupings(const CWallet& wallet)
302{
303 AssertLockHeld(wallet.cs_wallet);
304 std::set< std::set<CTxDestination> > groupings;
305 std::set<CTxDestination> grouping;
306
307 for (const auto& walletEntry : wallet.mapWallet)
308 {
309 const CWalletTx& wtx = walletEntry.second;
310
311 if (wtx.tx->vin.size() > 0)
312 {
313 bool any_mine = false;
314 // group all input addresses with each other
315 for (const CTxIn& txin : wtx.tx->vin)
316 {
317 CTxDestination address;
318 if(!InputIsMine(wallet, txin)) /* If this input isn't mine, ignore it */
319 continue;
320 if(!ExtractDestination(wallet.mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
321 continue;
322 grouping.insert(address);
323 any_mine = true;
324 }
325
326 // group change with input addresses
327 if (any_mine)
328 {
329 for (const CTxOut& txout : wtx.tx->vout)
330 if (OutputIsChange(wallet, txout))
331 {
332 CTxDestination txoutAddr;
333 if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
334 continue;
335 grouping.insert(txoutAddr);
336 }
337 }
338 if (grouping.size() > 0)
339 {
340 groupings.insert(grouping);
341 grouping.clear();
342 }
343 }
344
345 // group lone addrs by themselves
346 for (const auto& txout : wtx.tx->vout)
347 if (wallet.IsMine(txout))
348 {
349 CTxDestination address;
350 if(!ExtractDestination(txout.scriptPubKey, address))
351 continue;
352 grouping.insert(address);
353 groupings.insert(grouping);
354 grouping.clear();
355 }
356 }
357
358 std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
359 std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it
360 for (const std::set<CTxDestination>& _grouping : groupings)
361 {
362 // make a set of all the groups hit by this new group
363 std::set< std::set<CTxDestination>* > hits;
364 std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
365 for (const CTxDestination& address : _grouping)
366 if ((it = setmap.find(address)) != setmap.end())
367 hits.insert((*it).second);
368
369 // merge all hit groups into a new single group and delete old groups
370 std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
371 for (std::set<CTxDestination>* hit : hits)
372 {
373 merged->insert(hit->begin(), hit->end());
374 uniqueGroupings.erase(hit);
375 delete hit;
376 }
377 uniqueGroupings.insert(merged);
378
379 // update setmap
380 for (const CTxDestination& element : *merged)
381 setmap[element] = merged;
382 }
383
384 std::set< std::set<CTxDestination> > ret;
385 for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)
386 {
387 ret.insert(*uniqueGrouping);
388 delete uniqueGrouping;
389 }
390
391 return ret;
392}
393} // namespace wallet
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a scriptPubKey for the destination.
Definition: addresstype.cpp:49
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:143
bool MoneyRange(const CAmount &nValue)
Definition: amount.h:27
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
int ret
#define Assume(val)
Assume is the identity function.
Definition: check.h:118
uint32_t n
Definition: transaction.h:32
Txid hash
Definition: transaction.h:31
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:413
bool IsUnspendable() const
Returns whether the script is guaranteed to fail at execution, regardless of the initial stack.
Definition: script.h:571
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:296
const std::vector< CTxOut > vout
Definition: transaction.h:307
const std::vector< CTxIn > vin
Definition: transaction.h:306
An input of a transaction.
Definition: transaction.h:67
COutPoint prevout
Definition: transaction.h:69
An output of a transaction.
Definition: transaction.h:150
CScript scriptPubKey
Definition: transaction.h:153
CAmount nValue
Definition: transaction.h:152
std::string ToString() const
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:311
A transaction with a bunch of additional info that only the owner cares about.
Definition: transaction.h:195
bool isConfirmed() const
Definition: transaction.h:363
bool isBlockConflicted() const
Definition: transaction.h:360
const Txid & GetHash() const LIFETIMEBOUND
Definition: transaction.h:364
CAmount nChangeCached
Definition: transaction.h:249
CTransactionRef tx
Definition: transaction.h:267
CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]
Definition: transaction.h:240
bool InMempool() const
Definition: transaction.cpp:27
bool m_is_cache_empty
This flag is true if all m_amounts caches are empty.
Definition: transaction.h:247
bool OutputIsChange(const CWallet &wallet, const CTxOut &txout)
Definition: receive.cpp:74
Balance GetBalance(const CWallet &wallet, const int min_depth, bool avoid_reuse)
Definition: receive.cpp:242
bool AllInputsMine(const CWallet &wallet, const CTransaction &tx)
Returns whether all of the inputs belong to the wallet.
Definition: receive.cpp:23
bool CachedTxIsFromMe(const CWallet &wallet, const CWalletTx &wtx)
Definition: receive.cpp:196
CAmount TxGetChange(const CWallet &wallet, const CTransaction &tx)
Definition: receive.cpp:87
bool CachedTxIsTrusted(const CWallet &wallet, const CWalletTx &wtx, std::set< Txid > &trusted_parents)
Definition: receive.cpp:202
bool ScriptIsChange(const CWallet &wallet, const CScript &script)
Definition: receive.cpp:52
CAmount TxGetCredit(const CWallet &wallet, const CTransaction &tx)
Definition: receive.cpp:40
static CAmount GetCachableAmount(const CWallet &wallet, const CWalletTx &wtx, CWalletTx::AmountType type, bool avoid_reuse)
Definition: receive.cpp:100
CAmount OutputGetChange(const CWallet &wallet, const CTxOut &txout)
Definition: receive.cpp:79
CAmount CachedTxGetDebit(const CWallet &wallet, const CWalletTx &wtx, bool avoid_reuse)
Definition: receive.cpp:122
CAmount CachedTxGetChange(const CWallet &wallet, const CWalletTx &wtx)
Definition: receive.cpp:130
CAmount CachedTxGetCredit(const CWallet &wallet, const CWalletTx &wtx, bool avoid_reuse)
Definition: receive.cpp:110
void CachedTxGetAmounts(const CWallet &wallet, const CWalletTx &wtx, std::list< COutputEntry > &listReceived, std::list< COutputEntry > &listSent, CAmount &nFee, bool include_change)
Definition: receive.cpp:139
std::map< CTxDestination, CAmount > GetAddressBalances(const CWallet &wallet)
Definition: receive.cpp:273
@ WALLET_FLAG_AVOID_REUSE
Definition: walletutil.h:21
bool InputIsMine(const CWallet &wallet, const CTxIn &txin)
Definition: receive.cpp:13
CAmount OutputGetCredit(const CWallet &wallet, const CTxOut &txout)
Definition: receive.cpp:32
std::set< std::set< CTxDestination > > GetAddressGroupings(const CWallet &wallet)
Definition: receive.cpp:301
Definition: receive.h:32
void Set(bool avoid_reuse, CAmount value)
Definition: transaction.h:142
#define LOCK(cs)
Definition: sync.h:259
AssertLockHeld(pool.cs)