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