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