Skip to content

Commit b5a8d0c

Browse files
committed
Merge #15450: gui: Create wallet menu option
613de61 Add Create Wallet menu action (Andrew Chow) 9b41cbb Expose wallet creation to the GUI via WalletController (Andrew Chow) 78863e2 Add CreateWalletDialog to create wallets from the GUI (Andrew Chow) 60adb21 Optionally allow AskPassphraseDialog to output the passphrase (Andrew Chow) bc6d8a3 gui: Refactor OpenWalletActivity (João Barbosa) Pull request description: This PR adds a menu option to create a new wallet. When clicked, a `CreateWalletDialog` will be created and prompt the user to name the wallet and choose whether to disable private keys, make a blank wallet, and encrypt the wallet. If the wallet is encrypted, the wallet will be born encrypted with the wallet first created blank, then encrypted, and then a new HD seed generated and set. To allow the newly created wallets to be encrypted, some changes to how encrypting a wallet works. Instead of encrypting and locking the wallet, the wallet will be encrypted and then unlocked. This is also an extra belt-and-suspenders check to make sure that encryption worked. ACKs for top commit: fanquake: ACK 613de61 - re-reviewed on macOS. I'm going to merge this now. It's had a stack of review, and as mentioned multiple times above, lets get this into `master` so it can get more testing pre `v0.19.0`. Tree-SHA512: 3f22cc20b13703ffc90d366ae9133114832fea77f4f319da7fd85eb454f2f0bd5d7e1e6e20284dea2f370d8574f83b45669dcbbe506b994410d32e8e7a6fa877
2 parents e4b9748 + 613de61 commit b5a8d0c

15 files changed

+541
-78
lines changed

contrib/bitcoin-qt.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ FORMS += \
1616
../src/qt/forms/sendcoinsentry.ui \
1717
../src/qt/forms/signverifymessagedialog.ui \
1818
../src/qt/forms/transactiondescdialog.ui \
19+
../src/qt/forms/createwalletdialog.ui
1920

2021
RESOURCES += \
2122
../src/qt/bitcoin.qrc

src/Makefile.qt.include

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ QT_FORMS_UI = \
9898
qt/forms/addressbookpage.ui \
9999
qt/forms/askpassphrasedialog.ui \
100100
qt/forms/coincontroldialog.ui \
101+
qt/forms/createwalletdialog.ui \
101102
qt/forms/editaddressdialog.ui \
102103
qt/forms/helpmessagedialog.ui \
103104
qt/forms/intro.ui \
@@ -117,6 +118,7 @@ QT_MOC_CPP = \
117118
qt/moc_addressbookpage.cpp \
118119
qt/moc_addresstablemodel.cpp \
119120
qt/moc_askpassphrasedialog.cpp \
121+
qt/moc_createwalletdialog.cpp \
120122
qt/moc_bantablemodel.cpp \
121123
qt/moc_bitcoinaddressvalidator.cpp \
122124
qt/moc_bitcoinamountfield.cpp \
@@ -202,6 +204,7 @@ BITCOIN_QT_H = \
202204
qt/clientmodel.h \
203205
qt/coincontroldialog.h \
204206
qt/coincontroltreewidget.h \
207+
qt/createwalletdialog.h \
205208
qt/csvmodelwriter.h \
206209
qt/editaddressdialog.h \
207210
qt/guiconstants.h \
@@ -328,6 +331,7 @@ BITCOIN_QT_WALLET_CPP = \
328331
qt/askpassphrasedialog.cpp \
329332
qt/coincontroldialog.cpp \
330333
qt/coincontroltreewidget.cpp \
334+
qt/createwalletdialog.cpp \
331335
qt/editaddressdialog.cpp \
332336
qt/openuridialog.cpp \
333337
qt/overviewpage.cpp \

src/dummywallet.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
#include <stdio.h>
66
#include <util/system.h>
77
#include <walletinitinterface.h>
8+
#include <support/allocators/secure.h>
89

910
class CWallet;
11+
enum class WalletCreationStatus;
1012

1113
namespace interfaces {
1214
class Chain;
@@ -74,6 +76,11 @@ std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string&
7476
throw std::logic_error("Wallet function called in non-wallet build.");
7577
}
7678

