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