transactionrecord.cpp raw

   1  // Copyright (c) 2011-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 <qt/transactionrecord.h>
   6  
   7  #include <chain.h>
   8  #include <interfaces/wallet.h>
   9  #include <key_io.h>
  10  
  11  #include <cstdint>
  12  
  13  #include <QDateTime>
  14  
  15  /* Return positive answer if transaction should be shown in list.
  16   */
  17  bool TransactionRecord::showTransaction()
  18  {
  19      // There are currently no cases where we hide transactions, but
  20      // we may want to use this in the future for things like RBF.
  21      return true;
  22  }
  23  
  24  /*
  25   * Decompose CWallet transaction to model transaction records.
  26   */
  27  QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interfaces::WalletTx& wtx)
  28  {
  29      QList<TransactionRecord> parts;
  30      int64_t nTime = wtx.time;
  31      CAmount nCredit = wtx.credit;
  32      CAmount nDebit = wtx.debit;
  33      CAmount nNet = nCredit - nDebit;
  34      Txid hash = wtx.tx->GetHash();
  35  
  36      bool all_from_me = true;
  37      bool any_from_me = false;
  38      if (wtx.is_coinbase) {
  39          all_from_me = false;
  40      } else {
  41          for (const bool mine : wtx.txin_is_mine)
  42          {
  43              all_from_me = all_from_me && mine;
  44              if (mine) any_from_me = true;
  45          }
  46      }
  47  
  48      if (all_from_me || !any_from_me) {
  49          CAmount nTxFee = nDebit - wtx.tx->GetValueOut();
  50  
  51          for(unsigned int i = 0; i < wtx.tx->vout.size(); i++)
  52          {
  53              const CTxOut& txout = wtx.tx->vout[i];
  54  
  55              if (all_from_me) {
  56                  // Change is only really possible if we're the sender
  57                  // Otherwise, someone just sent bitcoins to a change address, which should be shown
  58                  if (wtx.txout_is_change[i]) {
  59                      continue;
  60                  }
  61  
  62                  //
  63                  // Debit
  64                  //
  65  
  66                  TransactionRecord sub(hash, nTime);
  67                  sub.idx = i;
  68  
  69                  if (!std::get_if<CNoDestination>(&wtx.txout_address[i]))
  70                  {
  71                      // Sent to Bitcoin Address
  72                      sub.type = TransactionRecord::SendToAddress;
  73                      sub.address = EncodeDestination(wtx.txout_address[i]);
  74                  }
  75                  else
  76                  {
  77                      // Sent to IP, or other non-address transaction like OP_EVAL
  78                      sub.type = TransactionRecord::SendToOther;
  79                      sub.address = wtx.comment_to.value_or("");
  80                  }
  81  
  82                  CAmount nValue = txout.nValue;
  83                  /* Add fee to first output */
  84                  if (nTxFee > 0)
  85                  {
  86                      nValue += nTxFee;
  87                      nTxFee = 0;
  88                  }
  89                  sub.debit = -nValue;
  90  
  91                  parts.append(sub);
  92              }
  93  
  94              bool mine = wtx.txout_is_mine[i];
  95              if(mine)
  96              {
  97                  //
  98                  // Credit
  99                  //
 100  
 101                  TransactionRecord sub(hash, nTime);
 102                  sub.idx = i; // vout index
 103                  sub.credit = txout.nValue;
 104                  if (wtx.txout_address_is_mine[i])
 105                  {
 106                      // Received by Bitcoin Address
 107                      sub.type = TransactionRecord::RecvWithAddress;
 108                      sub.address = EncodeDestination(wtx.txout_address[i]);
 109                  }
 110                  else
 111                  {
 112                      // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
 113                      sub.type = TransactionRecord::RecvFromOther;
 114                      sub.address = wtx.from.value_or("");
 115                  }
 116                  if (wtx.is_coinbase)
 117                  {
 118                      // Generated
 119                      sub.type = TransactionRecord::Generated;
 120                  }
 121  
 122                  parts.append(sub);
 123              }
 124          }
 125      } else {
 126          //
 127          // Mixed debit transaction, can't break down payees
 128          //
 129          parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0));
 130      }
 131  
 132      return parts;
 133  }
 134  
 135  void TransactionRecord::updateStatus(const interfaces::WalletTxStatus& wtx, const uint256& block_hash, int numBlocks, int64_t block_time)
 136  {
 137      // Determine transaction status
 138  
 139      // Sort order, unrecorded transactions sort to the top
 140      int typesort;
 141      switch (type) {
 142      case SendToAddress: case SendToOther:
 143          typesort = 2; break;
 144      case RecvWithAddress: case RecvFromOther:
 145          typesort = 3; break;
 146      default:
 147          typesort = 9;
 148      }
 149      status.sortKey = strprintf("%010d-%01d-%010u-%03d-%d",
 150          wtx.block_height,
 151          wtx.is_coinbase ? 1 : 0,
 152          wtx.time_received,
 153          idx,
 154          typesort);
 155      status.countsForBalance = wtx.is_trusted && !(wtx.blocks_to_maturity > 0);
 156      status.depth = wtx.depth_in_main_chain;
 157      status.m_cur_block_hash = block_hash;
 158  
 159      // For generated transactions, determine maturity
 160      if (type == TransactionRecord::Generated) {
 161          if (wtx.blocks_to_maturity > 0)
 162          {
 163              status.status = TransactionStatus::Immature;
 164  
 165              if (wtx.is_in_main_chain)
 166              {
 167                  status.matures_in = wtx.blocks_to_maturity;
 168              }
 169              else
 170              {
 171                  status.status = TransactionStatus::NotAccepted;
 172              }
 173          }
 174          else
 175          {
 176              status.status = TransactionStatus::Confirmed;
 177          }
 178      }
 179      else
 180      {
 181          if (status.depth < 0)
 182          {
 183              status.status = TransactionStatus::Conflicted;
 184          }
 185          else if (status.depth == 0)
 186          {
 187              status.status = TransactionStatus::Unconfirmed;
 188              if (wtx.is_abandoned)
 189                  status.status = TransactionStatus::Abandoned;
 190          }
 191          else if (status.depth < RecommendedNumConfirmations)
 192          {
 193              status.status = TransactionStatus::Confirming;
 194          }
 195          else
 196          {
 197              status.status = TransactionStatus::Confirmed;
 198          }
 199      }
 200      status.needsUpdate = false;
 201  }
 202  
 203  bool TransactionRecord::statusUpdateNeeded(const uint256& block_hash) const
 204  {
 205      assert(!block_hash.IsNull());
 206      return status.m_cur_block_hash != block_hash || status.needsUpdate;
 207  }
 208  
 209  QString TransactionRecord::getTxHash() const
 210  {
 211      return QString::fromStdString(hash.ToString());
 212  }
 213  
 214  int TransactionRecord::getOutputIndex() const
 215  {
 216      return idx;
 217  }
 218