Bitcoin Core 28.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 <wallet/receive.h>
9#include <wallet/wallet.h>
10
11namespace wallet {
13{
14 AssertLockHeld(wallet.cs_wallet);
15 const CWalletTx* prev = wallet.GetWalletTx(txin.prevout.hash);
16 if (prev && txin.prevout.n < prev->tx->vout.size()) {
17 return wallet.IsMine(prev->tx->vout[txin.prevout.n]);
18 }
19 return ISMINE_NO;
20}
21
22bool AllInputsMine(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter)
23{
24 LOCK(wallet.cs_wallet);
25 for (const CTxIn& txin : tx.vin) {
26 if (!(InputIsMine(wallet, txin) & filter)) return false;
27 }
28 return true;
29}
30
31CAmount OutputGetCredit(const CWallet& wallet, const CTxOut& txout, const isminefilter& filter)
32{
33 if (!MoneyRange(txout.nValue))
34 throw std::runtime_error(std::string(__func__) + ": value out of range");
35 LOCK(wallet.cs_wallet);
36 return ((wallet.IsMine(txout) & filter) ? txout.nValue : 0);
37}
38
39CAmount TxGetCredit(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter)
40{
41 CAmount nCredit = 0;
42 for (const CTxOut& txout : tx.vout)
43 {
44 nCredit += OutputGetCredit(wallet, txout, filter);
45 if (!MoneyRange(nCredit))
46 throw std::runtime_error(std::string(__func__) + ": value out of range");
47 }
48 return nCredit;
49}
50
52{
53 // TODO: fix handling of 'change' outputs. The assumption is that any
54 // payment to a script that is ours, but is not in the address book
55 // is change. That assumption is likely to break when we implement multisignature
56 // wallets that return change back into a multi-signature-protected address;
57 // a better way of identifying which outputs are 'the send' and which are
58 // 'the change' will need to be implemented (maybe extend CWalletTx to remember
59 // which output, if any, was change).
60 AssertLockHeld(wallet.cs_wallet);
61 if (wallet.IsMine(script))
62 {
63 CTxDestination address;
64 if (!ExtractDestination(script, address))
65 return true;
66 if (!wallet.FindAddressBookEntry(address)) {
67 return true;
68 }
69 }
70 return false;
71}
72
73bool OutputIsChange(const CWallet& wallet, const CTxOut& txout)
74{
75 return ScriptIsChange(wallet, txout.scriptPubKey);
76}
77
79{
80 AssertLockHeld(wallet.cs_wallet);
81 if (!MoneyRange(txout.nValue))
82 throw std::runtime_error(std::string(__func__) + ": value out of range");
83 return (OutputIsChange(wallet, txout) ? txout.nValue : 0);
84}
85
87{
88 LOCK(wallet.cs_wallet);
89 CAmount nChange = 0;
90 for (const CTxOut& txout : tx.vout)
91 {
92 nChange += OutputGetChange(wallet, txout);
93 if (!MoneyRange(nChange))
94 throw std::runtime_error(std::string(__func__) + ": value out of range");
95 }
96 return nChange;
97}
98
100{
101 auto& amount = wtx.m_amounts[type];
102 if (!amount.m_cached[filter]) {
103 amount.Set(filter, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx, filter) : TxGetCredit(wallet, *wtx.tx, filter));
104 wtx.m_is_cache_empty = false;
105 }
106 return amount.m_value[filter];
107}
108
110{
111 AssertLockHeld(wallet.cs_wallet);
112
113 // Must wait until coinbase is safely deep enough in the chain before valuing it
114 if (wallet.IsTxImmatureCoinBase(wtx))
115 return 0;
116
117 CAmount credit = 0;
118 const isminefilter get_amount_filter{filter & ISMINE_ALL};
119 if (get_amount_filter) {
120 // GetBalance can assume transactions in mapWallet won't change
121 credit += GetCachableAmount(wallet, wtx, CWalletTx::CREDIT, get_amount_filter);
122 }
123 return credit;
124}
125
127{
128 if (wtx.tx->vin.empty())
129 return 0;
130
131 CAmount debit = 0;
132 const isminefilter get_amount_filter{filter & ISMINE_ALL};
133 if (get_amount_filter) {
134 debit += GetCachableAmount(wallet, wtx, CWalletTx::DEBIT, get_amount_filter);
135 }
136 return debit;
137}
138
140{
141 if (wtx.fChangeCached)
142 return wtx.nChangeCached;
143 wtx.nChangeCached = TxGetChange(wallet, *wtx.tx);
144 wtx.fChangeCached = true;
145 return wtx.nChangeCached;
146}
147
149{
150 AssertLockHeld(wallet.cs_wallet);
151
152 if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) {
154 }
155
156 return 0;
157}
158
160{
161 AssertLockHeld(wallet.cs_wallet);
162
163 // Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future).
164 bool allow_cache = (filter & ISMINE_ALL) && (filter & ISMINE_ALL) != ISMINE_ALL;
165
166 // Must wait until coinbase is safely deep enough in the chain before valuing it
167 if (wallet.IsTxImmatureCoinBase(wtx))
168 return 0;
169
170 if (allow_cache && wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_cached[filter]) {
172 }
173
174 bool allow_used_addresses = (filter & ISMINE_USED) || !wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
175 CAmount nCredit = 0;
176 Txid hashTx = wtx.GetHash();
177 for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
178 const CTxOut& txout = wtx.tx->vout[i];
179 if (!wallet.IsSpent(COutPoint(hashTx, i)) && (allow_used_addresses || !wallet.IsSpentKey(txout.scriptPubKey))) {
180 nCredit += OutputGetCredit(wallet, txout, filter);
181 if (!MoneyRange(nCredit))
182 throw std::runtime_error(std::string(__func__) + " : value out of range");
183 }
184 }
185
186 if (allow_cache) {
187 wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].Set(filter, nCredit);
188 wtx.m_is_cache_empty = false;
189 }
190
191 return nCredit;
192}
193
195 std::list<COutputEntry>& listReceived,
196 std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter,
197 bool include_change)
198{
199 nFee = 0;
200 listReceived.clear();
201 listSent.clear();
202
203 // Compute fee:
204 CAmount nDebit = CachedTxGetDebit(wallet, wtx, filter);
205 if (nDebit > 0) // debit>0 means we signed/sent this transaction
206 {
207 CAmount nValueOut = wtx.tx->GetValueOut();
208 nFee = nDebit - nValueOut;
209 }
210
211 LOCK(wallet.cs_wallet);
212 // Sent/received.
213 for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i)
214 {
215 const CTxOut& txout = wtx.tx->vout[i];
216 isminetype fIsMine = wallet.IsMine(txout);
217 // Only need to handle txouts if AT LEAST one of these is true:
218 // 1) they debit from us (sent)
219 // 2) the output is to us (received)
220 if (nDebit > 0)
221 {
222 if (!include_change && OutputIsChange(wallet, txout))
223 continue;
224 }
225 else if (!(fIsMine & filter))
226 continue;
227
228 // In either case, we need to get the destination address
229 CTxDestination address;
230
231 if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
232 {
233 wallet.WalletLogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
234 wtx.GetHash().ToString());
235 address = CNoDestination();
236 }
237
238 COutputEntry output = {address, txout.nValue, (int)i};
239
240 // If we are debited by the transaction, add the output as a "sent" entry
241 if (nDebit > 0)
242 listSent.push_back(output);
243
244 // If we are receiving the output, add it as a "received" entry
245 if (fIsMine & filter)
246 listReceived.push_back(output);
247 }
248
249}
250
251bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
252{
253 return (CachedTxGetDebit(wallet, wtx, filter) > 0);
254}
255
256// NOLINTNEXTLINE(misc-no-recursion)
257bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<uint256>& trusted_parents)
258{
259 AssertLockHeld(wallet.cs_wallet);
260 if (wtx.isConfirmed()) return true;
261 if (wtx.isBlockConflicted()) return false;
262 // using wtx's cached debit
263 if (!wallet.m_spend_zero_conf_change || !CachedTxIsFromMe(wallet, wtx, ISMINE_ALL)) return false;
264
265 // Don't trust unconfirmed transactions from us unless they are in the mempool.
266 if (!wtx.InMempool()) return false;
267
268 // Trusted if all inputs are from us and are in the mempool:
269 for (const CTxIn& txin : wtx.tx->vin)
270 {
271 // Transactions not sent by us: not trusted
272 const CWalletTx* parent = wallet.GetWalletTx(txin.prevout.hash);
273 if (parent == nullptr) return false;
274 const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
275 // Check that this specific input being spent is trusted
276 if (wallet.IsMine(parentOut) != ISMINE_SPENDABLE) return false;
277 // If we've already trusted this parent, continue
278 if (trusted_parents.count(parent->GetHash())) continue;
279 // Recurse to check that the parent is also trusted
280 if (!CachedTxIsTrusted(wallet, *parent, trusted_parents)) return false;
281 trusted_parents.insert(parent->GetHash());
282 }
283 return true;
284}
285
287{
288 std::set<uint256> trusted_parents;
289 LOCK(wallet.cs_wallet);
290 return CachedTxIsTrusted(wallet, wtx, trusted_parents);
291}
292
293Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
294{
295 Balance ret;
296 isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED;
297 {
298 LOCK(wallet.cs_wallet);
299 std::set<uint256> trusted_parents;
300 for (const auto& entry : wallet.mapWallet)
301 {
302 const CWalletTx& wtx = entry.second;
303 const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)};
304 const int tx_depth{wallet.GetTxDepthInMainChain(wtx)};
305 const CAmount tx_credit_mine{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_SPENDABLE | reuse_filter)};
306 const CAmount tx_credit_watchonly{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_WATCH_ONLY | reuse_filter)};
307 if (is_trusted && tx_depth >= min_depth) {
308 ret.m_mine_trusted += tx_credit_mine;
309 ret.m_watchonly_trusted += tx_credit_watchonly;
310 }
311 if (!is_trusted && tx_depth == 0 && wtx.InMempool()) {
312 ret.m_mine_untrusted_pending += tx_credit_mine;
313 ret.m_watchonly_untrusted_pending += tx_credit_watchonly;
314 }
315 ret.m_mine_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_SPENDABLE);
316 ret.m_watchonly_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_WATCH_ONLY);
317 }
318 }
319 return ret;
320}
321
322std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
323{
324 std::map<CTxDestination, CAmount> balances;
325
326 {
327 LOCK(wallet.cs_wallet);
328 std::set<uint256> trusted_parents;
329 for (const auto& walletEntry : wallet.mapWallet)
330 {
331 const CWalletTx& wtx = walletEntry.second;
332
333 if (!CachedTxIsTrusted(wallet, wtx, trusted_parents))
334 continue;
335
336 if (wallet.IsTxImmatureCoinBase(wtx))
337 continue;
338
339 int nDepth = wallet.GetTxDepthInMainChain(wtx);
340 if (nDepth < (CachedTxIsFromMe(wallet, wtx, ISMINE_ALL) ? 0 : 1))
341 continue;
342
343 for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
344 const auto& output = wtx.tx->vout[i];
345 CTxDestination addr;
346 if (!wallet.IsMine(output))
347 continue;
348 if(!ExtractDestination(output.scriptPubKey, addr))
349 continue;
350
351 CAmount n = wallet.IsSpent(COutPoint(Txid::FromUint256(walletEntry.first), i)) ? 0 : output.nValue;
352 balances[addr] += n;
353 }
354 }
355 }
356
357 return balances;
358}
359
360std::set< std::set<CTxDestination> > GetAddressGroupings(const CWallet& wallet)
361{
362 AssertLockHeld(wallet.cs_wallet);
363 std::set< std::set<CTxDestination> > groupings;
364 std::set<CTxDestination> grouping;
365
366 for (const auto& walletEntry : wallet.mapWallet)
367 {
368 const CWalletTx& wtx = walletEntry.second;
369
370 if (wtx.tx->vin.size() > 0)
371 {
372 bool any_mine = false;
373 // group all input addresses with each other
374 for (const CTxIn& txin : wtx.tx->vin)
375 {
376 CTxDestination address;
377 if(!InputIsMine(wallet, txin)) /* If this input isn't mine, ignore it */
378 continue;
379 if(!ExtractDestination(wallet.mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
380 continue;
381 grouping.insert(address);
382 any_mine = true;
383 }
384
385 // group change with input addresses
386 if (any_mine)
387 {
388 for (const CTxOut& txout : wtx.tx->vout)
389 if (OutputIsChange(wallet, txout))
390 {
391 CTxDestination txoutAddr;
392 if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
393 continue;
394 grouping.insert(txoutAddr);
395 }
396 }
397 if (grouping.size() > 0)
398 {
399 groupings.insert(grouping);
400 grouping.clear();
401 }
402 }
403
404 // group lone addrs by themselves
405 for (const auto& txout : wtx.tx->vout)
406 if (wallet.IsMine(txout))
407 {
408 CTxDestination address;
409 if(!ExtractDestination(txout.scriptPubKey, address))
410 continue;
411 grouping.insert(address);
412 groupings.insert(grouping);
413 grouping.clear();
414 }
415 }
416
417 std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
418 std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it
419 for (const std::set<CTxDestination>& _grouping : groupings)
420 {
421 // make a set of all the groups hit by this new group
422 std::set< std::set<CTxDestination>* > hits;
423 std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
424 for (const CTxDestination& address : _grouping)
425 if ((it = setmap.find(address)) != setmap.end())
426 hits.insert((*it).second);
427
428 // merge all hit groups into a new single group and delete old groups
429 std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
430 for (std::set<CTxDestination>* hit : hits)
431 {
432 merged->insert(hit->begin(), hit->end());
433 uniqueGroupings.erase(hit);
434 delete hit;
435 }
436 uniqueGroupings.insert(merged);
437
438 // update setmap
439 for (const CTxDestination& element : *merged)
440 setmap[element] = merged;
441 }
442
443 std::set< std::set<CTxDestination> > ret;
444 for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)
445 {
446 ret.insert(*uniqueGrouping);
447 delete uniqueGrouping;
448 }
449
450 return ret;
451}
452} // 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:140
bool MoneyRange(const CAmount &nValue)
Definition: amount.h:27
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
int ret
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
uint32_t n
Definition: transaction.h:32
Txid hash
Definition: transaction.h:31
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:415
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
static transaction_identifier FromUint256(const uint256 &id)
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:300
A transaction with a bunch of additional info that only the owner cares about.
Definition: transaction.h:177
bool isConfirmed() const
Definition: transaction.h:350
bool isBlockConflicted() const
Definition: transaction.h:347
const Txid & GetHash() const LIFETIMEBOUND
Definition: transaction.h:351
CAmount nChangeCached
Definition: transaction.h:238
CTransactionRef tx
Definition: transaction.h:258
CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]
Definition: transaction.h:229
bool InMempool() const
Definition: transaction.cpp:21
bool m_is_cache_empty
This flag is true if all m_amounts caches are empty.
Definition: transaction.h:236
bool OutputIsChange(const CWallet &wallet, const CTxOut &txout)
Definition: receive.cpp:73
CAmount CachedTxGetAvailableCredit(const CWallet &wallet, const CWalletTx &wtx, const isminefilter &filter)
Definition: receive.cpp:159
Balance GetBalance(const CWallet &wallet, const int min_depth, bool avoid_reuse)
Definition: receive.cpp:293
CAmount TxGetChange(const CWallet &wallet, const CTransaction &tx)
Definition: receive.cpp:86
bool ScriptIsChange(const CWallet &wallet, const CScript &script)
Definition: receive.cpp:51
bool CachedTxIsFromMe(const CWallet &wallet, const CWalletTx &wtx, const isminefilter &filter)
Definition: receive.cpp:251
CAmount CachedTxGetDebit(const CWallet &wallet, const CWalletTx &wtx, const isminefilter &filter)
filter decides which addresses will count towards the debit
Definition: receive.cpp:126
void CachedTxGetAmounts(const CWallet &wallet, const CWalletTx &wtx, std::list< COutputEntry > &listReceived, std::list< COutputEntry > &listSent, CAmount &nFee, const isminefilter &filter, bool include_change)
Definition: receive.cpp:194
CAmount OutputGetCredit(const CWallet &wallet, const CTxOut &txout, const isminefilter &filter)
Definition: receive.cpp:31
CAmount CachedTxGetCredit(const CWallet &wallet, const CWalletTx &wtx, const isminefilter &filter)
Definition: receive.cpp:109
bool CachedTxIsTrusted(const CWallet &wallet, const CWalletTx &wtx, std::set< uint256 > &trusted_parents)
Definition: receive.cpp:257
CAmount TxGetCredit(const CWallet &wallet, const CTransaction &tx, const isminefilter &filter)
Definition: receive.cpp:39
std::underlying_type< isminetype >::type isminefilter
used for bitflags of isminetype
Definition: wallet.h:48
CAmount OutputGetChange(const CWallet &wallet, const CTxOut &txout)
Definition: receive.cpp:78
isminetype
IsMine() return codes, which depend on ScriptPubKeyMan implementation.
Definition: types.h:41
@ ISMINE_USED
Definition: types.h:45
@ ISMINE_NO
Definition: types.h:42
@ ISMINE_SPENDABLE
Definition: types.h:44
@ ISMINE_WATCH_ONLY
Definition: types.h:43
@ ISMINE_ALL
Definition: types.h:46
CAmount CachedTxGetChange(const CWallet &wallet, const CWalletTx &wtx)
Definition: receive.cpp:139
bool AllInputsMine(const CWallet &wallet, const CTransaction &tx, const isminefilter &filter)
Returns whether all of the inputs match the filter.
Definition: receive.cpp:22
isminetype InputIsMine(const CWallet &wallet, const CTxIn &txin)
Definition: receive.cpp:12
static CAmount GetCachableAmount(const CWallet &wallet, const CWalletTx &wtx, CWalletTx::AmountType type, const isminefilter &filter)
Definition: receive.cpp:99
CAmount CachedTxGetImmatureCredit(const CWallet &wallet, const CWalletTx &wtx, const isminefilter &filter)
Definition: receive.cpp:148
std::map< CTxDestination, CAmount > GetAddressBalances(const CWallet &wallet)
Definition: receive.cpp:322
@ WALLET_FLAG_AVOID_REUSE
Definition: walletutil.h:42
std::set< std::set< CTxDestination > > GetAddressGroupings(const CWallet &wallet)
Definition: receive.cpp:360
Definition: receive.h:37
void Set(isminefilter filter, CAmount value)
Definition: transaction.h:141
CAmount m_value[ISMINE_ENUM_ELEMENTS]
Definition: transaction.h:136
std::bitset< ISMINE_ENUM_ELEMENTS > m_cached
Definition: transaction.h:135
#define LOCK(cs)
Definition: sync.h:257
AssertLockHeld(pool.cs)