Bitcoin Core  27.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>
6 #include <consensus/consensus.h>
7 #include <wallet/receive.h>
8 #include <wallet/transaction.h>
9 #include <wallet/wallet.h>
10 
11 namespace 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 
22 bool 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 
31 CAmount 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 
39 CAmount 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 
51 bool ScriptIsChange(const CWallet& wallet, const CScript& script)
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 
73 bool 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 
99 static CAmount GetCachableAmount(const CWallet& wallet, const CWalletTx& wtx, CWalletTx::AmountType type, const isminefilter& filter)
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 
109 CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
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 
126 CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
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]) {
171  return wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_value[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 
194 void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
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 
251 bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
252 {
253  return (CachedTxGetDebit(wallet, wtx, filter) > 0);
254 }
255 
256 bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<uint256>& trusted_parents)
257 {
258  AssertLockHeld(wallet.cs_wallet);
259  if (wtx.isConfirmed()) return true;
260  if (wtx.isBlockConflicted()) return false;
261  // using wtx's cached debit
262  if (!wallet.m_spend_zero_conf_change || !CachedTxIsFromMe(wallet, wtx, ISMINE_ALL)) return false;
263 
264  // Don't trust unconfirmed transactions from us unless they are in the mempool.
265  if (!wtx.InMempool()) return false;
266 
267  // Trusted if all inputs are from us and are in the mempool:
268  for (const CTxIn& txin : wtx.tx->vin)
269  {
270  // Transactions not sent by us: not trusted
271  const CWalletTx* parent = wallet.GetWalletTx(txin.prevout.hash);
272  if (parent == nullptr) return false;
273  const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
274  // Check that this specific input being spent is trusted
275  if (wallet.IsMine(parentOut) != ISMINE_SPENDABLE) return false;
276  // If we've already trusted this parent, continue
277  if (trusted_parents.count(parent->GetHash())) continue;
278  // Recurse to check that the parent is also trusted
279  if (!CachedTxIsTrusted(wallet, *parent, trusted_parents)) return false;
280  trusted_parents.insert(parent->GetHash());
281  }
282  return true;
283 }
284 
285 bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx)
286 {
287  std::set<uint256> trusted_parents;
288  LOCK(wallet.cs_wallet);
289  return CachedTxIsTrusted(wallet, wtx, trusted_parents);
290 }
291 
292 Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
293 {
294  Balance ret;
295  isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED;
296  {
297  LOCK(wallet.cs_wallet);
298  std::set<uint256> trusted_parents;
299  for (const auto& entry : wallet.mapWallet)
300  {
301  const CWalletTx& wtx = entry.second;
302  const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)};
303  const int tx_depth{wallet.GetTxDepthInMainChain(wtx)};
304  const CAmount tx_credit_mine{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_SPENDABLE | reuse_filter)};
305  const CAmount tx_credit_watchonly{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_WATCH_ONLY | reuse_filter)};
306  if (is_trusted && tx_depth >= min_depth) {
307  ret.m_mine_trusted += tx_credit_mine;
308  ret.m_watchonly_trusted += tx_credit_watchonly;
309  }
310  if (!is_trusted && tx_depth == 0 && wtx.InMempool()) {
311  ret.m_mine_untrusted_pending += tx_credit_mine;
312  ret.m_watchonly_untrusted_pending += tx_credit_watchonly;
313  }
314  ret.m_mine_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_SPENDABLE);
315  ret.m_watchonly_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_WATCH_ONLY);
316  }
317  }
318  return ret;
319 }
320 
321 std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
322 {
323  std::map<CTxDestination, CAmount> balances;
324 
325  {
326  LOCK(wallet.cs_wallet);
327  std::set<uint256> trusted_parents;
328  for (const auto& walletEntry : wallet.mapWallet)
329  {
330  const CWalletTx& wtx = walletEntry.second;
331 
332  if (!CachedTxIsTrusted(wallet, wtx, trusted_parents))
333  continue;
334 
335  if (wallet.IsTxImmatureCoinBase(wtx))
336  continue;
337 
338  int nDepth = wallet.GetTxDepthInMainChain(wtx);
339  if (nDepth < (CachedTxIsFromMe(wallet, wtx, ISMINE_ALL) ? 0 : 1))
340  continue;
341 
342  for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
343  const auto& output = wtx.tx->vout[i];
344  CTxDestination addr;
345  if (!wallet.IsMine(output))
346  continue;
347  if(!ExtractDestination(output.scriptPubKey, addr))
348  continue;
349 
350  CAmount n = wallet.IsSpent(COutPoint(Txid::FromUint256(walletEntry.first), i)) ? 0 : output.nValue;
351  balances[addr] += n;
352  }
353  }
354  }
355 
356  return balances;
357 }
358 
359 std::set< std::set<CTxDestination> > GetAddressGroupings(const CWallet& wallet)
360 {
361  AssertLockHeld(wallet.cs_wallet);
362  std::set< std::set<CTxDestination> > groupings;
363  std::set<CTxDestination> grouping;
364 
365  for (const auto& walletEntry : wallet.mapWallet)
366  {
367  const CWalletTx& wtx = walletEntry.second;
368 
369  if (wtx.tx->vin.size() > 0)
370  {
371  bool any_mine = false;
372  // group all input addresses with each other
373  for (const CTxIn& txin : wtx.tx->vin)
374  {
375  CTxDestination address;
376  if(!InputIsMine(wallet, txin)) /* If this input isn't mine, ignore it */
377  continue;
378  if(!ExtractDestination(wallet.mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
379  continue;
380  grouping.insert(address);
381  any_mine = true;
382  }
383 
384  // group change with input addresses
385  if (any_mine)
386  {
387  for (const CTxOut& txout : wtx.tx->vout)
388  if (OutputIsChange(wallet, txout))
389  {
390  CTxDestination txoutAddr;
391  if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
392  continue;
393  grouping.insert(txoutAddr);
394  }
395  }
396  if (grouping.size() > 0)
397  {
398  groupings.insert(grouping);
399  grouping.clear();
400  }
401  }
402 
403  // group lone addrs by themselves
404  for (const auto& txout : wtx.tx->vout)
405  if (wallet.IsMine(txout))
406  {
407  CTxDestination address;
408  if(!ExtractDestination(txout.scriptPubKey, address))
409  continue;
410  grouping.insert(address);
411  groupings.insert(grouping);
412  grouping.clear();
413  }
414  }
415 
416  std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
417  std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it
418  for (const std::set<CTxDestination>& _grouping : groupings)
419  {
420  // make a set of all the groups hit by this new group
421  std::set< std::set<CTxDestination>* > hits;
422  std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
423  for (const CTxDestination& address : _grouping)
424  if ((it = setmap.find(address)) != setmap.end())
425  hits.insert((*it).second);
426 
427  // merge all hit groups into a new single group and delete old groups
428  std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
429  for (std::set<CTxDestination>* hit : hits)
430  {
431  merged->insert(hit->begin(), hit->end());
432  uniqueGroupings.erase(hit);
433  delete hit;
434  }
435  uniqueGroupings.insert(merged);
436 
437  // update setmap
438  for (const CTxDestination& element : *merged)
439  setmap[element] = merged;
440  }
441 
442  std::set< std::set<CTxDestination> > ret;
443  for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)
444  {
445  ret.insert(*uniqueGrouping);
446  delete uniqueGrouping;
447  }
448 
449  return ret;
450 }
451 } // 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, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:131
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:414
bool IsUnspendable() const
Returns whether the script is guaranteed to fail at execution, regardless of the initial stack.
Definition: script.h:552
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:301
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:292
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:256
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:43
CAmount OutputGetChange(const CWallet &wallet, const CTxOut &txout)
Definition: receive.cpp:78
isminetype
IsMine() return codes, which depend on ScriptPubKeyMan implementation.
Definition: types.h:40
@ ISMINE_USED
Definition: types.h:44
@ ISMINE_NO
Definition: types.h:41
@ ISMINE_SPENDABLE
Definition: types.h:43
@ ISMINE_WATCH_ONLY
Definition: types.h:42
@ ISMINE_ALL
Definition: types.h:45
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:321
@ WALLET_FLAG_AVOID_REUSE
Definition: walletutil.h:42
std::set< std::set< CTxDestination > > GetAddressGroupings(const CWallet &wallet)
Definition: receive.cpp:359
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)