Bitcoin ABC  0.26.3
P2P Digital Currency
walletview.cpp
Go to the documentation of this file.
1 // Copyright (c) 2011-2016 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/walletview.h>
6 
7 #include <config.h> // For GetConfig
8 #include <interfaces/node.h>
9 #include <node/psbt.h>
10 #include <node/transaction.h>
11 #include <node/ui_interface.h>
12 #include <policy/policy.h>
13 #include <qt/addressbookpage.h>
14 #include <qt/askpassphrasedialog.h>
15 #include <qt/clientmodel.h>
16 #include <qt/guiutil.h>
17 #include <qt/optionsmodel.h>
18 #include <qt/overviewpage.h>
19 #include <qt/platformstyle.h>
20 #include <qt/receivecoinsdialog.h>
21 #include <qt/sendcoinsdialog.h>
24 #include <qt/transactionview.h>
25 #include <qt/walletmodel.h>
26 #include <util/strencodings.h>
27 
28 #include <QAction>
29 #include <QActionGroup>
30 #include <QFileDialog>
31 #include <QHBoxLayout>
32 #include <QProgressDialog>
33 #include <QPushButton>
34 #include <QVBoxLayout>
35 
36 #include <fstream>
37 
38 using node::AnalyzePSBT;
40 using node::PSBTAnalysis;
41 
42 WalletView::WalletView(const PlatformStyle *_platformStyle,
43  WalletModel *_walletModel, QWidget *parent)
44  : QStackedWidget(parent), clientModel(nullptr), walletModel(_walletModel),
45  platformStyle(_platformStyle) {
46  // Create tabs
48 
49  transactionsPage = new QWidget(this);
50  QVBoxLayout *vbox = new QVBoxLayout();
51  QHBoxLayout *hbox_buttons = new QHBoxLayout();
53  vbox->addWidget(transactionView);
54  QPushButton *exportButton = new QPushButton(tr("&Export"), this);
55  exportButton->setToolTip(
56  tr("Export the data in the current tab to a file"));
58  exportButton->setIcon(platformStyle->SingleColorIcon(":/icons/export"));
59  }
60  hbox_buttons->addStretch();
61  hbox_buttons->addWidget(exportButton);
62  vbox->addLayout(hbox_buttons);
63  transactionsPage->setLayout(vbox);
64 
67 
74 
75  addWidget(overviewPage);
76  addWidget(transactionsPage);
77  addWidget(receiveCoinsPage);
78  addWidget(sendCoinsPage);
79 
82  // Clicking on a transaction on the overview pre-selects the transaction on
83  // the transaction history page
85  static_cast<void (TransactionView::*)(const QModelIndex &)>(
87 
90 
93  // Highlight transaction after send
95  static_cast<void (TransactionView::*)(const uint256 &)>(
97 
98  // Clicking on "Export" allows to export the transaction list
99  connect(exportButton, &QPushButton::clicked, transactionView,
101 
102  // Pass through messages from sendCoinsPage
103  connect(sendCoinsPage, &SendCoinsDialog::message, this,
105  // Pass through messages from transactionView
108  connect(this, &WalletView::setPrivacy, overviewPage,
110 
111  // Set the model properly.
113 }
114 
116 
118  this->clientModel = _clientModel;
119 
120  overviewPage->setClientModel(_clientModel);
121  sendCoinsPage->setClientModel(_clientModel);
122  if (walletModel) {
123  walletModel->setClientModel(_clientModel);
124  }
125 }
126 
128  this->walletModel = _walletModel;
129 
130  // Put transaction list in tabs
131  transactionView->setModel(_walletModel);
132  overviewPage->setWalletModel(_walletModel);
133  receiveCoinsPage->setModel(_walletModel);
134  sendCoinsPage->setModel(_walletModel);
136  _walletModel ? _walletModel->getAddressTableModel() : nullptr);
138  _walletModel ? _walletModel->getAddressTableModel() : nullptr);
139 
140  if (_walletModel) {
141  // Receive and pass through messages from wallet model
142  connect(_walletModel, &WalletModel::message, this,
144 
145  // Handle changes in encryption status
146  connect(_walletModel, &WalletModel::encryptionStatusChanged, this,
149 
150  // update HD status
151  Q_EMIT hdEnabledStatusChanged();
152 
153  // Balloon pop-up for new transaction
154  connect(_walletModel->getTransactionTableModel(),
155  &TransactionTableModel::rowsInserted, this,
157 
158  // Ask for passphrase if needed
159  connect(_walletModel, &WalletModel::requireUnlock, this,
161 
162  // Show progress dialog
163  connect(_walletModel, &WalletModel::showProgress, this,
165  }
166 }
167 
168 void WalletView::processNewTransaction(const QModelIndex &parent, int start,
169  int end) {
170  // Prevent balloon-spam when initial block download is in progress
171  if (!walletModel || !clientModel ||
173  return;
174  }
175 
177  if (!ttm || ttm->processingQueuedTransactions()) {
178  return;
179  }
180 
181  QString date = ttm->index(start, TransactionTableModel::Date, parent)
182  .data()
183  .toString();
184  qint64 amount = ttm->index(start, TransactionTableModel::Amount, parent)
185  .data(Qt::EditRole)
186  .toULongLong();
187  QString type = ttm->index(start, TransactionTableModel::Type, parent)
188  .data()
189  .toString();
190  QModelIndex index = ttm->index(start, 0, parent);
191  QString address =
192  ttm->data(index, TransactionTableModel::AddressRole).toString();
193  QString label = GUIUtil::HtmlEscape(
194  ttm->data(index, TransactionTableModel::LabelRole).toString());
195 
196  Q_EMIT incomingTransaction(
198  int64_t(amount) * SATOSHI, type, address, label,
200 }
201 
203  setCurrentWidget(overviewPage);
204 }
205 
207  setCurrentWidget(transactionsPage);
208 }
209 
211  setCurrentWidget(receiveCoinsPage);
212 }
213 
214 void WalletView::gotoSendCoinsPage(QString addr) {
215  setCurrentWidget(sendCoinsPage);
216 
217  if (!addr.isEmpty()) {
218  sendCoinsPage->setAddress(addr);
219  }
220 }
221 
222 void WalletView::gotoSignMessageTab(QString addr) {
223  // calls show() in showTab_SM()
224  SignVerifyMessageDialog *signVerifyMessageDialog =
226  signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
227  signVerifyMessageDialog->setModel(walletModel);
228  signVerifyMessageDialog->showTab_SM(true);
229 
230  if (!addr.isEmpty()) {
231  signVerifyMessageDialog->setAddress_SM(addr);
232  }
233 }
234 
236  // calls show() in showTab_VM()
237  SignVerifyMessageDialog *signVerifyMessageDialog =
239  signVerifyMessageDialog->setAttribute(Qt::WA_DeleteOnClose);
240  signVerifyMessageDialog->setModel(walletModel);
241  signVerifyMessageDialog->showTab_VM(true);
242 
243  if (!addr.isEmpty()) {
244  signVerifyMessageDialog->setAddress_VM(addr);
245  }
246 }
247 
249  QString filename = GUIUtil::getOpenFileName(
250  this, tr("Load Transaction Data"), QString(),
251  tr("Partially Signed Transaction (*.psbt)"), nullptr);
252  if (filename.isEmpty()) {
253  return;
254  }
255  if (GetFileSize(filename.toLocal8Bit().data(), MAX_FILE_SIZE_PSBT) ==
257  Q_EMIT message(tr("Error"),
258  tr("PSBT file must be smaller than 100 MiB"),
260  return;
261  }
262  std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary};
263  std::string dataStr(std::istreambuf_iterator<char>{in}, {});
264 
265  std::string error;
267  if (!DecodeRawPSBT(psbtx, dataStr, error)) {
268  Q_EMIT message(tr("Error"),
269  tr("Unable to decode PSBT file") + "\n" +
270  QString::fromStdString(error),
272  return;
273  }
274 
276  bool complete = false;
277  PSBTAnalysis analysis = AnalyzePSBT(psbtx);
278  QMessageBox msgBox;
279  msgBox.setText("PSBT");
280  switch (analysis.next) {
281  case PSBTRole::CREATOR:
282  case PSBTRole::UPDATER:
283  msgBox.setInformativeText(
284  "PSBT is incomplete. Copy to clipboard for manual inspection?");
285  break;
286  case PSBTRole::SIGNER:
287  msgBox.setInformativeText(
288  "Transaction needs more signatures. Copy to clipboard?");
289  break;
290  case PSBTRole::FINALIZER:
291  case PSBTRole::EXTRACTOR:
292  complete = FinalizeAndExtractPSBT(psbtx, mtx);
293  if (complete) {
294  msgBox.setInformativeText(
295  tr("Would you like to send this transaction?"));
296  } else {
297  // The analyzer missed something, e.g. if there are
298  // final_scriptSig but with invalid signatures.
299  msgBox.setInformativeText(
300  tr("There was an unexpected problem processing the PSBT. "
301  "Copy to clipboard for manual inspection?"));
302  }
303  }
304 
305  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
306  switch (msgBox.exec()) {
307  case QMessageBox::Yes: {
308  if (complete) {
309  std::string err_string;
311 
313  *clientModel->node().context(), tx, err_string,
314  DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK(), /* relay */ true,
315  /* wait_callback */ false);
316  if (result == TransactionError::OK) {
317  Q_EMIT message(tr("Success"),
318  tr("Broadcasted transaction successfully."),
321  } else {
322  Q_EMIT message(tr("Error"),
323  QString::fromStdString(err_string),
325  }
326  } else {
327  // Serialize the PSBT
329  ssTx << psbtx;
330  GUIUtil::setClipboard(EncodeBase64(ssTx.str()).c_str());
331  Q_EMIT message(tr("PSBT copied"), "Copied to clipboard",
333  return;
334  }
335  }
336  case QMessageBox::Cancel:
337  break;
338  default:
339  assert(false);
340  }
341 }
342 
344  return sendCoinsPage->handlePaymentRequest(recipient);
345 }
346 
349 }
350 
352  Q_EMIT encryptionStatusChanged();
353 }
354 
356  if (!walletModel) {
357  return;
358  }
360  dlg.setModel(walletModel);
361  dlg.exec();
362 
364 }
365 
367  QString filename =
368  GUIUtil::getSaveFileName(this, tr("Backup Wallet"), QString(),
369  tr("Wallet Data (*.dat)"), nullptr);
370 
371  if (filename.isEmpty()) {
372  return;
373  }
374 
375  if (!walletModel->wallet().backupWallet(filename.toLocal8Bit().data())) {
376  Q_EMIT message(
377  tr("Backup Failed"),
378  tr("There was an error trying to save the wallet data to %1.")
379  .arg(filename),
381  } else {
382  Q_EMIT message(
383  tr("Backup Successful"),
384  tr("The wallet data was successfully saved to %1.").arg(filename),
386  }
387 }
388 
391  dlg.setModel(walletModel);
392  dlg.exec();
393 }
394 
396  if (!walletModel) {
397  return;
398  }
399 
400  // Unlock wallet when requested by wallet model
403  dlg.setModel(walletModel);
404  dlg.exec();
405  }
406 }
407 
409  if (!walletModel) {
410  return;
411  }
412 
414 }
415 
417  if (!walletModel) {
418  return;
419  }
420 
422 }
423 
424 void WalletView::showProgress(const QString &title, int nProgress) {
425  if (nProgress == 0) {
426  progressDialog = new QProgressDialog(title, tr("Cancel"), 0, 100);
428  progressDialog->setWindowModality(Qt::ApplicationModal);
429  progressDialog->setMinimumDuration(0);
430  progressDialog->setAutoClose(false);
431  progressDialog->setValue(0);
432  } else if (nProgress == 100) {
433  if (progressDialog) {
434  progressDialog->close();
435  progressDialog->deleteLater();
436  progressDialog = nullptr;
437  }
438  } else if (progressDialog) {
439  if (progressDialog->wasCanceled()) {
441  } else {
442  progressDialog->setValue(nProgress);
443  }
444  }
445 }
446 
448  Q_EMIT outOfSyncWarningClicked();
449 }
static constexpr Amount SATOSHI
Definition: amount.h:143
Widget that shows a list of sending or receiving addresses.
@ ForEditing
Open address book for editing.
void setModel(AddressTableModel *model)
Multifunctional dialog to ask for passphrases.
void setModel(WalletModel *model)
@ Unlock
Ask passphrase and unlock.
@ Encrypt
Ask passphrase twice and encrypt.
@ ChangePass
Ask old passphrase + new passphrase twice.
@ MSG_INFORMATION
Predefined combinations for certain default usage cases.
Definition: ui_interface.h:71
@ MODAL
Force blocking, modal message box dialog (not just OS notification)
Definition: ui_interface.h:65
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
std::string str() const
Definition: streams.h:212
Amount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Definition: feerate.h:54
A mutable version of CTransaction.
Definition: transaction.h:274
Model for Bitcoin network client.
Definition: clientmodel.h:39
interfaces::Node & node() const
Definition: clientmodel.h:54
int getDisplayUnit() const
Definition: optionsmodel.h:97
Overview ("home") page widget.
Definition: overviewpage.h:28
void setWalletModel(WalletModel *walletModel)
void setClientModel(ClientModel *clientModel)
void transactionClicked(const QModelIndex &index)
void outOfSyncWarningClicked()
void showOutOfSyncWarning(bool fShow)
void setPrivacy(bool privacy)
QIcon SingleColorIcon(const QString &filename) const
Colorize an icon (given filename) with the icon color.
bool getImagesOnButtons() const
Definition: platformstyle.h:20
Dialog for requesting payment of bitcoins.
void setModel(WalletModel *model)
Dialog for sending bitcoins.
void setClientModel(ClientModel *clientModel)
void setModel(WalletModel *model)
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
void setAddress(const QString &address)
void message(const QString &title, const QString &message, unsigned int style)
void coinsSent(const uint256 &txid)
void setAddress_SM(const QString &address)
void setModel(WalletModel *model)
void setAddress_VM(const QString &address)
UI model for the transaction table of a wallet.
@ LabelRole
Label of address related to transaction.
@ AddressRole
Address of transaction.
QVariant data(const QModelIndex &index, int role) const override
bool processingQueuedTransactions() const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Widget showing the transaction list for a wallet, including a filter row.
void setModel(WalletModel *model)
void message(const QString &title, const QString &message, unsigned int style)
Fired when a message should be reported to the user.
void focusTransaction(const QModelIndex &)
Interface to Bitcoin wallet from Qt view code.
Definition: walletmodel.h:47
void showProgress(const QString &title, int nProgress)
void message(const QString &title, const QString &message, unsigned int style)
void setClientModel(ClientModel *client_model)
Definition: walletmodel.cpp:57
AddressTableModel * getAddressTableModel()
OptionsModel * getOptionsModel()
interfaces::Wallet & wallet() const
Definition: walletmodel.h:150
EncryptionStatus getEncryptionStatus() const
void requireUnlock()
void encryptionStatusChanged()
QString getWalletName() const
TransactionTableModel * getTransactionTableModel()
const PlatformStyle * platformStyle
Definition: walletview.h:74
void gotoHistoryPage()
Switch to history (transactions) page.
Definition: walletview.cpp:206
void gotoVerifyMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to verify message tab.
Definition: walletview.cpp:235
void setWalletModel(WalletModel *walletModel)
Set the wallet model.
Definition: walletview.cpp:127
bool handlePaymentRequest(const SendCoinsRecipient &recipient)
Definition: walletview.cpp:343
void gotoSendCoinsPage(QString addr="")
Switch to send coins page.
Definition: walletview.cpp:214
void incomingTransaction(const QString &date, int unit, const Amount amount, const QString &type, const QString &address, const QString &label, const QString &walletName)
Notify that a new transaction appeared.
void changePassphrase()
Change encrypted wallet passphrase.
Definition: walletview.cpp:389
QProgressDialog * progressDialog
Definition: walletview.h:73
SendCoinsDialog * sendCoinsPage
Definition: walletview.h:67
OverviewPage * overviewPage
Definition: walletview.h:64
void setClientModel(ClientModel *clientModel)
Set the client model.
Definition: walletview.cpp:117
void outOfSyncWarningClicked()
Notify that the out of sync warning icon has been pressed.
void gotoReceiveCoinsPage()
Switch to receive coins page.
Definition: walletview.cpp:210
void gotoSignMessageTab(QString addr="")
Show Sign/Verify Message dialog and switch to sign message tab.
Definition: walletview.cpp:222
QWidget * transactionsPage
Definition: walletview.h:65
void usedSendingAddresses()
Show used sending addresses.
Definition: walletview.cpp:408
ReceiveCoinsDialog * receiveCoinsPage
Definition: walletview.h:66
void encryptWallet()
Encrypt the wallet.
Definition: walletview.cpp:355
TransactionView * transactionView
Definition: walletview.h:71
WalletView(const PlatformStyle *platformStyle, WalletModel *walletModel, QWidget *parent)
Definition: walletview.cpp:42
void showProgress(const QString &title, int nProgress)
Show progress dialog e.g.
Definition: walletview.cpp:424
void message(const QString &title, const QString &message, unsigned int style)
Fired when a message should be reported to the user.
AddressBookPage * usedReceivingAddressesPage
Definition: walletview.h:69
void backupWallet()
Backup the wallet.
Definition: walletview.cpp:366
ClientModel * clientModel
Definition: walletview.h:61
void gotoLoadPSBT()
Load Partially Signed Bitcoin Transaction.
Definition: walletview.cpp:248
void requestedSyncWarningInfo()
User has requested more information about the out of sync state.
Definition: walletview.cpp:447
AddressBookPage * usedSendingAddressesPage
Definition: walletview.h:68
void unlockWallet()
Ask for passphrase to unlock wallet temporarily.
Definition: walletview.cpp:395
WalletModel * walletModel
Definition: walletview.h:62
void gotoOverviewPage()
Switch to overview (home) page.
Definition: walletview.cpp:202
void usedReceivingAddresses()
Show used receiving addresses.
Definition: walletview.cpp:416
void transactionClicked()
void updateEncryptionStatus()
Re-emit encryption status signal.
Definition: walletview.cpp:351
void hdEnabledStatusChanged()
HD-Enabled status of wallet changed (only possible during startup)
void coinsSent()
void setPrivacy(bool privacy)
void processNewTransaction(const QModelIndex &parent, int start, int end)
Show incoming transaction notification for new transactions.
Definition: walletview.cpp:168
void showOutOfSyncWarning(bool fShow)
Definition: walletview.cpp:347
void encryptionStatusChanged()
Encryption status of wallet changed.
WalletModel * getWalletModel()
Definition: walletview.h:48
virtual node::NodeContext * context()
Get and set internal node context.
Definition: node.h:264
virtual bool isInitialBlockDownload()=0
Is initial block download.
virtual void abortRescan()=0
Abort a rescan.
virtual bool backupWallet(const std::string &filename)=0
Back up wallet.
256-bit opaque blob.
Definition: uint256.h:129
TransactionError
Definition: error.h:22
QString HtmlEscape(const QString &str, bool fMultiLine)
Definition: guiutil.cpp:248
void PolishProgressDialog(QProgressDialog *dialog)
Definition: guiutil.cpp:951
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get open filename, convenience wrapper for QFileDialog::getOpenFileName.
Definition: guiutil.cpp:334
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix when ...
Definition: guiutil.cpp:291
void bringToFront(QWidget *w)
Definition: guiutil.cpp:387
void setClipboard(const QString &str)
Definition: guiutil.cpp:774
PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
Provides helpful miscellaneous information about where a PSBT is in the signing workflow.
Definition: psbt.cpp:16
TransactionError BroadcastTransaction(const NodeContext &node, const CTransactionRef tx, std::string &err_string, const Amount max_tx_fee, bool relay, bool wait_callback)
Submit a transaction to the mempool and (optionally) relay it to all P2P peers.
Definition: transaction.cpp:37
static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE
Maximum fee rate for sendrawtransaction and testmempoolaccept RPC calls.
Definition: transaction.h:32
static CTransactionRef MakeTransactionRef()
Definition: transaction.h:316
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
bool DecodeRawPSBT(PartiallySignedTransaction &psbt, const std::string &tx_data, std::string &error)
Decode a raw (binary blob) PSBT into a PartiallySignedTransaction.
Definition: psbt.cpp:307
bool FinalizeAndExtractPSBT(PartiallySignedTransaction &psbtx, CMutableTransaction &result)
Finalizes a PSBT if possible, and extracts it to a CMutableTransaction if it could be finalized.
Definition: psbt.cpp:247
const std::streamsize MAX_FILE_SIZE_PSBT
Definition: psbt.h:41
@ SER_NETWORK
Definition: serialize.h:152
std::string EncodeBase64(Span< const uint8_t > input)
A version of CTransaction with the PSBT format.
Definition: psbt.h:334
Holds the results of AnalyzePSBT (miscellaneous information about a PSBT)
Definition: psbt.h:35
PSBTRole next
Which of the BIP 174 roles needs to handle the transaction next.
Definition: psbt.h:45
std::streampos GetFileSize(const char *path, std::streamsize max)
Get the size of a file by scanning it.
Definition: system.cpp:153
bool error(const char *fmt, const Args &...args)
Definition: system.h:45
assert(!tx.IsCoinBase())
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11