receive.cpp raw

   1  // Copyright (c) 2021-2022 The Limenka 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  isminetype 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 ISMINE_NO;
  21  }
  22  
  23  bool AllInputsMine(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter)
  24  {
  25      LOCK(wallet.cs_wallet);
  26      for (const CTxIn& txin : tx.vin) {
  27          if (!(InputIsMine(wallet, txin) & filter)) return false;
  28      }
  29      return true;
  30  }
  31  
  32  CAmount OutputGetCredit(const CWallet& wallet, const CTxOut& txout, const isminefilter& filter)
  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) & filter) ? txout.nValue : 0);
  38  }
  39  
  40  CAmount TxGetCredit(const CWallet& wallet, const CTransaction& tx, const isminefilter& filter)
  41  {
  42      CAmount nCredit = 0;
  43      for (const CTxOut& txout : tx.vout)
  44      {
  45          nCredit += OutputGetCredit(wallet, txout, filter);
  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, const isminefilter& filter)
 101  {
 102      auto& amount = wtx.m_amounts[type];
 103      if (!amount.m_cached[filter]) {
 104          amount.Set(filter, type == CWalletTx::DEBIT ? wallet.GetDebit(*wtx.tx, filter) : TxGetCredit(wallet, *wtx.tx, filter));
 105          wtx.m_is_cache_empty = false;
 106      }
 107      return amount.m_value[filter];
 108  }
 109  
 110  CAmount CachedTxGetCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
 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      CAmount credit = 0;
 119      const isminefilter get_amount_filter{filter & ISMINE_ALL};
 120      if (get_amount_filter) {
 121          // GetBalance can assume transactions in mapWallet won't change
 122          credit += GetCachableAmount(wallet, wtx, CWalletTx::CREDIT, get_amount_filter);
 123      }
 124      return credit;
 125  }
 126  
 127  CAmount CachedTxGetDebit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
 128  {
 129      if (wtx.tx->vin.empty())
 130          return 0;
 131  
 132      CAmount debit = 0;
 133      const isminefilter get_amount_filter{filter & ISMINE_ALL};
 134      if (get_amount_filter) {
 135          debit += GetCachableAmount(wallet, wtx, CWalletTx::DEBIT, get_amount_filter);
 136      }
 137      return debit;
 138  }
 139  
 140  CAmount CachedTxGetChange(const CWallet& wallet, const CWalletTx& wtx)
 141  {
 142      if (wtx.fChangeCached)
 143          return wtx.nChangeCached;
 144      wtx.nChangeCached = TxGetChange(wallet, *wtx.tx);
 145      wtx.fChangeCached = true;
 146      return wtx.nChangeCached;
 147  }
 148  
 149  CAmount CachedTxGetImmatureCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
 150  {
 151      AssertLockHeld(wallet.cs_wallet);
 152  
 153      if (wallet.IsTxImmatureCoinBase(wtx) && wtx.isConfirmed()) {
 154          return GetCachableAmount(wallet, wtx, CWalletTx::IMMATURE_CREDIT, filter);
 155      }
 156  
 157      return 0;
 158  }
 159  
 160  CAmount CachedTxGetAvailableCredit(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
 161  {
 162      AssertLockHeld(wallet.cs_wallet);
 163  
 164      // Avoid caching ismine for NO or ALL cases (could remove this check and simplify in the future).
 165      bool allow_cache = (filter & ISMINE_ALL) && (filter & ISMINE_ALL) != ISMINE_ALL;
 166  
 167      // Must wait until coinbase is safely deep enough in the chain before valuing it
 168      if (wallet.IsTxImmatureCoinBase(wtx))
 169          return 0;
 170  
 171      if (allow_cache && wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_cached[filter]) {
 172          return wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].m_value[filter];
 173      }
 174  
 175      bool allow_used_addresses = (filter & ISMINE_USED) || !wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
 176      CAmount nCredit = 0;
 177      Txid hashTx = wtx.GetHash();
 178      for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
 179          const CTxOut& txout = wtx.tx->vout[i];
 180          if (!wallet.IsSpent(COutPoint(hashTx, i)) && (allow_used_addresses || !wallet.IsSpentKey(txout.scriptPubKey))) {
 181              nCredit += OutputGetCredit(wallet, txout, filter);
 182              if (!MoneyRange(nCredit))
 183                  throw std::runtime_error(std::string(__func__) + " : value out of range");
 184          }
 185      }
 186  
 187      if (allow_cache) {
 188          wtx.m_amounts[CWalletTx::AVAILABLE_CREDIT].Set(filter, nCredit);
 189          wtx.m_is_cache_empty = false;
 190      }
 191  
 192      return nCredit;
 193  }
 194  
 195  void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
 196                    std::list<COutputEntry>& listReceived,
 197                    std::list<COutputEntry>& listSent, CAmount& nFee, const isminefilter& filter,
 198                    bool include_change)
 199  {
 200      nFee = 0;
 201      listReceived.clear();
 202      listSent.clear();
 203  
 204      // Compute fee:
 205      CAmount nDebit = CachedTxGetDebit(wallet, wtx, filter);
 206      if (nDebit > 0) // debit>0 means we signed/sent this transaction
 207      {
 208          CAmount nValueOut = wtx.tx->GetValueOut();
 209          nFee = nDebit - nValueOut;
 210      }
 211  
 212      LOCK(wallet.cs_wallet);
 213      // Sent/received.
 214      for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i)
 215      {
 216          const CTxOut& txout = wtx.tx->vout[i];
 217          isminetype fIsMine = wallet.IsMine(txout);
 218          // Only need to handle txouts if AT LEAST one of these is true:
 219          //   1) they debit from us (sent)
 220          //   2) the output is to us (received)
 221          if (nDebit > 0)
 222          {
 223              if (!include_change && OutputIsChange(wallet, txout))
 224                  continue;
 225          }
 226          else if (!(fIsMine & filter))
 227              continue;
 228  
 229          // In either case, we need to get the destination address
 230          CTxDestination address;
 231  
 232          if (!ExtractDestination(txout.scriptPubKey, address) && !txout.scriptPubKey.IsUnspendable())
 233          {
 234              wallet.WalletLogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
 235                                      wtx.GetHash().ToString());
 236              address = CNoDestination();
 237          }
 238  
 239          COutputEntry output = {address, txout.nValue, (int)i};
 240  
 241          // If we are debited by the transaction, add the output as a "sent" entry
 242          if (nDebit > 0)
 243              listSent.push_back(output);
 244  
 245          // If we are receiving the output, add it as a "received" entry
 246          if (fIsMine & filter)
 247              listReceived.push_back(output);
 248      }
 249  
 250  }
 251  
 252  bool CachedTxIsFromMe(const CWallet& wallet, const CWalletTx& wtx, const isminefilter& filter)
 253  {
 254      return (CachedTxGetDebit(wallet, wtx, filter) > 0);
 255  }
 256  
 257  // NOLINTNEXTLINE(misc-no-recursion)
 258  bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx, std::set<uint256>& trusted_parents)
 259  {
 260      AssertLockHeld(wallet.cs_wallet);
 261      if (wtx.isConfirmed()) return true;
 262      if (wtx.isBlockConflicted()) return false;
 263      // using wtx's cached debit
 264      if (!wallet.m_spend_zero_conf_change || !CachedTxIsFromMe(wallet, wtx, ISMINE_ALL)) return false;
 265  
 266      // Don't trust unconfirmed transactions from us unless they are in the mempool.
 267      if (!wtx.InMempool()) return false;
 268  
 269      // Trusted if all inputs are from us and are in the mempool:
 270      for (const CTxIn& txin : wtx.tx->vin)
 271      {
 272          // Transactions not sent by us: not trusted
 273          const CWalletTx* parent = wallet.GetWalletTx(txin.prevout.hash);
 274          if (parent == nullptr) return false;
 275          const CTxOut& parentOut = parent->tx->vout[txin.prevout.n];
 276          // Check that this specific input being spent is trusted
 277          if (wallet.IsMine(parentOut) != ISMINE_SPENDABLE) return false;
 278          // If we've already trusted this parent, continue
 279          if (trusted_parents.count(parent->GetHash())) continue;
 280          // Recurse to check that the parent is also trusted
 281          if (!CachedTxIsTrusted(wallet, *parent, trusted_parents)) return false;
 282          trusted_parents.insert(parent->GetHash());
 283      }
 284      return true;
 285  }
 286  
 287  bool CachedTxIsTrusted(const CWallet& wallet, const CWalletTx& wtx)
 288  {
 289      std::set<uint256> trusted_parents;
 290      LOCK(wallet.cs_wallet);
 291      return CachedTxIsTrusted(wallet, wtx, trusted_parents);
 292  }
 293  
 294  Balance GetBalance(const CWallet& wallet, const int min_depth, bool avoid_reuse)
 295  {
 296      Balance ret;
 297      isminefilter reuse_filter = avoid_reuse ? ISMINE_NO : ISMINE_USED;
 298      {
 299          LOCK(wallet.cs_wallet);
 300          std::set<uint256> trusted_parents;
 301          for (const auto& entry : wallet.mapWallet)
 302          {
 303              const CWalletTx& wtx = entry.second;
 304              const bool is_trusted{CachedTxIsTrusted(wallet, wtx, trusted_parents)};
 305              const int tx_depth{wallet.GetTxDepthInMainChain(wtx)};
 306              const CAmount tx_credit_mine{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_SPENDABLE | reuse_filter)};
 307              const CAmount tx_credit_watchonly{CachedTxGetAvailableCredit(wallet, wtx, ISMINE_WATCH_ONLY | reuse_filter)};
 308              if (is_trusted && tx_depth >= min_depth) {
 309                  ret.m_mine_trusted += tx_credit_mine;
 310                  ret.m_watchonly_trusted += tx_credit_watchonly;
 311              }
 312              if (!is_trusted && tx_depth == 0 && wtx.InMempool()) {
 313                  ret.m_mine_untrusted_pending += tx_credit_mine;
 314                  ret.m_watchonly_untrusted_pending += tx_credit_watchonly;
 315              }
 316              ret.m_mine_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_SPENDABLE);
 317              ret.m_watchonly_immature += CachedTxGetImmatureCredit(wallet, wtx, ISMINE_WATCH_ONLY);
 318          }
 319      }
 320      return ret;
 321  }
 322  
 323  // Calculate total balance in a different way from GetBalance. The biggest
 324  // difference is that GetBalance sums up all unspent TxOuts paying to the
 325  // wallet, while this sums up both spent and unspent TxOuts paying to the
 326  // wallet, and then subtracts the values of TxIns spending from the wallet. This
 327  // also has fewer restrictions on which unconfirmed transactions are considered
 328  // trusted.
 329  CAmount CWallet::GetLegacyBalance(const isminefilter& filter, int minDepth) const
 330  {
 331      LOCK(cs_wallet);
 332  
 333      const auto tip_height = GetLastBlockHeight();
 334      const auto tip_blockhash = m_last_block_processed;
 335      int64_t tip_mtp = -1;
 336      const auto checkFinalTx = [&](const CTransaction& tx) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) {
 337          // cloned from tx_verify:IsFinalTx, but optimised a bit
 338          // NOTE: LOCKTIME_THRESHOLD would need to be checked before AD ~11500
 339          // NOTE: <= rather than < because we care about the *next* block
 340          if ((int64_t)tx.nLockTime <= tip_height) {
 341              return true;
 342          }
 343          for (const auto& txin : tx.vin) {
 344              if (!(txin.nSequence == CTxIn::SEQUENCE_FINAL)) {
 345                  if (tx.nLockTime >= LOCKTIME_THRESHOLD) {
 346                      if (tip_mtp == -1) {
 347                          CHECK_NONFATAL(this->chain().findBlock(tip_blockhash, interfaces::FoundBlock().mtpTime(tip_mtp)));
 348                      }
 349                      if (tx.nLockTime < tip_mtp) {
 350                          return true;
 351                      }
 352                  }
 353  
 354                  return false;
 355              }
 356          }
 357          return true;
 358      };
 359  
 360      CAmount balance = 0;
 361      for (const auto& entry : mapWallet) {
 362          const CWalletTx& wtx = entry.second;
 363          const int depth = GetTxDepthInMainChain(wtx);
 364          if (depth < 0 || IsTxImmatureCoinBase(wtx)) {
 365              continue;
 366          }
 367  
 368          if (depth == 0) {
 369              bool have_conflicts = false;
 370              for (const CTxIn& txin : wtx.tx->vin) {
 371                  if (mapTxSpends.count(txin.prevout) > 1) {
 372                      have_conflicts = true;
 373                      break;
 374                  }
 375              }
 376              if (have_conflicts && !wtx.InMempool()) {
 377                  // Rather than include two conflicting unconfirmed transactions in the same balance, only include ones in our mempool (which cannot contain conflicts)
 378                  continue;
 379              }
 380  
 381              if (!checkFinalTx(*wtx.tx)) {
 382                  continue;
 383              }
 384          }
 385  
 386          // Loop through tx outputs and add incoming payments. For outgoing txs,
 387          // treat change outputs specially, as part of the amount debited.
 388          CAmount debit = GetDebit(*wtx.tx, filter);
 389          const bool outgoing = debit > 0;
 390          for (const CTxOut& out : wtx.tx->vout) {
 391              if (outgoing && OutputIsChange(*this, out)) {
 392                  debit -= out.nValue;
 393              } else if (IsMine(out) & filter && depth >= minDepth) {
 394                  balance += out.nValue;
 395              }
 396          }
 397  
 398          // For outgoing txs, subtract amount debited.
 399          if (outgoing) {
 400              balance -= debit;
 401          }
 402      }
 403  
 404      return balance;
 405  }
 406  
 407  std::map<CTxDestination, CAmount> GetAddressBalances(const CWallet& wallet)
 408  {
 409      std::map<CTxDestination, CAmount> balances;
 410  
 411      {
 412          LOCK(wallet.cs_wallet);
 413          std::set<uint256> trusted_parents;
 414          for (const auto& walletEntry : wallet.mapWallet)
 415          {
 416              const CWalletTx& wtx = walletEntry.second;
 417  
 418              if (!CachedTxIsTrusted(wallet, wtx, trusted_parents))
 419                  continue;
 420  
 421              if (wallet.IsTxImmatureCoinBase(wtx))
 422                  continue;
 423  
 424              int nDepth = wallet.GetTxDepthInMainChain(wtx);
 425              if (nDepth < (CachedTxIsFromMe(wallet, wtx, ISMINE_ALL) ? 0 : 1))
 426                  continue;
 427  
 428              for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
 429                  const auto& output = wtx.tx->vout[i];
 430                  CTxDestination addr;
 431                  if (!wallet.IsMine(output))
 432                      continue;
 433                  if(!ExtractDestination(output.scriptPubKey, addr))
 434                      continue;
 435  
 436                  CAmount n = wallet.IsSpent(COutPoint(Txid::FromUint256(walletEntry.first), i)) ? 0 : output.nValue;
 437                  balances[addr] += n;
 438              }
 439          }
 440      }
 441  
 442      return balances;
 443  }
 444  
 445  std::set< std::set<CTxDestination> > GetAddressGroupings(const CWallet& wallet)
 446  {
 447      AssertLockHeld(wallet.cs_wallet);
 448      std::set< std::set<CTxDestination> > groupings;
 449      std::set<CTxDestination> grouping;
 450  
 451      for (const auto& walletEntry : wallet.mapWallet)
 452      {
 453          const CWalletTx& wtx = walletEntry.second;
 454  
 455          if (wtx.tx->vin.size() > 0)
 456          {
 457              bool any_mine = false;
 458              // group all input addresses with each other
 459              for (const CTxIn& txin : wtx.tx->vin)
 460              {
 461                  CTxDestination address;
 462                  if(!InputIsMine(wallet, txin)) /* If this input isn't mine, ignore it */
 463                      continue;
 464                  if(!ExtractDestination(wallet.mapWallet.at(txin.prevout.hash).tx->vout[txin.prevout.n].scriptPubKey, address))
 465                      continue;
 466                  grouping.insert(address);
 467                  any_mine = true;
 468              }
 469  
 470              // group change with input addresses
 471              if (any_mine)
 472              {
 473                 for (const CTxOut& txout : wtx.tx->vout)
 474                     if (OutputIsChange(wallet, txout))
 475                     {
 476                         CTxDestination txoutAddr;
 477                         if(!ExtractDestination(txout.scriptPubKey, txoutAddr))
 478                             continue;
 479                         grouping.insert(txoutAddr);
 480                     }
 481              }
 482              if (grouping.size() > 0)
 483              {
 484                  groupings.insert(grouping);
 485                  grouping.clear();
 486              }
 487          }
 488  
 489          // group lone addrs by themselves
 490          for (const auto& txout : wtx.tx->vout)
 491              if (wallet.IsMine(txout))
 492              {
 493                  CTxDestination address;
 494                  if(!ExtractDestination(txout.scriptPubKey, address))
 495                      continue;
 496                  grouping.insert(address);
 497                  groupings.insert(grouping);
 498                  grouping.clear();
 499              }
 500      }
 501  
 502      std::set< std::set<CTxDestination>* > uniqueGroupings; // a set of pointers to groups of addresses
 503      std::map< CTxDestination, std::set<CTxDestination>* > setmap;  // map addresses to the unique group containing it
 504      for (const std::set<CTxDestination>& _grouping : groupings)
 505      {
 506          // make a set of all the groups hit by this new group
 507          std::set< std::set<CTxDestination>* > hits;
 508          std::map< CTxDestination, std::set<CTxDestination>* >::iterator it;
 509          for (const CTxDestination& address : _grouping)
 510              if ((it = setmap.find(address)) != setmap.end())
 511                  hits.insert((*it).second);
 512  
 513          // merge all hit groups into a new single group and delete old groups
 514          std::set<CTxDestination>* merged = new std::set<CTxDestination>(_grouping);
 515          for (std::set<CTxDestination>* hit : hits)
 516          {
 517              merged->insert(hit->begin(), hit->end());
 518              uniqueGroupings.erase(hit);
 519              delete hit;
 520          }
 521          uniqueGroupings.insert(merged);
 522  
 523          // update setmap
 524          for (const CTxDestination& element : *merged)
 525              setmap[element] = merged;
 526      }
 527  
 528      std::set< std::set<CTxDestination> > ret;
 529      for (const std::set<CTxDestination>* uniqueGrouping : uniqueGroupings)
 530      {
 531          ret.insert(*uniqueGrouping);
 532          delete uniqueGrouping;
 533      }
 534  
 535      return ret;
 536  }
 537  } // namespace wallet
 538