79+
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<CWallet>& result)
80+
{
81+
throw std::logic_error("Wallet function called in non-wallet build.");
82+
}
83+
7784
namespace interfaces {
7885

7986
class Wallet;

src/interfaces/node.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <primitives/block.h>
2525
#include <rpc/server.h>
2626
#include <shutdown.h>
27+
#include <support/allocators/secure.h>
2728
#include <sync.h>
2829
#include <txmempool.h>
2930
#include <ui_interface.h>
@@ -43,6 +44,7 @@ fs::path GetWalletDir();
4344
std::vector<fs::path> ListWalletDir();
4445
std::vector<std::shared_ptr<CWallet>> GetWallets();
4546
std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning);
47+
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<CWallet>& result);
4648

4749
namespace interfaces {
4850

@@ -258,6 +260,13 @@ class NodeImpl : public Node
258260
{
259261
return MakeWallet(LoadWallet(*m_interfaces.chain, name, error, warning));
260262
}
263+
WalletCreationStatus createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::string& warning, std::unique_ptr<Wallet>& result) override
264+
{
265+
std::shared_ptr<CWallet> wallet;
266+
WalletCreationStatus status = CreateWallet(*m_interfaces.chain, passphrase, wallet_creation_flags, name, error, warning, wallet);
267+
result = MakeWallet(wallet);
268+
return status;
269+
}
261270
std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) override
262271
{
263272
return MakeHandler(::uiInterface.InitMessage_connect(fn));

src/interfaces/node.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <amount.h> // For CAmount
1010
#include <net.h> // For CConnman::NumConnections
1111
#include <netaddress.h> // For Network
12+
#include <support/allocators/secure.h> // For SecureString
1213

1314
#include <functional>
1415
#include <memory>
@@ -27,6 +28,7 @@ class RPCTimerInterface;
2728
class UniValue;
2829
class proxyType;
2930
struct CNodeStateStats;
31+
enum class WalletCreationStatus;
3032

3133
namespace interfaces {
3234
class Handler;
@@ -200,6 +202,9 @@ class Node
200202
//! with handleLoadWallet.
201203
virtual std::unique_ptr<Wallet> loadWallet(const std::string& name, std::string& error, std::string& warning) = 0;
202204

205+
//! Create a wallet from file
206+
virtual WalletCreationStatus createWallet(const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::string& warning, std::unique_ptr<Wallet>& result) = 0;
207+
203208
//! Register handler for init messages.
204209
using InitMessageFn = std::function<void(const std::string& message)>;
205210
virtual std::unique_ptr<Handler> handleInitMessage(InitMessageFn fn) = 0;

src/qt/askpassphrasedialog.cpp

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
#include <QMessageBox>
1919
#include <QPushButton>
2020

21-
AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent) :
21+
AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureString* passphrase_out) :
2222
QDialog(parent),
2323
ui(new Ui::AskPassphraseDialog),
2424
mode(_mode),
2525
model(nullptr),
26-
fCapsLock(false)
26+
fCapsLock(false),
27+
m_passphrase_out(passphrase_out)
2728
{
2829
ui->setupUi(this);
2930

@@ -90,7 +91,7 @@ void AskPassphraseDialog::setModel(WalletModel *_model)
9091
void AskPassphraseDialog::accept()
9192
{
9293
SecureString oldpass, newpass1, newpass2;
93-
if(!model)
94+
if (!model && mode != Encrypt)
9495
return;
9596
oldpass.reserve(MAX_PASSPHRASE_SIZE);
9697
newpass1.reserve(MAX_PASSPHRASE_SIZE);
@@ -119,24 +120,33 @@ void AskPassphraseDialog::accept()
119120
{
120121
if(newpass1 == newpass2)
121122
{
122-
if(model->setWalletEncrypted(true, newpass1))
123-
{
124-
QMessageBox::warning(this, tr("Wallet encrypted"),
123+
QString encryption_reminder = tr("Remember that encrypting your wallet cannot fully protect "
124+
"your bitcoins from being stolen by malware infecting your computer.");
125+
if (m_passphrase_out) {
126+
m_passphrase_out->assign(newpass1);
127+
QMessageBox::warning(this, tr("Wallet to be encrypted"),
125128
"<qt>" +
126-
tr("Your wallet is now encrypted. "
127-
"Remember that encrypting your wallet cannot fully protect "
128-
"your bitcoins from being stolen by malware infecting your computer.") +
129-
"<br><br><b>" +
130-
tr("IMPORTANT: Any previous backups you have made of your wallet file "
131-
"should be replaced with the newly generated, encrypted wallet file. "
132-
"For security reasons, previous backups of the unencrypted wallet file "
133-
"will become useless as soon as you start using the new, encrypted wallet.") +
129+
tr("Your wallet is about to be encrypted. ") + encryption_reminder +
134130
"</b></qt>");
135-
}
136-
else
137-
{
138-
QMessageBox::critical(this, tr("Wallet encryption failed"),
139-
tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
131+
} else {
132+
assert(model != nullptr);
133+
if(model->setWalletEncrypted(true, newpass1))
134+
{
135+
QMessageBox::warning(this, tr("Wallet encrypted"),
136+
"<qt>" +
137+
tr("Your wallet is now encrypted. ") + encryption_reminder +
138+
"<br><br><b>" +
139+
tr("IMPORTANT: Any previous backups you have made of your wallet file "
140+
"should be replaced with the newly generated, encrypted wallet file. "
141+
"For security reasons, previous backups of the unencrypted wallet file "
142+
"will become useless as soon as you start using the new, encrypted wallet.") +
143+
"</b></qt>");
144+
}
145+
else
146+
{
147+
QMessageBox::critical(this, tr("Wallet encryption failed"),
148+
tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
149+
}
140150
}
141151
QDialog::accept(); // Success
142152
}

src/qt/askpassphrasedialog.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#include <QDialog>
99

10+
#include <support/allocators/secure.h>
11+
1012
class WalletModel;
1113

1214
namespace Ui {
@@ -27,7 +29,7 @@ class AskPassphraseDialog : public QDialog
2729
Decrypt /**< Ask passphrase and decrypt wallet */
2830
};
2931

30-
explicit AskPassphraseDialog(Mode mode, QWidget *parent);
32+
explicit AskPassphraseDialog(Mode mode, QWidget *parent, SecureString* passphrase_out = nullptr);
3133
~AskPassphraseDialog();
3234

3335
void accept();
@@ -39,6 +41,7 @@ class AskPassphraseDialog : public QDialog
3941
Mode mode;
4042
WalletModel *model;
4143
bool fCapsLock;
44+
SecureString* m_passphrase_out;
4245

4346
private Q_SLOTS:
4447
void textChanged();

src/qt/bitcoingui.cpp

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <qt/bitcoinunits.h>
88
#include <qt/clientmodel.h>
9+
#include <qt/createwalletdialog.h>
910
#include <qt/guiconstants.h>
1011
#include <qt/guiutil.h>
1112
#include <qt/modaloverlay.h>
@@ -339,6 +340,9 @@ void BitcoinGUI::createActions()
339340
m_close_wallet_action = new QAction(tr("Close Wallet..."), this);
340341
m_close_wallet_action->setStatusTip(tr("Close wallet"));
341342

343+
m_create_wallet_action = new QAction(tr("Create Wallet..."), this);
344+
m_create_wallet_action->setStatusTip(tr("Create a new wallet"));
345+
342346
showHelpMessageAction = new QAction(tr("&Command-line options"), this);
343347
showHelpMessageAction->setMenuRole(QAction::NoRole);
344348
showHelpMessageAction->setStatusTip(tr("Show the %1 help message to get a list with possible Bitcoin command-line options").arg(PACKAGE_NAME));
@@ -379,31 +383,11 @@ void BitcoinGUI::createActions()
379383
continue;
380384
}
381385

382-
connect(action, &QAction::triggered, [this, name, path] {
383-
OpenWalletActivity* activity = m_wallet_controller->openWallet(path);
384-
385-
QProgressDialog* dialog = new QProgressDialog(this);
386-
dialog->setLabelText(tr("Opening Wallet <b>%1</b>...").arg(name.toHtmlEscaped()));
387-
dialog->setRange(0, 0);
388-
dialog->setCancelButton(nullptr);
389-
dialog->setWindowModality(Qt::ApplicationModal);
390-
dialog->show();
391-
392-
connect(activity, &OpenWalletActivity::message, this, [this] (QMessageBox::Icon icon, QString text) {
393-
QMessageBox box;
394-
box.setIcon(icon);
395-
box.setText(tr("Open Wallet Failed"));
396-
box.setInformativeText(text);
397-
box.setStandardButtons(QMessageBox::Ok);
398-
box.setDefaultButton(QMessageBox::Ok);
399-
connect(this, &QObject::destroyed, &box, &QDialog::accept);
400-
box.exec();
401-
});
386+
connect(action, &QAction::triggered, [this, path] {
387+
auto activity = new OpenWalletActivity(m_wallet_controller, this);
402388
connect(activity, &OpenWalletActivity::opened, this, &BitcoinGUI::setCurrentWallet);
403389
connect(activity, &OpenWalletActivity::finished, activity, &QObject::deleteLater);
404-
connect(activity, &OpenWalletActivity::finished, dialog, &QObject::deleteLater);
405-
bool invoked = QMetaObject::invokeMethod(activity, "open");
406-
assert(invoked);
390+
activity->open(path);
407391
});
408392
}
409393
if (m_open_wallet_menu->isEmpty()) {
@@ -414,6 +398,12 @@ void BitcoinGUI::createActions()
414398
connect(m_close_wallet_action, &QAction::triggered, [this] {
415399
m_wallet_controller->closeWallet(walletFrame->currentWalletModel(), this);
416400
});
401+
connect(m_create_wallet_action, &QAction::triggered, [this] {
402+
auto activity = new CreateWalletActivity(m_wallet_controller, this);
403+
connect(activity, &CreateWalletActivity::created, this, &BitcoinGUI::setCurrentWallet);
404+
connect(activity, &CreateWalletActivity::finished, activity, &QObject::deleteLater);
405+
activity->create();
406+
});
417407
}
418408
#endif // ENABLE_WALLET
419409

@@ -435,6 +425,7 @@ void BitcoinGUI::createMenuBar()
435425
QMenu *file = appMenuBar->addMenu(tr("&File"));
436426
if(walletFrame)
437427
{
428+
file->addAction(m_create_wallet_action);
438429
file->addAction(m_open_wallet_action);
439430
file->addAction(m_close_wallet_action);
440431
file->addSeparator();

src/qt/bitcoingui.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ class BitcoinGUI : public QMainWindow
147147
QAction* openRPCConsoleAction = nullptr;
148148
QAction* openAction = nullptr;
149149
QAction* showHelpMessageAction = nullptr;
150+
QAction* m_create_wallet_action{nullptr};
150151
QAction* m_open_wallet_action{nullptr};
151152
QMenu* m_open_wallet_menu{nullptr};
152153
QAction* m_close_wallet_action{nullptr};

src/qt/createwalletdialog.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) 2019 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+
#if defined(HAVE_CONFIG_H)
6+
#include <config/bitcoin-config.h>
7+
#endif
8+
9+
#include <qt/createwalletdialog.h>
10+
#include <qt/forms/ui_createwalletdialog.h>
11+
12+
#include <QPushButton>
13+
14+
CreateWalletDialog::CreateWalletDialog(QWidget* parent) :
15+
QDialog(parent),
16+
ui(new Ui::CreateWalletDialog)
17+
{
18+
ui->setupUi(this);
19+
ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Create"));
20+
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
21+
ui->wallet_name_line_edit->setFocus(Qt::ActiveWindowFocusReason);
22+
23+
connect(ui->wallet_name_line_edit, &QLineEdit::textEdited, [this](const QString& text) {
24+
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!text.isEmpty());
25+
});
26+
27+
connect(ui->encrypt_wallet_checkbox, &QCheckBox::toggled, [this](bool checked) {
28+
// Disable disable_privkeys_checkbox when encrypt is set to true, enable it when encrypt is false
29+
ui->disable_privkeys_checkbox->setEnabled(!checked);
30+
31+
// When the disable_privkeys_checkbox is disabled, uncheck it.
32+
if (!ui->disable_privkeys_checkbox->isEnabled()) {
33+
ui->disable_privkeys_checkbox->setChecked(false);
34+
}
35+
});
36+
}
37+
38+
CreateWalletDialog::~CreateWalletDialog()
39+
{
40+
delete ui;
41+
}
42+
43+
QString CreateWalletDialog::walletName() const
44+
{
45+
return ui->wallet_name_line_edit->text();
46+
}
47+
48+
bool CreateWalletDialog::encrypt() const
49+
{
50+
return ui->encrypt_wallet_checkbox->isChecked();
51+
}
52+
53+
bool CreateWalletDialog::disablePrivateKeys() const
54+
{
55+
return ui->disable_privkeys_checkbox->isChecked();
56+
}
57+
58+
bool CreateWalletDialog::blank() const
59+
{
60+
return ui->blank_wallet_checkbox->isChecked();
61+
}

0 commit comments

Comments
 (0)