diff --git a/src/dummywallet.cpp b/src/dummywallet.cpp --- a/src/dummywallet.cpp +++ b/src/dummywallet.cpp @@ -3,11 +3,13 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include #include #include class CChainParams; class CWallet; +enum class WalletCreationStatus; namespace interfaces { class Chain; @@ -56,6 +58,14 @@ throw std::logic_error("Wallet function called in non-wallet build."); } +WalletCreationStatus +CreateWallet(const CChainParams &chainParams, 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.h b/src/interfaces/node.h --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -5,10 +5,11 @@ #ifndef BITCOIN_INTERFACES_NODE_H #define BITCOIN_INTERFACES_NODE_H -#include // For banmap_t -#include // For Amount -#include // For CConnman::NumConnections -#include // For Network +#include // For banmap_t +#include // For Amount +#include // For CConnman::NumConnections +#include // For Network +#include // For SecureString #include #include @@ -31,6 +32,7 @@ class RPCServer; class RPCTimerInterface; class UniValue; +enum class WalletCreationStatus; namespace interfaces { class Handler; @@ -208,6 +210,13 @@ std::string &error, std::string &warning) const = 0; + //! Create a wallet from file + virtual WalletCreationStatus + createWallet(const CChainParams ¶ms, 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/interfaces/node.cpp b/src/interfaces/node.cpp --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,11 @@ interfaces::Chain &chain, const std::string &name, std::string &error, std::string &warning); +WalletCreationStatus +CreateWallet(const CChainParams ¶ms, 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 { @@ -278,6 +284,18 @@ return MakeWallet( LoadWallet(params, *m_context.chain, name, error, warning)); } + WalletCreationStatus + createWallet(const CChainParams ¶ms, 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( + params, *m_context.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/qt/createwalletdialog.cpp b/src/qt/createwalletdialog.cpp --- a/src/qt/createwalletdialog.cpp +++ b/src/qt/createwalletdialog.cpp @@ -14,7 +14,7 @@ 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)->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 --- 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.h b/src/qt/walletcontroller.h --- a/src/qt/walletcontroller.h +++ b/src/qt/walletcontroller.h @@ -6,6 +6,7 @@ #define BITCOIN_QT_WALLETCONTROLLER_H #include +#include #include #include @@ -19,6 +20,7 @@ #include #include #include +#include class OptionsModel; class PlatformStyle; @@ -28,6 +30,9 @@ class Node; } // namespace interfaces +class AskPassphraseDialog; +class CreateWalletActivity; +class CreateWalletDialog; class OpenWalletActivity; class WalletControllerActivity; @@ -104,6 +109,30 @@ const CChainParams &m_chainparams; }; +class CreateWalletActivity : public WalletControllerActivity { + Q_OBJECT + +public: + CreateWalletActivity(WalletController *wallet_controller, + QWidget *parent_widget, + const CChainParams &chainparams); + virtual ~CreateWalletActivity(); + + void create(); + +Q_SIGNALS: + void created(WalletModel *wallet_model); + +private: + void askPassphrase(); + void createWallet(); + void finish(); + + SecureString m_passphrase; + CreateWalletDialog *m_create_wallet_dialog{nullptr}; + AskPassphraseDialog *m_passphrase_dialog{nullptr}; +}; + class OpenWalletActivity : public WalletControllerActivity { Q_OBJECT diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp --- 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 @@ -168,6 +173,96 @@ GUIUtil::PolishProgressDialog(m_progress_dialog); } +CreateWalletActivity::CreateWalletActivity(WalletController *wallet_controller, + QWidget *parent_widget, + const CChainParams &chainparams) + : WalletControllerActivity(wallet_controller, parent_widget, chainparams) { + m_passphrase.reserve(MAX_PASSPHRASE_SIZE); +} + +CreateWalletActivity::~CreateWalletActivity() { + delete m_create_wallet_dialog; + delete m_passphrase_dialog; +} + +void CreateWalletActivity::askPassphrase() { + 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(this->m_chainparams, 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()) { + askPassphrase(); + } else { + createWallet(); + } + }); +} + OpenWalletActivity::OpenWalletActivity(WalletController *wallet_controller, QWidget *parent_widget, const CChainParams &chainparams)