receive.cpp raw

   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, bool include_nonmempool)
 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              bool nonmempool_spent = false;
 259              switch (wallet.HowSpent(outpoint)) {
 260              case CWallet::SpendType::CONFIRMED:
 261              case CWallet::SpendType::MEMPOOL:
 262                  // treat as spent; ignore
 263                  break;
 264              case CWallet::SpendType::NONMEMPOOL:
 265                  if (!include_nonmempool) break;
 266                  nonmempool_spent = true;
 267                  [[fallthrough]];
 268              case CWallet::SpendType::UNSPENT:
 269                  CAmount* bucket = nullptr;
 270  
 271                  // Set the amounts in the return object
 272                  if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) {
 273                      bucket = &ret.m_mine_immature;
 274                  } else if (is_trusted && tx_depth >= min_depth) {
 275                      bucket = &ret.m_mine_trusted;
 276                  } else if (!is_trusted && wtx.InMempool()) {
 277                      bucket = &ret.m_mine_untrusted_pending;
 278                  }
 279                  if (bucket) {
 280                      // Get the amounts for mine
 281                      CAmount credit_mine = txo.GetTxOut().nValue;
 282  
 283                      if (!allow_used_addresses && wallet.IsSpentKey(txo.GetTxOut().scriptPubKey)) {
 284                          bucket = &ret.m_mine_used;
 285                      }
 286                      *bucket += credit_mine;
 287                      if (nonmempool_spent) {
 288                          ret.m_mine_nonmempool -= credit_mine;
 289                      }
 290                  }
 291              }
 292          }
 293      }
 294      return ret;
 295  }
 296  
 297  std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
 298  {
 299      std::map<CTxDestination, CAmount> balances;
 300  
 301      {
 302          LOCK(wallet.cs_wallet);
 303          std::set<Txid> trusted_parents;
 304          for (const auto& [outpoint, txo] : wallet.GetTXOs()) {
 305              const CWalletTx& wtx = txo.GetWalletTx();
 306  
 307              if (!CachedTxIsTrusted(wallet, wtx, trusted_parents)) continue;
 308              if (wallet.IsTxImmatureCoinBase(wtx)) continue;
 309  
 310              int nDepth = wallet.GetTxDepthInMainChain(wtx);
 311              if (nDepth < (CachedTxIsFromMe(wallet, wtx) ? 0 : 1)) continue;
 312  
 313              CTxDestination addr;
 314              Assume(wallet.IsMine(txo.GetTxOut()));
 315              if(!ExtractDestination(txo.GetTxOut().scriptPubKey, addr)) continue;
 316  
 317              CAmount n = wallet.IsSpent(outpoint) ? 0 : txo.GetTxOut().nValue;
 318              balances[addr] += n;
 319          }
 320      }
 321  
 322      return balances;
 323  }
 324  
 325  std::set< std::set<CTxDestination> > GetAddressGroupings(const CWallet& wallet)
 326  {
 327      AssertLockHeld(wallet.cs_wallet);
 328      std::set< std::set<CTxDestination> > groupings;
 329      std::set<CTxDestination> grouping;
 330  
 331      for (const auto& walletEntry : wallet.mapWallet)
 332      {
 333          const CWalletTx& wtx = walletEntry.second;
 334  
 335          if (wtx.tx->vin.size() > 0)
 336          {
 337              bool any_mine = false;
 338              // group all input addresses with each other
 339              for (const CTxIn& txin : wtx.tx->vin)
 340              {
 341                  CTxDestination address;
 342                  if(!InputIsMine(wallet, txin)) /* If this input isn't mine, ignore it */
 343                      continue;
 344                  if(!ExtractDestination(wallet.mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
 345                      continue;
 346                  grouping.insert(address);
 347                  any_mine = true;
 348              }
 349  
 350              // group change with input addresses
 351              if (any_mine)
 352              {
 353                 for (const CTxOut& txout : wtx.tx->vout)
 354                     if (OutputIsChange(wallet, txout))
 355                     {
 356                         CTxDestination txoutAddr;
 357                         if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
 358                             continue;
 359                         grouping.insert(txoutAddr);
 360                     }
 361              }
 362              if (grouping.size() > 0)
 363              {
 364                  groupings.insert(grouping);
 365                  grouping.clear();
 366              }
 367          }
 368  
 369          // group lone addrs by themselves
 370          for (const auto& txout : wtx.tx->vout)
 371              if (wallet.IsMine(txout))
 372              {
 373                  CTxDestination address;
 374                  if(!ExtractDestination(txout.scriptPubKey, address))
 375                      continue;
 376                  grouping.insert(address);
 377                  groupings.insert(grouping);
 378                  grouping.clear();
 379              }
 380      }
 381  
 382      std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
 383      std::map< CTxDestination, std::set<CTxDestination>* > setmap;  // map addresses to the unique group containing it
 384      for (const std::set<CTxDestination>& _grouping : groupings)
 385      {
 386          // make a set of all the groups hit by this new group
 387          std::set< std::set<CTxDestination>* > hits;
 388          std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
 389          for (const CTxDestination& address : _grouping)
 390              if ((it = setmap.find(address)) != setmap.end())
 391                  hits.insert((*it).second);
 392  
 393          // merge all hit groups into a new single group and delete old groups
 394          std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
 395          for (std::set<CTxDestination>* hit : hits)
 396          {
 397              merged->insert(hit->begin(), hit->end());
 398              uniqueGroupings.erase(hit);
 399              delete hit;
 400          }
 401          uniqueGroupings.insert(merged);
 402  
 403          // update setmap
 404          for (const CTxDestination& element : *merged)
 405              setmap[element] = merged;
 406      }
 407  
 408      std::set< std::set<CTxDestination> > ret;
 409      for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)
 410      {
 411          ret.insert(*uniqueGrouping);
 412          delete uniqueGrouping;
 413      }
 414  
 415      return ret;
 416  }
 417  } // namespace wallet
 418