aboutsummaryrefslogtreecommitdiff
path: root/src/qt
diff options
context:
space:
mode:
authorAndrew Chow <github@achow101.com>2023-06-13 15:04:43 -0400
committerAndrew Chow <github@achow101.com>2023-06-23 14:24:33 -0400
commit48aae2cffeb91add75a70ac4d5075c38054452fa (patch)
tree87f61b153b99287ce844e0a8cf5423df887b3533 /src/qt
parent577be889cd52fc2d896a5f39c66bc2cadb8622e4 (diff)
downloadbitcoin-48aae2cffeb91add75a70ac4d5075c38054452fa.tar.xz
gui: Add File > Migrate Wallet
Diffstat (limited to 'src/qt')
-rw-r--r--src/qt/bitcoingui.cpp12
-rw-r--r--src/qt/bitcoingui.h2
-rw-r--r--src/qt/walletcontroller.cpp64
-rw-r--r--src/qt/walletcontroller.h22
4 files changed, 100 insertions, 0 deletions
diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp
index f201d8fa01..6147d986d0 100644
--- a/src/qt/bitcoingui.cpp
+++ b/src/qt/bitcoingui.cpp
@@ -359,6 +359,10 @@ void BitcoinGUI::createActions()
m_close_all_wallets_action = new QAction(tr("Close All Wallets…"), this);
m_close_all_wallets_action->setStatusTip(tr("Close all wallets"));
+ m_migrate_wallet_action = new QAction(tr("Migrate Wallet"), this);
+ m_migrate_wallet_action->setEnabled(false);
+ m_migrate_wallet_action->setStatusTip(tr("Migrate a 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));
@@ -456,6 +460,11 @@ void BitcoinGUI::createActions()
connect(m_close_all_wallets_action, &QAction::triggered, [this] {
m_wallet_controller->closeAllWallets(this);
});
+ connect(m_migrate_wallet_action, &QAction::triggered, [this] {
+ auto activity = new MigrateWalletActivity(m_wallet_controller, this);
+ connect(activity, &MigrateWalletActivity::migrated, this, &BitcoinGUI::setCurrentWallet);
+ activity->migrate(walletFrame->currentWalletModel());
+ });
connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::setPrivacy);
connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::enableHistoryAction);
}
@@ -483,6 +492,7 @@ void BitcoinGUI::createMenuBar()
file->addAction(m_open_wallet_action);
file->addAction(m_close_wallet_action);
file->addAction(m_close_all_wallets_action);
+ file->addAction(m_migrate_wallet_action);
file->addSeparator();
file->addAction(backupWalletAction);
file->addAction(m_restore_wallet_action);
@@ -767,6 +777,7 @@ void BitcoinGUI::setCurrentWallet(WalletModel* wallet_model)
}
}
updateWindowTitle();
+ m_migrate_wallet_action->setEnabled(wallet_model->wallet().isLegacy());
}
void BitcoinGUI::setCurrentWalletBySelectorIndex(int index)
@@ -800,6 +811,7 @@ void BitcoinGUI::setWalletActionsEnabled(bool enabled)
openAction->setEnabled(enabled);
m_close_wallet_action->setEnabled(enabled);
m_close_all_wallets_action->setEnabled(enabled);
+ m_migrate_wallet_action->setEnabled(enabled);
}
void BitcoinGUI::createTrayIcon()
diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h
index 92b889263b..0887ebd8cc 100644
--- a/src/qt/bitcoingui.h
+++ b/src/qt/bitcoingui.h
@@ -163,6 +163,8 @@ private:
QAction* m_wallet_selector_label_action = nullptr;
QAction* m_wallet_selector_action = nullptr;
QAction* m_mask_values_action{nullptr};
+ QAction* m_migrate_wallet_action{nullptr};
+ QMenu* m_migrate_wallet_menu{nullptr};
QLabel *m_wallet_selector_label = nullptr;
QComboBox* m_wallet_selector = nullptr;
diff --git a/src/qt/walletcontroller.cpp b/src/qt/walletcontroller.cpp
index d782838d6f..7b2ac4f90a 100644
--- a/src/qt/walletcontroller.cpp
+++ b/src/qt/walletcontroller.cpp
@@ -432,3 +432,67 @@ void RestoreWalletActivity::finish()
Q_EMIT finished();
}
+
+void MigrateWalletActivity::migrate(WalletModel* wallet_model)
+{
+ // Warn the user about migration
+ QMessageBox box(m_parent_widget);
+ box.setWindowTitle(tr("Migrate wallet"));
+ box.setText(tr("Are you sure you wish to migrate the wallet <i>%1</i>?").arg(GUIUtil::HtmlEscape(wallet_model->getDisplayName())));
+ box.setInformativeText(tr("Migrating the wallet will convert this wallet to one or more descriptor wallets. A new wallet backup will need to be made.\n"
+ "If this wallet contains any watchonly scripts, a new wallet will be created which contains those watchonly scripts.\n"
+ "If this wallet contains any solvable but not watched scripts, a different and new wallet will be created which contains those scripts.\n\n"
+ "The migration process will create a backup of the wallet before migrating. This backup file will be named "
+ "<wallet name>-<timestamp>.legacy.bak and can be found in the directory for this wallet. In the event of "
+ "an incorrect migration, the backup can be restored with the \"Restore Wallet\" functionality."));
+ box.setStandardButtons(QMessageBox::Yes|QMessageBox::Cancel);
+ box.setDefaultButton(QMessageBox::Yes);
+ if (box.exec() != QMessageBox::Yes) return;
+
+ // Get the passphrase if it is encrypted regardless of it is locked or unlocked. We need the passphrase itself.
+ SecureString passphrase;
+ WalletModel::EncryptionStatus enc_status = wallet_model->getEncryptionStatus();
+ if (enc_status == WalletModel::EncryptionStatus::Locked || enc_status == WalletModel::EncryptionStatus::Unlocked) {
+ AskPassphraseDialog dlg(AskPassphraseDialog::Unlock, m_parent_widget, &passphrase);
+ dlg.setModel(wallet_model);
+ dlg.exec();
+ }
+
+ // GUI needs to remove the wallet so that it can actually be unloaded by migration
+ const std::string name = wallet_model->wallet().getWalletName();
+ m_wallet_controller->removeAndDeleteWallet(wallet_model);
+
+ showProgressDialog(tr("Migrate Wallet"), tr("Migrating Wallet <b>%1</b>…").arg(GUIUtil::HtmlEscape(name)));
+
+ QTimer::singleShot(0, worker(), [this, name, passphrase] {
+ auto res{node().walletLoader().migrateWallet(name, passphrase)};
+
+ if (res) {
+ m_success_message = tr("The wallet '%1' was migrated successfully.").arg(GUIUtil::HtmlEscape(res->wallet->getWalletName()));
+ if (res->watchonly_wallet_name) {
+ m_success_message += tr(" Watchonly scripts have been migrated to a new wallet named '%1'.").arg(GUIUtil::HtmlEscape(res->watchonly_wallet_name.value()));
+ }
+ if (res->solvables_wallet_name) {
+ m_success_message += tr(" Solvable but not watched scripts have been migrated to a new wallet named '%1'.").arg(GUIUtil::HtmlEscape(res->solvables_wallet_name.value()));
+ }
+ m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(res->wallet));
+ } else {
+ m_error_message = util::ErrorString(res);
+ }
+
+ QTimer::singleShot(0, this, &MigrateWalletActivity::finish);
+ });
+}
+
+void MigrateWalletActivity::finish()
+{
+ if (!m_error_message.empty()) {
+ QMessageBox::critical(m_parent_widget, tr("Migration failed"), QString::fromStdString(m_error_message.translated));
+ } else {
+ QMessageBox::information(m_parent_widget, tr("Migration Successful"), m_success_message);
+ }
+
+ if (m_wallet_model) Q_EMIT migrated(m_wallet_model);
+
+ Q_EMIT finished();
+}
diff --git a/src/qt/walletcontroller.h b/src/qt/walletcontroller.h
index fcd65756c6..4f2443a727 100644
--- a/src/qt/walletcontroller.h
+++ b/src/qt/walletcontroller.h
@@ -40,6 +40,7 @@ class path;
class AskPassphraseDialog;
class CreateWalletActivity;
class CreateWalletDialog;
+class MigrateWalletActivity;
class OpenWalletActivity;
class WalletControllerActivity;
@@ -65,6 +66,8 @@ public:
void closeWallet(WalletModel* wallet_model, QWidget* parent = nullptr);
void closeAllWallets(QWidget* parent = nullptr);
+ void migrateWallet(WalletModel* wallet_model, QWidget* parent = nullptr);
+
Q_SIGNALS:
void walletAdded(WalletModel* wallet_model);
void walletRemoved(WalletModel* wallet_model);
@@ -83,6 +86,7 @@ private:
std::unique_ptr<interfaces::Handler> m_handler_load_wallet;
friend class WalletControllerActivity;
+ friend class MigrateWalletActivity;
};
class WalletControllerActivity : public QObject
@@ -175,4 +179,22 @@ private:
void finish();
};
+class MigrateWalletActivity : public WalletControllerActivity
+{
+ Q_OBJECT
+
+public:
+ MigrateWalletActivity(WalletController* wallet_controller, QWidget* parent) : WalletControllerActivity(wallet_controller, parent) {}
+
+ void migrate(WalletModel* wallet_model);
+
+Q_SIGNALS:
+ void migrated(WalletModel* wallet_model);
+
+private:
+ QString m_success_message;
+
+ void finish();
+};
+
#endif // BITCOIN_QT_WALLETCONTROLLER_H