From bc6d8a3662f0fb992073e5e80269a90a722d76e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Barbosa?= Date: Fri, 21 Jun 2019 15:13:15 +0100 Subject: [PATCH 1/5] gui: Refactor OpenWalletActivity --- src/qt/bitcoingui.cpp | 26 ++--------- src/qt/walletcontroller.cpp | 88 ++++++++++++++++++++++++++----------- src/qt/walletcontroller.h | 50 ++++++++++++++++----- 3 files changed, 103 insertions(+), 61 deletions(-) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 323797a4b68..4c520c00dfd 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -379,31 +379,11 @@ void BitcoinGUI::createActions() continue; } - connect(action, &QAction::triggered, [this, name, path] { - OpenWalletActivity* activity = m_wallet_controller->openWallet(path); - - QProgressDialog* dialog = new QProgressDialog(this); - dialog->setLabelText(tr("Opening Wallet %1...").arg(name.toHtmlEscaped())); - dialog->setRange(0, 0); - dialog->setCancelButton(nullptr); - dialog->setWindowModality(Qt::ApplicationModal); - dialog->show(); - - connect(activity, &OpenWalletActivity::message, this, [this] (QMessageBox::Icon icon, QString text) { - QMessageBox box; - box.setIcon(icon); - box.setText(tr("Open Wallet Failed")); - box.setInformativeText(text); - box.setStandardButtons(QMessageBox::Ok); - box.setDefaultButton(QMessageBox::Ok); - connect(this, &QObject::destroyed, &box, &QDialog::accept); - box.exec(); - }); + connect(action, &QAction::triggered, [this, path] { + auto activity = new OpenWalletActivity(m_wallet_controller, this); connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet); connect(activity, &OpenWalletActivity::finished, activity, &QObject::deleteLater); - connect(activity, &OpenWalletActivity::finished, dialog, &QObject::deleteLater); - bool invoked = QMetaObject::invokeMethod(activity, "open"); - assert(invoked); + activity->open(path); }); } if (m_open_wallet_menu->isEmpty()) { diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index a8e7bce6b59..88ccc8c2d6a 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include @@ -13,10 +14,13 @@ #include #include #include +#include #include WalletController::WalletController(interfaces::Node& node, const PlatformStyle* platform_style, OptionsModel* options_model, QObject* parent) : QObject(parent) + , m_activity_thread(new QThread(this)) + , m_activity_worker(new QObject) , m_node(node) , m_platform_style(platform_style) , m_options_model(options_model) @@ -29,15 +33,17 @@ WalletController::WalletController(interfaces::Node& node, const PlatformStyle* getOrCreateWallet(std::move(wallet)); } - m_activity_thread.start(); + m_activity_worker->moveToThread(m_activity_thread); + m_activity_thread->start(); } // Not using the default destructor because not all member types definitions are // available in the header, just forward declared. WalletController::~WalletController() { - m_activity_thread.quit(); - m_activity_thread.wait(); + m_activity_thread->quit(); + m_activity_thread->wait(); + delete m_activity_worker; } std::vector WalletController::getOpenWallets() const @@ -60,13 +66,6 @@ std::map WalletController::listWalletDir() const return wallets; } -OpenWalletActivity* WalletController::openWallet(const std::string& name, QWidget* parent) -{ - OpenWalletActivity* activity = new OpenWalletActivity(this, name); - activity->moveToThread(&m_activity_thread); - return activity; -} - void WalletController::closeWallet(WalletModel* wallet_model, QWidget* parent) { QMessageBox box(parent); @@ -140,23 +139,60 @@ void WalletController::removeAndDeleteWallet(WalletModel* wallet_model) delete wallet_model; } - -OpenWalletActivity::OpenWalletActivity(WalletController* wallet_controller, const std::string& name) - : m_wallet_controller(wallet_controller) - , m_name(name) -{} - -void OpenWalletActivity::open() +WalletControllerActivity::WalletControllerActivity(WalletController* wallet_controller, QWidget* parent_widget) + : QObject(wallet_controller) + , m_wallet_controller(wallet_controller) + , m_parent_widget(parent_widget) { - std::string error, warning; - std::unique_ptr wallet = m_wallet_controller->m_node.loadWallet(m_name, error, warning); - if (!warning.empty()) { - Q_EMIT message(QMessageBox::Warning, QString::fromStdString(warning)); - } - if (wallet) { - Q_EMIT opened(m_wallet_controller->getOrCreateWallet(std::move(wallet))); - } else { - Q_EMIT message(QMessageBox::Critical, QString::fromStdString(error)); +} + +WalletControllerActivity::~WalletControllerActivity() +{ + delete m_progress_dialog; +} + +void WalletControllerActivity::showProgressDialog(const QString& label_text) +{ + m_progress_dialog = new QProgressDialog(m_parent_widget); + + m_progress_dialog->setLabelText(label_text); + m_progress_dialog->setRange(0, 0); + m_progress_dialog->setCancelButton(nullptr); + m_progress_dialog->setWindowModality(Qt::ApplicationModal); + GUIUtil::PolishProgressDialog(m_progress_dialog); +} + +OpenWalletActivity::OpenWalletActivity(WalletController* wallet_controller, QWidget* parent_widget) + : WalletControllerActivity(wallet_controller, parent_widget) +{ +} + +void OpenWalletActivity::finish() +{ + m_progress_dialog->hide(); + + if (!m_error_message.empty()) { + QMessageBox::critical(m_parent_widget, tr("Open wallet failed"), QString::fromStdString(m_error_message)); + } else if (!m_warning_message.empty()) { + QMessageBox::warning(m_parent_widget, tr("Open wallet warning"), QString::fromStdString(m_warning_message)); } + + if (m_wallet_model) Q_EMIT opened(m_wallet_model); + Q_EMIT finished(); } + +void OpenWalletActivity::open(const std::string& path) +{ + QString name = path.empty() ? QString("["+tr("default wallet")+"]") : QString::fromStdString(path); + + showProgressDialog(tr("Opening Wallet %1...").arg(name.toHtmlEscaped())); + + QTimer::singleShot(0, worker(), [this, path] { + std::unique_ptr wallet = node().loadWallet(path, m_error_message, m_warning_message); + + if (wallet) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet)); + + QTimer::singleShot(0, this, &OpenWalletActivity::finish); + }); +} diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h index be1c2829199..dada9cfa63d 100644 --- a/src/qt/walletcontroller.h +++ b/src/qt/walletcontroller.h @@ -10,10 +10,13 @@ #include #include +#include #include #include #include +#include +#include #include class OptionsModel; @@ -25,6 +28,7 @@ class Node; } // namespace interfaces class OpenWalletActivity; +class WalletControllerActivity; /** * Controller between interfaces::Node, WalletModel instances and the GUI. @@ -33,7 +37,6 @@ class WalletController : public QObject { Q_OBJECT - WalletModel* getOrCreateWallet(std::unique_ptr wallet); void removeAndDeleteWallet(WalletModel* wallet_model); public: @@ -43,11 +46,12 @@ public: //! Returns wallet models currently open. std::vector getOpenWallets() const; + WalletModel* getOrCreateWallet(std::unique_ptr wallet); + //! Returns all wallet names in the wallet dir mapped to whether the wallet //! is loaded. std::map listWalletDir() const; - OpenWalletActivity* openWallet(const std::string& name, QWidget* parent = nullptr); void closeWallet(WalletModel* wallet_model, QWidget* parent = nullptr); Q_SIGNALS: @@ -57,7 +61,8 @@ Q_SIGNALS: void coinsSent(WalletModel* wallet_model, SendCoinsRecipient recipient, QByteArray transaction); private: - QThread m_activity_thread; + QThread* const m_activity_thread; + QObject* const m_activity_worker; interfaces::Node& m_node; const PlatformStyle* const m_platform_style; OptionsModel* const m_options_model; @@ -65,27 +70,48 @@ private: std::vector m_wallets; std::unique_ptr m_handler_load_wallet; - friend class OpenWalletActivity; + friend class WalletControllerActivity; }; -class OpenWalletActivity : public QObject +class WalletControllerActivity : public QObject { Q_OBJECT public: - OpenWalletActivity(WalletController* wallet_controller, const std::string& name); - -public Q_SLOTS: - void open(); + WalletControllerActivity(WalletController* wallet_controller, QWidget* parent_widget); + virtual ~WalletControllerActivity(); Q_SIGNALS: - void message(QMessageBox::Icon icon, const QString text); void finished(); + +protected: + interfaces::Node& node() const { return m_wallet_controller->m_node; } + QObject* worker() const { return m_wallet_controller->m_activity_worker; } + + void showProgressDialog(const QString& label_text); + + WalletController* const m_wallet_controller; + QWidget* const m_parent_widget; + QProgressDialog* m_progress_dialog{nullptr}; + WalletModel* m_wallet_model{nullptr}; + std::string m_error_message; + std::string m_warning_message; +}; + +class OpenWalletActivity : public WalletControllerActivity +{ + Q_OBJECT + +public: + OpenWalletActivity(WalletController* wallet_controller, QWidget* parent_widget); + + void open(const std::string& path); + +Q_SIGNALS: void opened(WalletModel* wallet_model); private: - WalletController* const m_wallet_controller; - std::string const m_name; + void finish(); }; #endif // BITCOIN_QT_WALLETCONTROLLER_H From 60adb21c7affb41ec475a62a53fb0a36bea35dfb Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Fri, 24 May 2019 15:14:54 -0400 Subject: [PATCH 2/5] Optionally allow AskPassphraseDialog to output the passphrase --- src/qt/askpassphrasedialog.cpp | 48 ++++++++++++++++++++-------------- src/qt/askpassphrasedialog.h | 5 +++- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index a89a15bc9d7..c9f17d12ec9 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -18,12 +18,13 @@ #include #include -AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) : +AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureString* passphrase_out) : QDialog(parent), ui(new Ui::AskPassphraseDialog), mode(_mode), model(nullptr), - fCapsLock(false) + fCapsLock(false), + m_passphrase_out(passphrase_out) { ui->setupUi(this); @@ -90,7 +91,7 @@ void AskPassphraseDialog::setModel(WalletModel *_model) void AskPassphraseDialog::accept() { SecureString oldpass, newpass1, newpass2; - if(!model) + if (!model && mode != Encrypt) return; oldpass.reserve(MAX_PASSPHRASE_SIZE); newpass1.reserve(MAX_PASSPHRASE_SIZE); @@ -119,24 +120,33 @@ void AskPassphraseDialog::accept() { if(newpass1 == newpass2) { - if(model->setWalletEncrypted(true, newpass1)) - { - QMessageBox::warning(this, tr("Wallet encrypted"), + QString encryption_reminder = tr("Remember that encrypting your wallet cannot fully protect " + "your bitcoins from being stolen by malware infecting your computer."); + if (m_passphrase_out) { + m_passphrase_out->assign(newpass1); + QMessageBox::warning(this, tr("Wallet to be encrypted"), "" + - tr("Your wallet is now encrypted. " - "Remember that encrypting your wallet cannot fully protect " - "your bitcoins from being stolen by malware infecting your computer.") + - "

" + - tr("IMPORTANT: Any previous backups you have made of your wallet file " - "should be replaced with the newly generated, encrypted wallet file. " - "For security reasons, previous backups of the unencrypted wallet file " - "will become useless as soon as you start using the new, encrypted wallet.") + + tr("Your wallet is about to be encrypted. ") + encryption_reminder + "
"); - } - else - { - QMessageBox::critical(this, tr("Wallet encryption failed"), - tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted.")); + } else { + assert(model != nullptr); + if(model->setWalletEncrypted(true, newpass1)) + { + QMessageBox::warning(this, tr("Wallet encrypted"), + "" + + tr("Your wallet is now encrypted. ") + encryption_reminder + + "

" + + tr("IMPORTANT: Any previous backups you have made of your wallet file " + "should be replaced with the newly generated, encrypted wallet file. " + "For security reasons, previous backups of the unencrypted wallet file " + "will become useless as soon as you start using the new, encrypted wallet.") + + "
"); + } + else + { + QMessageBox::critical(this, tr("Wallet encryption failed"), + tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted.")); + } } QDialog::accept(); // Success } diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index ac31569f637..bdfd3fb9a06 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -7,6 +7,8 @@ #include +#include + class WalletModel; namespace Ui { @@ -27,7 +29,7 @@ public: Decrypt /**< Ask passphrase and decrypt wallet */ }; - explicit AskPassphraseDialog(Mode mode, QWidget *parent); + explicit AskPassphraseDialog(Mode mode, QWidget *parent, SecureString* passphrase_out = nullptr); ~AskPassphraseDialog(); void accept(); @@ -39,6 +41,7 @@ private: Mode mode; WalletModel *model; bool fCapsLock; + SecureString* m_passphrase_out; private Q_SLOTS: void textChanged(); From 78863e290006e61060622dbdbecc5b58c0fefa05 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 20 Feb 2019 12:22:07 -0500 Subject: [PATCH 3/5] Add CreateWalletDialog to create wallets from the GUI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Barbosa --- contrib/bitcoin-qt.pro | 1 + src/Makefile.qt.include | 4 + src/qt/createwalletdialog.cpp | 61 ++++++++++++ src/qt/createwalletdialog.h | 35 +++++++ src/qt/forms/createwalletdialog.ui | 151 +++++++++++++++++++++++++++++ 5 files changed, 252 insertions(+) create mode 100644 src/qt/createwalletdialog.cpp create mode 100644 src/qt/createwalletdialog.h create mode 100644 src/qt/forms/createwalletdialog.ui diff --git a/contrib/bitcoin-qt.pro b/contrib/bitcoin-qt.pro index b8133bf7891..0e4eeee0a7a 100644 --- a/contrib/bitcoin-qt.pro +++ b/contrib/bitcoin-qt.pro @@ -16,6 +16,7 @@ FORMS += \ ../src/qt/forms/sendcoinsentry.ui \ ../src/qt/forms/signverifymessagedialog.ui \ ../src/qt/forms/transactiondescdialog.ui \ + ../src/qt/forms/createwalletdialog.ui RESOURCES += \ ../src/qt/bitcoin.qrc diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 6d8faf3883f..75401224187 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -98,6 +98,7 @@ QT_FORMS_UI = \ qt/forms/addressbookpage.ui \ qt/forms/askpassphrasedialog.ui \ qt/forms/coincontroldialog.ui \ + qt/forms/createwalletdialog.ui \ qt/forms/editaddressdialog.ui \ qt/forms/helpmessagedialog.ui \ qt/forms/intro.ui \ @@ -117,6 +118,7 @@ QT_MOC_CPP = \ qt/moc_addressbookpage.cpp \ qt/moc_addresstablemodel.cpp \ qt/moc_askpassphrasedialog.cpp \ + qt/moc_createwalletdialog.cpp \ qt/moc_bantablemodel.cpp \ qt/moc_bitcoinaddressvalidator.cpp \ qt/moc_bitcoinamountfield.cpp \ @@ -202,6 +204,7 @@ BITCOIN_QT_H = \ qt/clientmodel.h \ qt/coincontroldialog.h \ qt/coincontroltreewidget.h \ + qt/createwalletdialog.h \ qt/csvmodelwriter.h \ qt/editaddressdialog.h \ qt/guiconstants.h \ @@ -328,6 +331,7 @@ BITCOIN_QT_WALLET_CPP = \ qt/askpassphrasedialog.cpp \ qt/coincontroldialog.cpp \ qt/coincontroltreewidget.cpp \ + qt/createwalletdialog.cpp \ qt/editaddressdialog.cpp \ qt/openuridialog.cpp \ qt/overviewpage.cpp \ diff --git a/src/qt/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp new file mode 100644 index 00000000000..449dcc70a09 --- /dev/null +++ b/src/qt/createwalletdialog.cpp @@ -0,0 +1,61 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#if defined(HAVE_CONFIG_H) +#include +#endif + +#include +#include + +#include + +CreateWalletDialog::CreateWalletDialog(QWidget* parent) : + QDialog(parent), + ui(new Ui::CreateWalletDialog) +{ + ui->setupUi(this); + ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Create"); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + ui->wallet_name_line_edit->setFocus(Qt::ActiveWindowFocusReason); + + connect(ui->wallet_name_line_edit, &QLineEdit::textEdited, [this](const QString& text) { + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty()); + }); + + connect(ui->encrypt_wallet_checkbox, &QCheckBox::toggled, [this](bool checked) { + // Disable disable_privkeys_checkbox when encrypt is set to true, enable it when encrypt is false + ui->disable_privkeys_checkbox->setEnabled(!checked); + + // When the disable_privkeys_checkbox is disabled, uncheck it. + if (!ui->disable_privkeys_checkbox->isEnabled()) { + ui->disable_privkeys_checkbox->setChecked(false); + } + }); +} + +CreateWalletDialog::~CreateWalletDialog() +{ + delete ui; +} + +QString CreateWalletDialog::walletName() const +{ + return ui->wallet_name_line_edit->text(); +} + +bool CreateWalletDialog::encrypt() const +{ + return ui->encrypt_wallet_checkbox->isChecked(); +} + +bool CreateWalletDialog::disablePrivateKeys() const +{ + return ui->disable_privkeys_checkbox->isChecked(); +} + +bool CreateWalletDialog::blank() const +{ + return ui->blank_wallet_checkbox->isChecked(); +} diff --git a/src/qt/createwalletdialog.h b/src/qt/createwalletdialog.h new file mode 100644 index 00000000000..a1365b59694 --- /dev/null +++ b/src/qt/createwalletdialog.h @@ -0,0 +1,35 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_CREATEWALLETDIALOG_H +#define BITCOIN_QT_CREATEWALLETDIALOG_H + +#include + +class WalletModel; + +namespace Ui { + class CreateWalletDialog; +} + +/** Dialog for creating wallets + */ +class CreateWalletDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CreateWalletDialog(QWidget* parent); + virtual ~CreateWalletDialog(); + + QString walletName() const; + bool encrypt() const; + bool disablePrivateKeys() const; + bool blank() const; + +private: + Ui::CreateWalletDialog *ui; +}; + +#endif // BITCOIN_QT_CREATEWALLETDIALOG_H diff --git a/src/qt/forms/createwalletdialog.ui b/src/qt/forms/createwalletdialog.ui new file mode 100644 index 00000000000..1fbaeeaaab3 --- /dev/null +++ b/src/qt/forms/createwalletdialog.ui @@ -0,0 +1,151 @@ + + + CreateWalletDialog + + + + 0 + 0 + 364 + 185 + + + + Create Wallet + + + + + 10 + 140 + 341 + 32 + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 120 + 20 + 231 + 24 + + + + + + + 20 + 20 + 101 + 21 + + + + Wallet Name + + + + + + 20 + 50 + 171 + 22 + + + + Encrypt the wallet. The wallet will be encrypted with a password of your choice. + + + Encrypt Wallet + + + true + + + + + false + + + + 20 + 80 + 171 + 22 + + + + Disable private keys for this wallet. Wallets with private keys disabled will have no private keys and cannot have an HD seed or imported private keys. This is ideal for watch-only wallets. + + + Disable Private Keys + + + + + + 20 + 110 + 171 + 22 + + + + Make a blank wallet. Blank wallets do not initially have private keys or scripts. Private keys and addresses can be imported, or an HD seed can be set, at a later time. + + + Make Blank Wallet + + + + + wallet_name_line_edit + encrypt_wallet_checkbox + disable_privkeys_checkbox + blank_wallet_checkbox + + + + + buttonBox + accepted() + CreateWalletDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CreateWalletDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + From 9b41cbb28f603f4f71f5854d6ae2527932bba3cb Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Fri, 24 May 2019 17:14:16 -0400 Subject: [PATCH 4/5] Expose wallet creation to the GUI via WalletController MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Barbosa --- src/dummywallet.cpp | 7 +++ src/interfaces/node.cpp | 9 ++++ src/interfaces/node.h | 5 ++ src/qt/createwalletdialog.cpp | 2 +- src/qt/guiconstants.h | 2 + src/qt/walletcontroller.cpp | 92 +++++++++++++++++++++++++++++++++++ src/qt/walletcontroller.h | 31 +++++++++++- 7 files changed, 146 insertions(+), 2 deletions(-) diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp index eeec6dec258..126e3479f37 100644 --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -5,8 +5,10 @@ #include #include #include +#include class CWallet; +enum class WalletCreationStatus; namespace interfaces { class Chain; @@ -74,6 +76,11 @@ std::shared_ptr LoadWallet(interfaces::Chain& chain, const std::string& throw std::logic_error("Wallet function called in non-wallet build."); } +WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::string& warning, std::shared_ptr& result) +{ + throw std::logic_error("Wallet function called in non-wallet build."); +} + namespace interfaces { class Wallet; diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index fc49817502f..ccafc3ac8ce 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ fs::path GetWalletDir(); std::vector ListWalletDir(); std::vector> GetWallets(); std::shared_ptr LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning); +WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::string& warning, std::shared_ptr& result); namespace interfaces { @@ -258,6 +260,13 @@ public: { return MakeWallet(LoadWallet(*m_interfaces.chain, name, error, warning)); } + WalletCreationStatus createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::string& warning, std::unique_ptr& result) override + { + std::shared_ptr wallet; + WalletCreationStatus status = CreateWallet(*m_interfaces.chain, passphrase, wallet_creation_flags, name, error, warning, wallet); + result = MakeWallet(wallet); + return status; + } std::unique_ptr handleInitMessage(InitMessageFn fn) override { return MakeHandler(::uiInterface.InitMessage_connect(fn)); diff --git a/src/interfaces/node.h b/src/interfaces/node.h index b93b52c5cc9..e8c3d0b7212 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -9,6 +9,7 @@ #include // For CAmount #include // For CConnman::NumConnections #include // For Network +#include // For SecureString #include #include @@ -27,6 +28,7 @@ class RPCTimerInterface; class UniValue; class proxyType; struct CNodeStateStats; +enum class WalletCreationStatus; namespace interfaces { class Handler; @@ -200,6 +202,9 @@ public: //! with handleLoadWallet. virtual std::unique_ptr loadWallet(const std::string& name, std::string& error, std::string& warning) = 0; + //! Create a wallet from file + virtual WalletCreationStatus createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::string& warning, std::unique_ptr& result) = 0; + //! Register handler for init messages. using InitMessageFn = std::function; virtual std::unique_ptr handleInitMessage(InitMessageFn fn) = 0; diff --git a/src/qt/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp index 449dcc70a09..10262c37c35 100644 --- a/src/qt/createwalletdialog.cpp +++ b/src/qt/createwalletdialog.cpp @@ -16,7 +16,7 @@ CreateWalletDialog::CreateWalletDialog(QWidget* parent) : ui(new Ui::CreateWalletDialog) { ui->setupUi(this); - ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Create"); + ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Create")); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); ui->wallet_name_line_edit->setFocus(Qt::ActiveWindowFocusReason); diff --git a/src/qt/guiconstants.h b/src/qt/guiconstants.h index d8f55949838..dcdb2479770 100644 --- a/src/qt/guiconstants.h +++ b/src/qt/guiconstants.h @@ -5,6 +5,8 @@ #ifndef BITCOIN_QT_GUICONSTANTS_H #define BITCOIN_QT_GUICONSTANTS_H +#include + /* Milliseconds between model updates */ static const int MODEL_UPDATE_DELAY = 250; diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp index 88ccc8c2d6a..1a4f51c066d 100644 --- a/src/qt/walletcontroller.cpp +++ b/src/qt/walletcontroller.cpp @@ -2,9 +2,14 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include +#include #include #include +#include + #include #include @@ -162,6 +167,93 @@ void WalletControllerActivity::showProgressDialog(const QString& label_text) GUIUtil::PolishProgressDialog(m_progress_dialog); } +CreateWalletActivity::CreateWalletActivity(WalletController* wallet_controller, QWidget* parent_widget) + : WalletControllerActivity(wallet_controller, parent_widget) +{ + m_passphrase.reserve(MAX_PASSPHRASE_SIZE); +} + +CreateWalletActivity::~CreateWalletActivity() +{ + delete m_create_wallet_dialog; + delete m_passphrase_dialog; +} + +void CreateWalletActivity::askPasshprase() +{ + m_passphrase_dialog = new AskPassphraseDialog(AskPassphraseDialog::Encrypt, m_parent_widget, &m_passphrase); + m_passphrase_dialog->show(); + + connect(m_passphrase_dialog, &QObject::destroyed, [this] { + m_passphrase_dialog = nullptr; + }); + connect(m_passphrase_dialog, &QDialog::accepted, [this] { + createWallet(); + }); + connect(m_passphrase_dialog, &QDialog::rejected, [this] { + Q_EMIT finished(); + }); +} + +void CreateWalletActivity::createWallet() +{ + showProgressDialog(tr("Creating Wallet %1...").arg(m_create_wallet_dialog->walletName().toHtmlEscaped())); + + std::string name = m_create_wallet_dialog->walletName().toStdString(); + uint64_t flags = 0; + if (m_create_wallet_dialog->disablePrivateKeys()) { + flags |= WALLET_FLAG_DISABLE_PRIVATE_KEYS; + } + if (m_create_wallet_dialog->blank()) { + flags |= WALLET_FLAG_BLANK_WALLET; + } + + QTimer::singleShot(500, worker(), [this, name, flags] { + std::unique_ptr wallet; + WalletCreationStatus status = node().createWallet(m_passphrase, flags, name, m_error_message, m_warning_message, wallet); + + if (status == WalletCreationStatus::SUCCESS) m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(wallet)); + + QTimer::singleShot(500, this, &CreateWalletActivity::finish); + }); +} + +void CreateWalletActivity::finish() +{ + m_progress_dialog->hide(); + + if (!m_error_message.empty()) { + QMessageBox::critical(m_parent_widget, tr("Create wallet failed"), QString::fromStdString(m_error_message)); + } else if (!m_warning_message.empty()) { + QMessageBox::warning(m_parent_widget, tr("Create wallet warning"), QString::fromStdString(m_warning_message)); + } + + if (m_wallet_model) Q_EMIT created(m_wallet_model); + + Q_EMIT finished(); +} + +void CreateWalletActivity::create() +{ + m_create_wallet_dialog = new CreateWalletDialog(m_parent_widget); + m_create_wallet_dialog->setWindowModality(Qt::ApplicationModal); + m_create_wallet_dialog->show(); + + connect(m_create_wallet_dialog, &QObject::destroyed, [this] { + m_create_wallet_dialog = nullptr; + }); + connect(m_create_wallet_dialog, &QDialog::rejected, [this] { + Q_EMIT finished(); + }); + connect(m_create_wallet_dialog, &QDialog::accepted, [this] { + if (m_create_wallet_dialog->encrypt()) { + askPasshprase(); + } else { + createWallet(); + } + }); +} + OpenWalletActivity::OpenWalletActivity(WalletController* wallet_controller, QWidget* parent_widget) : WalletControllerActivity(wallet_controller, parent_widget) { diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h index dada9cfa63d..4e1a772f3ad 100644 --- a/src/qt/walletcontroller.h +++ b/src/qt/walletcontroller.h @@ -6,6 +6,7 @@ #define BITCOIN_QT_WALLETCONTROLLER_H #include +#include #include #include @@ -16,8 +17,9 @@ #include #include #include -#include #include +#include +#include class OptionsModel; class PlatformStyle; @@ -27,6 +29,9 @@ class Handler; class Node; } // namespace interfaces +class AskPassphraseDialog; +class CreateWalletActivity; +class CreateWalletDialog; class OpenWalletActivity; class WalletControllerActivity; @@ -98,6 +103,30 @@ protected: std::string m_warning_message; }; + +class CreateWalletActivity : public WalletControllerActivity +{ + Q_OBJECT + +public: + CreateWalletActivity(WalletController* wallet_controller, QWidget* parent_widget); + virtual ~CreateWalletActivity(); + + void create(); + +Q_SIGNALS: + void created(WalletModel* wallet_model); + +private: + void askPasshprase(); + void createWallet(); + void finish(); + + SecureString m_passphrase; + CreateWalletDialog* m_create_wallet_dialog{nullptr}; + AskPassphraseDialog* m_passphrase_dialog{nullptr}; +}; + class OpenWalletActivity : public WalletControllerActivity { Q_OBJECT From 613de61a04c210a51af9997e69f66439a17a632a Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 20 Feb 2019 12:22:08 -0500 Subject: [PATCH 5/5] Add Create Wallet menu action MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: João Barbosa --- src/qt/bitcoingui.cpp | 11 +++++++++++ src/qt/bitcoingui.h | 1 + 2 files changed, 12 insertions(+) diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 4c520c00dfd..c4960b38d7c 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -339,6 +340,9 @@ void BitcoinGUI::createActions() m_close_wallet_action = new QAction(tr("Close Wallet..."), this); m_close_wallet_action->setStatusTip(tr("Close wallet")); + m_create_wallet_action = new QAction(tr("Create Wallet..."), this); + m_create_wallet_action->setStatusTip(tr("Create a new wallet")); + showHelpMessageAction = new QAction(tr("&Command-line options"), this); showHelpMessageAction->setMenuRole(QAction::NoRole); showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(PACKAGE_NAME)); @@ -394,6 +398,12 @@ void BitcoinGUI::createActions() connect(m_close_wallet_action, &QAction::triggered, [this] { m_wallet_controller->closeWallet(walletFrame->currentWalletModel(), this); }); + connect(m_create_wallet_action, &QAction::triggered, [this] { + auto activity = new CreateWalletActivity(m_wallet_controller, this); + connect(activity, &CreateWalletActivity::created, this, &BitcoinGUI::setCurrentWallet); + connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater); + activity->create(); + }); } #endif // ENABLE_WALLET @@ -415,6 +425,7 @@ void BitcoinGUI::createMenuBar() QMenu *file = appMenuBar->addMenu(tr("&File")); if(walletFrame) { + file->addAction(m_create_wallet_action); file->addAction(m_open_wallet_action); file->addAction(m_close_wallet_action); file->addSeparator(); diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 46ced790074..809cf8b4edf 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -147,6 +147,7 @@ private: QAction* openRPCConsoleAction = nullptr; QAction* openAction = nullptr; QAction* showHelpMessageAction = nullptr; + QAction* m_create_wallet_action{nullptr}; QAction* m_open_wallet_action{nullptr}; QMenu* m_open_wallet_menu{nullptr}; QAction* m_close_wallet_action{nullptr};