Bitcoin Core  31.0.0
P2P Digital Currency
receive.cpp
Go to the documentation of this file.
1 // Copyright (c) 2021-present 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 <util/check.h>
8 #include <wallet/receive.h>
9 #include <wallet/transaction.h>
10 #include <wallet/wallet.h>
11 
12 namespace wallet {
13 bool 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 
23 bool AllInputsMine(const CWallet& wallet, const CTransaction& tx)
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 
74 bool 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 
100 static 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 
110 CAmount 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 
122 CAmount 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 
139 void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
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 
196 bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx)
197 {
198  if (!wtx.m_cached_from_me.has_value()) {
199  wtx.m_cached_from_me = wallet.IsFromMe(*wtx.tx);
200  }
201  return wtx.m_cached_from_me.value();
202 }
203 
204 // NOLINTNEXTLINE(misc-no-recursion)
205 bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<Txid>& trusted_parents)
206 {
207  AssertLockHeld(wallet.cs_wallet);
208 
209  // This wtx is already trusted
210  if (trusted_parents.contains(wtx.GetHash())) return true;
211 
212  if (wtx.isConfirmed()) return true;
213  if (wtx.isBlockConflicted()) return false;
214  // using wtx's cached debit
215  if (!wallet.m_spend_zero_conf_change || !CachedTxIsFromMe(wallet, wtx)) return false;
216 
217  // Don't trust unconfirmed transactions from us unless they are in the mempool.
218  if (!wtx.InMempool()) return false;
219 
220  // Trusted if all inputs are from us and are in the mempool:
221  for (const CTxIn& txin : wtx.tx->vin)
222  {
223  // Transactions not sent by us: not trusted
224  const CWalletTx* parent = wallet.GetWalletTx(txin.prevout.hash);
225  if (parent == nullptr) return false;
226  const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
227  // Check that this specific input being spent is trusted
228  if (!wallet.IsMine(parentOut)) return false;
229  // If we've already trusted this parent, continue
230  if (trusted_parents.contains(parent->GetHash())) continue;
231  // Recurse to check that the parent is also trusted
232  if (!CachedTxIsTrusted(wallet, *parent, trusted_parents)) return false;
233  trusted_parents.insert(parent->GetHash());
234  }
235  return true;
236 }
237 
238 bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx)
239 {
240  std::set<Txid> trusted_parents;
241  LOCK(wallet.cs_wallet);
242  return CachedTxIsTrusted(wallet, wtx, trusted_parents);
243 }
244 
245 Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
246 {
247  Balance ret;
248  bool allow_used_addresses = !avoid_reuse || !wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
249  {
250  LOCK(wallet.cs_wallet);
251  std::set<Txid> trusted_parents;
252  for (const auto& [outpoint, txo] : wallet.GetTXOs()) {
253  const CWalletTx& wtx = txo.GetWalletTx();
254 
255  const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)};
256  const int tx_depth{wallet.GetTxDepthInMainChain(wtx)};
257 
258  if (!wallet.IsSpent(outpoint) && (allow_used_addresses || !wallet.IsSpentKey(txo.GetTxOut().scriptPubKey))) {
259  // Get the amounts for mine
260  CAmount credit_mine = txo.GetTxOut().nValue;
261 
262  // Set the amounts in the return object
263  if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) {
264  ret.m_mine_immature += credit_mine;
265  } else if (is_trusted && tx_depth >= min_depth) {
266  ret.m_mine_trusted += credit_mine;
267  } else if (!is_trusted && wtx.InMempool()) {
268  ret.m_mine_untrusted_pending += credit_mine;
269  }
270  }
271  }
272  }
273  return ret;
274 }
275 
276 std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
277 {
278  std::map<CTxDestination, CAmount> balances;
279 
280  {
281  LOCK(wallet.cs_wallet);
282  std::set<Txid> trusted_parents;
283  for (const auto& [outpoint, txo] : wallet.GetTXOs()) {
284  const CWalletTx& wtx = txo.GetWalletTx();
285 
286  if (!CachedTxIsTrusted(wallet, wtx, trusted_parents)) continue;
287  if (wallet.IsTxImmatureCoinBase(wtx)) continue;
288 
289  int nDepth = wallet.GetTxDepthInMainChain(wtx);
290  if (nDepth < (CachedTxIsFromMe(wallet, wtx) ? 0 : 1)) continue;
291 
292  CTxDestination addr;
293  Assume(wallet.IsMine(txo.GetTxOut()));
294  if(!ExtractDestination(txo.GetTxOut().scriptPubKey, addr)) continue;
295 
296  CAmount n = wallet.IsSpent(outpoint) ? 0 : txo.GetTxOut().nValue;
297  balances[addr] += n;
298  }
299  }
300 
301  return balances;
302 }
303 
304 std::set< std::set<CTxDestination> > GetAddressGroupings(const CWallet& wallet)
305 {
306  AssertLockHeld(wallet.cs_wallet);
307  std::set< std::set<CTxDestination> > groupings;
308  std::set<CTxDestination> grouping;
309 
310  for (const auto& walletEntry : wallet.mapWallet)
311  {
312  const CWalletTx& wtx = walletEntry.second;
313 
314  if (wtx.tx->vin.size() > 0)
315  {
316  bool any_mine = false;
317  // group all input addresses with each other
318  for (const CTxIn& txin : wtx.tx->vin)
319  {
320  CTxDestination address;
321  if(!InputIsMine(wallet, txin)) /* If this input isn't mine, ignore it */
322  continue;
323  if(!ExtractDestination(wallet.mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
324  continue;
325  grouping.insert(address);
326  any_mine = true;
327  }
328 
329  // group change with input addresses
330  if (any_mine)
331  {
332  for (const CTxOut& txout : wtx.tx->vout)
333  if (OutputIsChange(wallet, txout))
334  {
335  CTxDestination txoutAddr;
336  if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
337  continue;
338  grouping.insert(txoutAddr);
339  }
340  }
341  if (grouping.size() > 0)
342  {
343  groupings.insert(grouping);
344  grouping.clear();
345  }
346  }
347 
348  // group lone addrs by themselves
349  for (const auto& txout : wtx.tx->vout)
350  if (wallet.IsMine(txout))
351  {
352  CTxDestination address;
353  if(!ExtractDestination(txout.scriptPubKey, address))
354  continue;
355  grouping.insert(address);
356  groupings.insert(grouping);
357  grouping.clear();
358  }
359  }
360 
361  std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
362  std::map< CTxDestination, std::set<CTxDestination>* > setmap; // map addresses to the unique group containing it
363  for (const std::set<CTxDestination>& _grouping : groupings)
364  {
365  // make a set of all the groups hit by this new group
366  std::set< std::set<CTxDestination>* > hits;
367  std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
368  for (const CTxDestination& address : _grouping)
369  if ((it = setmap.find(address)) != setmap.end())
370  hits.insert((*it).second);
371 
372  // merge all hit groups into a new single group and delete old groups
373  std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
374  for (std::set<CTxDestination>* hit : hits)
375  {
376  merged->insert(hit->begin(), hit->end());
377  uniqueGroupings.erase(hit);
378  delete hit;
379  }
380  uniqueGroupings.insert(merged);
381 
382  // update setmap
383  for (const CTxDestination& element : *merged)
384  setmap[element] = merged;
385  }
386 
387  std::set< std::set<CTxDestination> > ret;
388  for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)
389  {
390  ret.insert(*uniqueGrouping);
391  delete uniqueGrouping;
392  }
393 
394  return ret;
395 }
396 } // namespace wallet
CAmount nValue
Definition: transaction.h:142
CAmount CachedTxGetDebit(const CWallet &wallet, const CWalletTx &wtx, bool avoid_reuse)
Definition: receive.cpp:122
int ret
bool CachedTxIsTrusted(const CWallet &wallet, const CWalletTx &wtx, std::set< Txid > &trusted_parents)
Definition: receive.cpp:205
AssertLockHeld(pool.cs)
CScript scriptPubKey
Definition: transaction.h:143
bool OutputIsChange(const CWallet &wallet, const CTxOut &txout)
Definition: receive.cpp:74
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:276
bool MoneyRange(const CAmount &nValue)
Definition: amount.h:27
bool m_is_cache_empty
This flag is true if all m_amounts caches are empty.
Definition: transaction.h:249
CAmount CachedTxGetCredit(const CWallet &wallet, const CWalletTx &wtx, bool avoid_reuse)
Definition: receive.cpp:110
Balance GetBalance(const CWallet &wallet, const int min_depth, bool avoid_reuse)
Definition: receive.cpp:245
CAmount CachedTxGetChange(const CWallet &wallet, const CWalletTx &wtx)
Definition: receive.cpp:130
bool CachedTxIsFromMe(const CWallet &wallet, const CWalletTx &wtx)
Definition: receive.cpp:196
const std::vector< CTxIn > vin
Definition: transaction.h:291
bool IsUnspendable() const
Returns whether the script is guaranteed to fail at execution, regardless of the initial stack...
Definition: script.h:563
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
A transaction with a bunch of additional info that only the owner cares about.
Definition: transaction.h:194
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a scriptPubKey for the destination.
Definition: addresstype.cpp:49
An input of a transaction.
Definition: transaction.h:61
#define LOCK(cs)
Definition: sync.h:258
Txid hash
Definition: transaction.h:31
uint32_t n
Definition: transaction.h:32
const std::vector< CTxOut > vout
Definition: transaction.h:292
std::string ToString() const
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:309
An output of a transaction.
Definition: transaction.h:139
bool isBlockConflicted() const
Definition: transaction.h:363
std::set< std::set< CTxDestination > > GetAddressGroupings(const CWallet &wallet)
Definition: receive.cpp:304
#define Assume(val)
Assume is the identity function.
Definition: check.h:125
bool ScriptIsChange(const CWallet &wallet, const CScript &script)
Definition: receive.cpp:52
const Txid & GetHash() const LIFETIMEBOUND
Definition: transaction.h:367
CAmount OutputGetCredit(const CWallet &wallet, const CTxOut &txout)
Definition: receive.cpp:32
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:404
CAmount OutputGetChange(const CWallet &wallet, const CTxOut &txout)
Definition: receive.cpp:79
std::variant< CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown > CTxDestination
A txout script categorized into standard templates.
Definition: addresstype.h:143
void Set(bool avoid_reuse, CAmount value)
Definition: transaction.h:142
bool InMempool() const
Definition: transaction.cpp:27
CachableAmount m_amounts[AMOUNTTYPE_ENUM_ELEMENTS]
Definition: transaction.h:242
Definition: receive.h:31
bool InputIsMine(const CWallet &wallet, const CTxIn &txin)
Definition: receive.cpp:13
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:280
static CAmount GetCachableAmount(const CWallet &wallet, const CWalletTx &wtx, CWalletTx::AmountType type, bool avoid_reuse)
Definition: receive.cpp:100
CAmount nChangeCached
Definition: transaction.h:251
CAmount TxGetChange(const CWallet &wallet, const CTransaction &tx)
Definition: receive.cpp:87
COutPoint prevout
Definition: transaction.h:64
CTransactionRef tx
Definition: transaction.h:269
bool isConfirmed() const
Definition: transaction.h:366
bool AllInputsMine(const CWallet &wallet, const CTransaction &tx)
Returns whether all of the inputs belong to the wallet.
Definition: receive.cpp:23
std::optional< bool > m_cached_from_me
Definition: transaction.h:236
CAmount TxGetCredit(const CWallet &wallet, const CTransaction &tx)
Definition: receive.cpp:40