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