/ src / wallet / receive.cpp
receive.cpp
  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 {
 12  isminetype InputIsMine(const CWallet& wallet, const CTxIn& txin)
 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  
 78  CAmount OutputGetChange(const CWallet& wallet, const CTxOut& txout)
 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  
 86  CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx)
 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  
139  CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx)
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  
148  CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
149  {
150      AssertLockHeld(wallet.cs_wallet);
151  
152      if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) {
153          return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, filter);
154      }
155  
156      return 0;
157  }
158  
159  CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
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