Bitcoin Core  22.0.0
P2P Digital Currency
transactiontablemodel.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2020 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 
6 
7 #include <qt/addresstablemodel.h>
8 #include <qt/clientmodel.h>
9 #include <qt/guiconstants.h>
10 #include <qt/guiutil.h>
11 #include <qt/optionsmodel.h>
12 #include <qt/platformstyle.h>
13 #include <qt/transactiondesc.h>
14 #include <qt/transactionrecord.h>
15 #include <qt/walletmodel.h>
16 
17 #include <core_io.h>
18 #include <interfaces/handler.h>
19 #include <uint256.h>
20 
21 #include <algorithm>
22 #include <functional>
23 
24 #include <QColor>
25 #include <QDateTime>
26 #include <QDebug>
27 #include <QIcon>
28 #include <QLatin1Char>
29 #include <QLatin1String>
30 #include <QList>
31 
32 
33 // Amount column is right-aligned it contains numbers
34 static int column_alignments[] = {
35  Qt::AlignLeft|Qt::AlignVCenter, /* status */
36  Qt::AlignLeft|Qt::AlignVCenter, /* watchonly */
37  Qt::AlignLeft|Qt::AlignVCenter, /* date */
38  Qt::AlignLeft|Qt::AlignVCenter, /* type */
39  Qt::AlignLeft|Qt::AlignVCenter, /* address */
40  Qt::AlignRight|Qt::AlignVCenter /* amount */
41  };
42 
43 // Comparison operator for sort/binary search of model tx list
44 struct TxLessThan
45 {
46  bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
47  {
48  return a.hash < b.hash;
49  }
50  bool operator()(const TransactionRecord &a, const uint256 &b) const
51  {
52  return a.hash < b;
53  }
54  bool operator()(const uint256 &a, const TransactionRecord &b) const
55  {
56  return a < b.hash;
57  }
58 };
59 
60 // queue notifications to show a non freezing progress dialog e.g. for rescan
62 {
63 public:
65  TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction):
66  hash(_hash), status(_status), showTransaction(_showTransaction) {}
67 
68  void invoke(QObject *ttm)
69  {
70  QString strHash = QString::fromStdString(hash.GetHex());
71  qDebug() << "NotifyTransactionChanged: " + strHash + " status= " + QString::number(status);
72  bool invoked = QMetaObject::invokeMethod(ttm, "updateTransaction", Qt::QueuedConnection,
73  Q_ARG(QString, strHash),
74  Q_ARG(int, status),
75  Q_ARG(bool, showTransaction));
76  assert(invoked);
77  }
78 private:
82 };
83 
84 // Private implementation
86 {
87 public:
89  parent(_parent)
90  {
91  }
92 
94 
95  /* Local cache of wallet.
96  * As it is in the same order as the CWallet, by definition
97  * this is sorted by sha256.
98  */
99  QList<TransactionRecord> cachedWallet;
100 
102  bool m_loaded = false;
104  bool m_loading = false;
105  std::vector< TransactionNotification > vQueueNotifications;
106 
107  void NotifyTransactionChanged(const uint256 &hash, ChangeType status);
108  void DispatchNotifications();
109 
110  /* Query entire wallet anew from core.
111  */
113  {
114  assert(!m_loaded);
115  {
116  for (const auto& wtx : wallet.getWalletTxs()) {
119  }
120  }
121  }
122  m_loaded = true;
124  }
125 
126  /* Update our model of the wallet incrementally, to synchronize our model of the wallet
127  with that of the core.
128 
129  Call with transaction that was added, removed or changed.
130  */
131  void updateWallet(interfaces::Wallet& wallet, const uint256 &hash, int status, bool showTransaction)
132  {
133  qDebug() << "TransactionTablePriv::updateWallet: " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
134 
135  // Find bounds of this transaction in model
136  QList<TransactionRecord>::iterator lower = std::lower_bound(
137  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
138  QList<TransactionRecord>::iterator upper = std::upper_bound(
139  cachedWallet.begin(), cachedWallet.end(), hash, TxLessThan());
140  int lowerIndex = (lower - cachedWallet.begin());
141  int upperIndex = (upper - cachedWallet.begin());
142  bool inModel = (lower != upper);
143 
144  if(status == CT_UPDATED)
145  {
146  if(showTransaction && !inModel)
147  status = CT_NEW; /* Not in model, but want to show, treat as new */
148  if(!showTransaction && inModel)
149  status = CT_DELETED; /* In model, but want to hide, treat as deleted */
150  }
151 
152  qDebug() << " inModel=" + QString::number(inModel) +
153  " Index=" + QString::number(lowerIndex) + "-" + QString::number(upperIndex) +
154  " showTransaction=" + QString::number(showTransaction) + " derivedStatus=" + QString::number(status);
155 
156  switch(status)
157  {
158  case CT_NEW:
159  if(inModel)
160  {
161  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is already in model";
162  break;
163  }
164  if(showTransaction)
165  {
166  // Find transaction in wallet
167  interfaces::WalletTx wtx = wallet.getWalletTx(hash);
168  if(!wtx.tx)
169  {
170  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_NEW, but transaction is not in wallet";
171  break;
172  }
173  // Added -- insert at the right position
174  QList<TransactionRecord> toInsert =
176  if(!toInsert.isEmpty()) /* only if something to insert */
177  {
178  parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex+toInsert.size()-1);
179  int insert_idx = lowerIndex;
180  for (const TransactionRecord &rec : toInsert)
181  {
182  cachedWallet.insert(insert_idx, rec);
183  insert_idx += 1;
184  }
185  parent->endInsertRows();
186  }
187  }
188  break;
189  case CT_DELETED:
190  if(!inModel)
191  {
192  qWarning() << "TransactionTablePriv::updateWallet: Warning: Got CT_DELETED, but transaction is not in model";
193  break;
194  }
195  // Removed -- remove entire transaction from table
196  parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex-1);
197  cachedWallet.erase(lower, upper);
198  parent->endRemoveRows();
199  break;
200  case CT_UPDATED:
201  // Miscellaneous updates -- nothing to do, status update will take care of this, and is only computed for
202  // visible transactions.
203  for (int i = lowerIndex; i < upperIndex; i++) {
204  TransactionRecord *rec = &cachedWallet[i];
205  rec->status.needsUpdate = true;
206  }
207  break;
208  }
209  }
210 
211  int size()
212  {
213  return cachedWallet.size();
214  }
215 
216  TransactionRecord* index(interfaces::Wallet& wallet, const uint256& cur_block_hash, const int idx)
217  {
218  if (idx >= 0 && idx < cachedWallet.size()) {
219  TransactionRecord *rec = &cachedWallet[idx];
220 
221  // If a status update is needed (blocks came in since last check),
222  // try to update the status of this transaction from the wallet.
223  // Otherwise, simply re-use the cached status.
225  int numBlocks;
226  int64_t block_time;
227  if (!cur_block_hash.IsNull() && rec->statusUpdateNeeded(cur_block_hash) && wallet.tryGetTxStatus(rec->hash, wtx, numBlocks, block_time)) {
228  rec->updateStatus(wtx, cur_block_hash, numBlocks, block_time);
229  }
230  return rec;
231  }
232  return nullptr;
233  }
234 
236  {
237  return TransactionDesc::toHTML(node, wallet, rec, unit);
238  }
239 
241  {
242  auto tx = wallet.getTx(rec->hash);
243  if (tx) {
244  std::string strHex = EncodeHexTx(*tx);
245  return QString::fromStdString(strHex);
246  }
247  return QString();
248  }
249 };
250 
252  QAbstractTableModel(parent),
253  walletModel(parent),
254  priv(new TransactionTablePriv(this)),
255  fProcessingQueuedTransactions(false),
256  platformStyle(_platformStyle)
257 {
259 
260  columns << QString() << QString() << tr("Date") << tr("Type") << tr("Label") << BitcoinUnits::getAmountColumnTitle(walletModel->getOptionsModel()->getDisplayUnit());
262 
264 }
265 
267 {
269  delete priv;
270 }
271 
274 {
276  Q_EMIT headerDataChanged(Qt::Horizontal,Amount,Amount);
277 }
278 
279 void TransactionTableModel::updateTransaction(const QString &hash, int status, bool showTransaction)
280 {
281  uint256 updated;
282  updated.SetHex(hash.toStdString());
283 
284  priv->updateWallet(walletModel->wallet(), updated, status, showTransaction);
285 }
286 
288 {
289  // Blocks came in since last poll.
290  // Invalidate status (number of confirmations) and (possibly) description
291  // for all rows. Qt is smart enough to only actually request the data for the
292  // visible rows.
293  Q_EMIT dataChanged(index(0, Status), index(priv->size()-1, Status));
294  Q_EMIT dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
295 }
296 
297 int TransactionTableModel::rowCount(const QModelIndex &parent) const
298 {
299  if (parent.isValid()) {
300  return 0;
301  }
302  return priv->size();
303 }
304 
305 int TransactionTableModel::columnCount(const QModelIndex &parent) const
306 {
307  if (parent.isValid()) {
308  return 0;
309  }
310  return columns.length();
311 }
312 
314 {
315  QString status;
316 
317  switch(wtx->status.status)
318  {
320  status = tr("Open for %n more block(s)","",wtx->status.open_for);
321  break;
323  status = tr("Open until %1").arg(GUIUtil::dateTimeStr(wtx->status.open_for));
324  break;
326  status = tr("Unconfirmed");
327  break;
329  status = tr("Abandoned");
330  break;
332  status = tr("Confirming (%1 of %2 recommended confirmations)").arg(wtx->status.depth).arg(TransactionRecord::RecommendedNumConfirmations);
333  break;
335  status = tr("Confirmed (%1 confirmations)").arg(wtx->status.depth);
336  break;
338  status = tr("Conflicted");
339  break;
341  status = tr("Immature (%1 confirmations, will be available after %2)").arg(wtx->status.depth).arg(wtx->status.depth + wtx->status.matures_in);
342  break;
344  status = tr("Generated but not accepted");
345  break;
346  }
347 
348  return status;
349 }
350 
352 {
353  if(wtx->time)
354  {
355  return GUIUtil::dateTimeStr(wtx->time);
356  }
357  return QString();
358 }
359 
360 /* Look up address in address book, if found return label (address)
361  otherwise just return (address)
362  */
363 QString TransactionTableModel::lookupAddress(const std::string &address, bool tooltip) const
364 {
365  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address));
366  QString description;
367  if(!label.isEmpty())
368  {
369  description += label;
370  }
371  if(label.isEmpty() || tooltip)
372  {
373  description += QString(" (") + QString::fromStdString(address) + QString(")");
374  }
375  return description;
376 }
377 
379 {
380  switch(wtx->type)
381  {
383  return tr("Received with");
385  return tr("Received from");
388  return tr("Sent to");
390  return tr("Payment to yourself");
392  return tr("Mined");
393  default:
394  return QString();
395  }
396 }
397 
399 {
400  switch(wtx->type)
401  {
403  return QIcon(":/icons/tx_mined");
406  return QIcon(":/icons/tx_input");
409  return QIcon(":/icons/tx_output");
410  default:
411  return QIcon(":/icons/tx_inout");
412  }
413 }
414 
415 QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
416 {
417  QString watchAddress;
418  if (tooltip && wtx->involvesWatchAddress) {
419  // Mark transactions involving watch-only addresses by adding " (watch-only)"
420  watchAddress = QLatin1String(" (") + tr("watch-only") + QLatin1Char(')');
421  }
422 
423  switch(wtx->type)
424  {
426  return QString::fromStdString(wtx->address) + watchAddress;
430  return lookupAddress(wtx->address, tooltip) + watchAddress;
432  return QString::fromStdString(wtx->address) + watchAddress;
434  return lookupAddress(wtx->address, tooltip) + watchAddress;
435  default:
436  return tr("(n/a)") + watchAddress;
437  }
438 }
439 
441 {
442  // Show addresses without label in a less visible color
443  switch(wtx->type)
444  {
448  {
449  QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address));
450  if(label.isEmpty())
451  return COLOR_BAREADDRESS;
452  } break;
454  return COLOR_BAREADDRESS;
455  default:
456  break;
457  }
458  return QVariant();
459 }
460 
461 QString TransactionTableModel::formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed, BitcoinUnits::SeparatorStyle separators) const
462 {
463  QString str = BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), wtx->credit + wtx->debit, false, separators);
464  if(showUnconfirmed)
465  {
466  if(!wtx->status.countsForBalance)
467  {
468  str = QString("[") + str + QString("]");
469  }
470  }
471  return QString(str);
472 }
473 
475 {
476  switch(wtx->status.status)
477  {
482  return QIcon(":/icons/transaction_0");
484  return QIcon(":/icons/transaction_abandoned");
486  switch(wtx->status.depth)
487  {
488  case 1: return QIcon(":/icons/transaction_1");
489  case 2: return QIcon(":/icons/transaction_2");
490  case 3: return QIcon(":/icons/transaction_3");
491  case 4: return QIcon(":/icons/transaction_4");
492  default: return QIcon(":/icons/transaction_5");
493  };
495  return QIcon(":/icons/transaction_confirmed");
497  return QIcon(":/icons/transaction_conflicted");
499  int total = wtx->status.depth + wtx->status.matures_in;
500  int part = (wtx->status.depth * 4 / total) + 1;
501  return QIcon(QString(":/icons/transaction_%1").arg(part));
502  }
504  return QIcon(":/icons/transaction_0");
505  default:
506  return COLOR_BLACK;
507  }
508 }
509 
511 {
512  if (wtx->involvesWatchAddress)
513  return QIcon(":/icons/eye");
514  else
515  return QVariant();
516 }
517 
519 {
520  QString tooltip = formatTxStatus(rec) + QString("\n") + formatTxType(rec);
523  {
524  tooltip += QString(" ") + formatTxToAddress(rec, true);
525  }
526  return tooltip;
527 }
528 
529 QVariant TransactionTableModel::data(const QModelIndex &index, int role) const
530 {
531  if(!index.isValid())
532  return QVariant();
533  TransactionRecord *rec = static_cast<TransactionRecord*>(index.internalPointer());
534 
535  const auto column = static_cast<ColumnIndex>(index.column());
536  switch (role) {
537  case RawDecorationRole:
538  switch (column) {
539  case Status:
540  return txStatusDecoration(rec);
541  case Watchonly:
542  return txWatchonlyDecoration(rec);
543  case Date: return {};
544  case Type: return {};
545  case ToAddress:
546  return txAddressDecoration(rec);
547  case Amount: return {};
548  } // no default case, so the compiler can warn about missing cases
549  assert(false);
550  case Qt::DecorationRole:
551  {
552  QIcon icon = qvariant_cast<QIcon>(index.data(RawDecorationRole));
553  return platformStyle->TextColorIcon(icon);
554  }
555  case Qt::DisplayRole:
556  switch (column) {
557  case Status: return {};
558  case Watchonly: return {};
559  case Date:
560  return formatTxDate(rec);
561  case Type:
562  return formatTxType(rec);
563  case ToAddress:
564  return formatTxToAddress(rec, false);
565  case Amount:
567  } // no default case, so the compiler can warn about missing cases
568  assert(false);
569  case Qt::EditRole:
570  // Edit role is used for sorting, so return the unformatted values
571  switch (column) {
572  case Status:
573  return QString::fromStdString(rec->status.sortKey);
574  case Date:
575  return rec->time;
576  case Type:
577  return formatTxType(rec);
578  case Watchonly:
579  return (rec->involvesWatchAddress ? 1 : 0);
580  case ToAddress:
581  return formatTxToAddress(rec, true);
582  case Amount:
583  return qint64(rec->credit + rec->debit);
584  } // no default case, so the compiler can warn about missing cases
585  assert(false);
586  case Qt::ToolTipRole:
587  return formatTooltip(rec);
588  case Qt::TextAlignmentRole:
589  return column_alignments[index.column()];
590  case Qt::ForegroundRole:
591  // Use the "danger" color for abandoned transactions
593  {
594  return COLOR_TX_STATUS_DANGER;
595  }
596  // Non-confirmed (but not immature) as transactions are grey
598  {
599  return COLOR_UNCONFIRMED;
600  }
601  if(index.column() == Amount && (rec->credit+rec->debit) < 0)
602  {
603  return COLOR_NEGATIVE;
604  }
605  if(index.column() == ToAddress)
606  {
607  return addressColor(rec);
608  }
609  break;
610  case TypeRole:
611  return rec->type;
612  case DateRole:
613  return QDateTime::fromTime_t(static_cast<uint>(rec->time));
614  case WatchonlyRole:
615  return rec->involvesWatchAddress;
617  return txWatchonlyDecoration(rec);
618  case LongDescriptionRole:
620  case AddressRole:
621  return QString::fromStdString(rec->address);
622  case LabelRole:
623  return walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
624  case AmountRole:
625  return qint64(rec->credit + rec->debit);
626  case TxHashRole:
627  return rec->getTxHash();
628  case TxHexRole:
629  return priv->getTxHex(walletModel->wallet(), rec);
630  case TxPlainTextRole:
631  {
632  QString details;
633  QDateTime date = QDateTime::fromTime_t(static_cast<uint>(rec->time));
634  QString txLabel = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(rec->address));
635 
636  details.append(date.toString("M/d/yy HH:mm"));
637  details.append(" ");
638  details.append(formatTxStatus(rec));
639  details.append(". ");
640  if(!formatTxType(rec).isEmpty()) {
641  details.append(formatTxType(rec));
642  details.append(" ");
643  }
644  if(!rec->address.empty()) {
645  if(txLabel.isEmpty())
646  details.append(tr("(no label)") + " ");
647  else {
648  details.append("(");
649  details.append(txLabel);
650  details.append(") ");
651  }
652  details.append(QString::fromStdString(rec->address));
653  details.append(" ");
654  }
655  details.append(formatTxAmount(rec, false, BitcoinUnits::SeparatorStyle::NEVER));
656  return details;
657  }
658  case ConfirmedRole:
659  return rec->status.status == TransactionStatus::Status::Confirming || rec->status.status == TransactionStatus::Status::Confirmed;
660  case FormattedAmountRole:
661  // Used for copy/export, so don't include separators
663  case StatusRole:
664  return rec->status.status;
665  }
666  return QVariant();
667 }
668 
669 QVariant TransactionTableModel::headerData(int section, Qt::Orientation orientation, int role) const
670 {
671  if(orientation == Qt::Horizontal)
672  {
673  if(role == Qt::DisplayRole)
674  {
675  return columns[section];
676  }
677  else if (role == Qt::TextAlignmentRole)
678  {
679  return column_alignments[section];
680  } else if (role == Qt::ToolTipRole)
681  {
682  switch(section)
683  {
684  case Status:
685  return tr("Transaction status. Hover over this field to show number of confirmations.");
686  case Date:
687  return tr("Date and time that the transaction was received.");
688  case Type:
689  return tr("Type of transaction.");
690  case Watchonly:
691  return tr("Whether or not a watch-only address is involved in this transaction.");
692  case ToAddress:
693  return tr("User-defined intent/purpose of the transaction.");
694  case Amount:
695  return tr("Amount removed from or added to balance.");
696  }
697  }
698  }
699  return QVariant();
700 }
701 
702 QModelIndex TransactionTableModel::index(int row, int column, const QModelIndex &parent) const
703 {
704  Q_UNUSED(parent);
706  if(data)
707  {
708  return createIndex(row, column, data);
709  }
710  return QModelIndex();
711 }
712 
714 {
715  // emit dataChanged to update Amount column with the current unit
717  Q_EMIT dataChanged(index(0, Amount), index(priv->size()-1, Amount));
718 }
719 
721 {
722  // Find transaction in wallet
723  // Determine whether to show transaction or not (determine this here so that no relocking is needed in GUI thread)
724  bool showTransaction = TransactionRecord::showTransaction();
725 
726  TransactionNotification notification(hash, status, showTransaction);
727 
728  if (!m_loaded || m_loading)
729  {
730  vQueueNotifications.push_back(notification);
731  return;
732  }
733  notification.invoke(parent);
734 }
735 
737 {
738  if (!m_loaded || m_loading) return;
739 
740  if (vQueueNotifications.size() > 10) { // prevent balloon spam, show maximum 10 balloons
741  bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, true));
742  assert(invoked);
743  }
744  for (unsigned int i = 0; i < vQueueNotifications.size(); ++i)
745  {
746  if (vQueueNotifications.size() - i <= 10) {
747  bool invoked = QMetaObject::invokeMethod(parent, "setProcessingQueuedTransactions", Qt::QueuedConnection, Q_ARG(bool, false));
748  assert(invoked);
749  }
750 
751  vQueueNotifications[i].invoke(parent);
752  }
753  vQueueNotifications.clear();
754 }
755 
757 {
758  // Connect signals to wallet
760  m_handler_show_progress = walletModel->wallet().handleShowProgress([this](const std::string&, int progress) {
761  priv->m_loading = progress < 100;
763  });
764 }
765 
767 {
768  // Disconnect signals from wallet
769  m_handler_transaction_changed->disconnect();
770  m_handler_show_progress->disconnect();
771 }
void updateWallet(interfaces::Wallet &wallet, const uint256 &hash, int status, bool showTransaction)
bool statusUpdateNeeded(const uint256 &block_hash) const
Return whether a status update is needed.
void updateAmountColumnTitle()
Updates the column title to "Amount (DisplayUnit)" and emits headerDataChanged() signal for table hea...
TransactionRecord * index(interfaces::Wallet &wallet, const uint256 &cur_block_hash, const int idx)
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
Confirmed, but waiting for the recommended number of confirmations.
interfaces::Wallet & wallet() const
Definition: walletmodel.h:144
QVariant txWatchonlyDecoration(const TransactionRecord *wtx) const
Transaction not yet final, waiting for block.
Transaction status (TransactionRecord::Status)
assert(!tx.IsCoinBase())
QString getTxHash() const
Return the unique identifier for this transaction (part)
Generated (mined) transactions.
static int column_alignments[]
QString formatTooltip(const TransactionRecord *rec) const
Have 6 or more confirmations (normal tx) or fully mature (mined tx)
std::string sortKey
Sorting key based on status.
static QString format(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=SeparatorStyle::STANDARD, bool justify=false)
Format as string.
void updateTransaction(const QString &hash, int status, bool showTransaction)
QString describe(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, int unit)
QString dateTimeStr(const QDateTime &date)
Definition: guiutil.cpp:77
TransactionTablePriv(TransactionTableModel *_parent)
static QList< TransactionRecord > decomposeTransaction(const interfaces::WalletTx &wtx)
QVariant txStatusDecoration(const TransactionRecord *wtx) const
void NotifyTransactionChanged(const uint256 &hash, ChangeType status)
bool operator()(const TransactionRecord &a, const TransactionRecord &b) const
Mined but not accepted.
Not yet mined into a block.
static QString toHTML(interfaces::Node &node, interfaces::Wallet &wallet, TransactionRecord *rec, int unit)
int columnCount(const QModelIndex &parent) const override
CTransactionRef tx
Definition: wallet.h:374
QIcon TextColorIcon(const QIcon &icon) const
Colorize an icon (given object) with the text color.
AddressTableModel * getAddressTableModel()
Transaction data, hex-encoded.
TransactionTableModel * parent
bool IsNull() const
Definition: uint256.h:31
int rowCount(const QModelIndex &parent) const override
TransactionTablePriv * priv
void updateStatus(const interfaces::WalletTxStatus &wtx, const uint256 &block_hash, int numBlocks, int64_t block_time)
Update status from core wallet tx.
int getDisplayUnit() const
Definition: optionsmodel.h:87
static QString getAmountColumnTitle(int unit)
Gets title for amount column including current display unit if optionsModel reference available */...
bool operator()(const uint256 &a, const TransactionRecord &b) const
QList< TransactionRecord > cachedWallet
bool operator()(const TransactionRecord &a, const uint256 &b) const
uint256 getLastBlockProcessed() const
virtual std::unique_ptr< Handler > handleTransactionChanged(TransactionChangedFn fn)=0
UI model for a transaction.
TransactionStatus status
Status: can change with block chain update.
QString formatTxType(const TransactionRecord *wtx) const
virtual std::unique_ptr< Handler > handleShowProgress(ShowProgressFn fn)=0
Whole transaction as plain text.
std::unique_ptr< interfaces::Handler > m_handler_transaction_changed
std::vector< TransactionNotification > vQueueNotifications
#define COLOR_TX_STATUS_DANGER
Definition: guiconstants.h:33
QString labelForAddress(const QString &address) const
Look up label for address in address book, if not found return empty string.
Interface for accessing a wallet.
Definition: wallet.h:52
TransactionNotification(uint256 _hash, ChangeType _status, bool _showTransaction)
bool countsForBalance
Transaction counts towards available balance.
TransactionTableModel(const PlatformStyle *platformStyle, WalletModel *parent=nullptr)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Date and time this transaction was created.
std::string ToString() const
Definition: uint256.cpp:64
#define COLOR_BLACK
Definition: guiconstants.h:35
interfaces::Node & node() const
Definition: walletmodel.h:143
void displayUnitChanged(int unit)
UI model for the transaction table of a wallet.
#define COLOR_UNCONFIRMED
Definition: guiconstants.h:25
void refreshWallet(interfaces::Wallet &wallet)
Normal (sent/received) transactions.
QString lookupAddress(const std::string &address, bool tooltip) const
std::unique_ptr< interfaces::Handler > m_handler_show_progress
static bool showTransaction()
Decompose CWallet transaction to model transaction records.
256-bit opaque blob.
Definition: uint256.h:124
QString formatTxToAddress(const TransactionRecord *wtx, bool tooltip) const
bool m_loading
True when transactions are being notified, for instance when scanning.
Conflicts with other transaction or mempool.
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:51
bool involvesWatchAddress
Whether the transaction was sent/received with a watch-only address.
std::string GetHex() const
Definition: uint256.cpp:20
QString getTxHex(interfaces::Wallet &wallet, TransactionRecord *rec)
std::string EncodeHexTx(const CTransaction &tx, const int serializeFlags=0)
Definition: core_write.cpp:137
Label of address related to transaction.
bool m_loaded
True when model finishes loading all wallet transactions on start.
QString formatTxStatus(const TransactionRecord *wtx) const
QVariant addressColor(const TransactionRecord *wtx) const
#define COLOR_TX_STATUS_OPENUNTILDATE
Definition: guiconstants.h:31
qint64 open_for
Timestamp if status==OpenUntilDate, otherwise number of additional blocks that need to be mined befor...
QVariant txAddressDecoration(const TransactionRecord *wtx) const
Formatted amount, without brackets when unconfirmed.
QVariant data(const QModelIndex &index, int role) const override
ChangeType
General change type (added, updated, removed).
Definition: ui_change_type.h:9
void SetHex(const char *psz)
Definition: uint256.cpp:30
Abandoned from the wallet.
#define COLOR_BAREADDRESS
Definition: guiconstants.h:29
Top-level interface for a bitcoin node (bitcoind process).
Definition: node.h:54
const PlatformStyle * platformStyle
Updated transaction status.
Definition: wallet.h:388
#define COLOR_NEGATIVE
Definition: guiconstants.h:27
static const int RecommendedNumConfirmations
Number of confirmation recommended for accepting a transaction.
QString formatTxAmount(const TransactionRecord *wtx, bool showUnconfirmed=true, BitcoinUnits::SeparatorStyle separators=BitcoinUnits::SeparatorStyle::STANDARD) const
OptionsModel * getOptionsModel()
QString formatTxDate(const TransactionRecord *wtx) const