/ src / wallet / receive.cpp
receive.cpp
  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  
 32  CAmount OutputGetCredit(const CWallet& wallet, const CTxOut& txout)
 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  
 40  CAmount TxGetCredit(const CWallet& wallet, const CTransaction& tx)
 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  
 52  bool ScriptIsChange(const CWallet& wallet, const CScript& script)
 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  
 79  CAmount OutputGetChange(const CWallet& wallet, const CTxOut& txout)
 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  
 87  CAmount TxGetChange(const CWallet& wallet, const CTransaction& tx)
 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  
130  CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx)
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