mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-02-09 07:01:44 +00:00
Merge bitcoin-core/gui#877: Add a menu action to restore then migrate a legacy wallet
14371fd1fca5c88764073a015aa3ff2ac96710bf gui: Add a menu item to restore then migrate a wallet file (Ava Chow) f11a7d248cf5bdac5164bf527054b0822b5294ab gui: Add restore_and_migrate function to restore then migrate a wallet (Ava Chow) 16ab6dfc1074b43c6fa80181574dc6e77b9aae1c gui: Move actual migration part of migrate() to its own function (Ava Chow) 4ec2d18a0734f44c0a74f05b59ad1269d323dfdb wallet, interfaces, gui: Expose load_after_restore parameter (Ava Chow) Pull request description: Some users will have a backup of their legacy wallet. These cannot be restored since the "Restore Wallet" action expects to be able to load the wallet after restoring, and this fails for legacy wallets now that they are deleted. Furthermore, the "Migrate Wallet" action only allows users to migrate wallets that are in the wallets directory, so such backups cannot be migrated from the GUI. This PR resolves this issue by adding a menu item in the "Migrate Wallet" menu which allows users to select their backup file so that it will first be restored but not loaded, and then migrated. Depends on https://github.com/bitcoin/bitcoin/pull/32620 ACKs for top commit: hebasto: ACK 14371fd1fca5c88764073a015aa3ff2ac96710bf. Tree-SHA512: 2b09c012f4c70d0cb283305bf3d1a18ae5a2bfb80977c91544ac1fbc29d6360df49438cfdc8f66661ddb42ddab728c8ef1f9e0d7031877fbd846f9cea957398e
This commit is contained in:
commit
41bf8f2d5e
@ -325,7 +325,7 @@ public:
|
||||
virtual std::string getWalletDir() = 0;
|
||||
|
||||
//! Restore backup wallet
|
||||
virtual util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) = 0;
|
||||
virtual util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings, bool load_after_restore) = 0;
|
||||
|
||||
//! Migrate a wallet
|
||||
virtual util::Result<WalletMigrationResult> migrateWallet(const std::string& name, const SecureString& passphrase) = 0;
|
||||
|
||||
@ -485,6 +485,32 @@ void BitcoinGUI::createActions()
|
||||
QAction* action = m_migrate_wallet_menu->addAction(tr("No wallets available"));
|
||||
action->setEnabled(false);
|
||||
}
|
||||
m_migrate_wallet_menu->addSeparator();
|
||||
QAction* restore_migrate_file_action = m_migrate_wallet_menu->addAction(tr("Restore and Migrate Wallet File..."));
|
||||
restore_migrate_file_action->setEnabled(true);
|
||||
|
||||
connect(restore_migrate_file_action, &QAction::triggered, [this] {
|
||||
QString name_data_file = tr("Wallet Data");
|
||||
QString title_windows = tr("Restore and Migrate Wallet Backup");
|
||||
|
||||
QString backup_file = GUIUtil::getOpenFileName(this, title_windows, QString(), name_data_file + QLatin1String(" (*.dat)"), nullptr);
|
||||
if (backup_file.isEmpty()) return;
|
||||
|
||||
bool wallet_name_ok;
|
||||
/*: Title of pop-up window shown when the user is attempting to
|
||||
restore a wallet. */
|
||||
QString title = tr("Restore and Migrate Wallet");
|
||||
//: Label of the input field where the name of the wallet is entered.
|
||||
QString label = tr("Wallet Name");
|
||||
QString wallet_name = QInputDialog::getText(this, title, label, QLineEdit::Normal, "", &wallet_name_ok);
|
||||
if (!wallet_name_ok || wallet_name.isEmpty()) return;
|
||||
|
||||
auto activity = new MigrateWalletActivity(m_wallet_controller, this);
|
||||
connect(activity, &MigrateWalletActivity::migrated, this, &BitcoinGUI::setCurrentWallet);
|
||||
connect(activity, &MigrateWalletActivity::migrated, rpcConsole, &RPCConsole::setCurrentWallet);
|
||||
auto backup_file_path = fs::PathFromString(backup_file.toStdString());
|
||||
activity->restore_and_migrate(backup_file_path, wallet_name.toStdString());
|
||||
});
|
||||
});
|
||||
connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::setPrivacy);
|
||||
connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::enableHistoryAction);
|
||||
|
||||
@ -409,7 +409,7 @@ void RestoreWalletActivity::restore(const fs::path& backup_file, const std::stri
|
||||
tr("Restoring Wallet <b>%1</b>…").arg(name.toHtmlEscaped()));
|
||||
|
||||
QTimer::singleShot(0, worker(), [this, backup_file, wallet_name] {
|
||||
auto wallet{node().walletLoader().restoreWallet(backup_file, wallet_name, m_warning_message)};
|
||||
auto wallet{node().walletLoader().restoreWallet(backup_file, wallet_name, m_warning_message, /*load_after_restore=*/true)};
|
||||
|
||||
if (wallet) {
|
||||
m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(*wallet));
|
||||
@ -439,22 +439,8 @@ void RestoreWalletActivity::finish()
|
||||
Q_EMIT finished();
|
||||
}
|
||||
|
||||
void MigrateWalletActivity::migrate(const std::string& name)
|
||||
void MigrateWalletActivity::do_migrate(const std::string& name)
|
||||
{
|
||||
// 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(GUIUtil::WalletDisplayName(name))));
|
||||
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;
|
||||
|
||||
SecureString passphrase;
|
||||
if (node().walletLoader().isEncrypted(name)) {
|
||||
// Get the passphrase for the wallet
|
||||
@ -484,6 +470,64 @@ void MigrateWalletActivity::migrate(const std::string& name)
|
||||
});
|
||||
}
|
||||
|
||||
void MigrateWalletActivity::migrate(const std::string& name)
|
||||
{
|
||||
// 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(GUIUtil::WalletDisplayName(name))));
|
||||
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;
|
||||
|
||||
do_migrate(name);
|
||||
}
|
||||
|
||||
void MigrateWalletActivity::restore_and_migrate(const fs::path& path, const std::string& wallet_name)
|
||||
{
|
||||
// Warn the user about migration
|
||||
QMessageBox box(m_parent_widget);
|
||||
box.setWindowTitle(tr("Restore and Migrate wallet"));
|
||||
box.setText(tr("Are you sure you wish to restore the wallet file <i>%1</i> to <i>%2</i> and migrate it?").arg(GUIUtil::HtmlEscape(fs::PathToString(path)), GUIUtil::HtmlEscape(GUIUtil::WalletDisplayName(wallet_name))));
|
||||
box.setInformativeText(tr("Restoring the wallet will copy the backup file to the wallets directory and place it in the standard "
|
||||
"wallet directory layout. The original file will not be modified.\n\n"
|
||||
"Migrating the wallet will convert the restored 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;
|
||||
|
||||
showProgressDialog(
|
||||
//: Title of progress window which is displayed when wallets are being restored.
|
||||
tr("Restore Wallet"),
|
||||
/*: Descriptive text of the restore wallets progress window which indicates to
|
||||
the user that wallets are currently being restored.*/
|
||||
tr("Restoring Wallet <b>%1</b>…").arg(GUIUtil::HtmlEscape(GUIUtil::WalletDisplayName(wallet_name))));
|
||||
|
||||
QTimer::singleShot(0, worker(), [this, path, wallet_name] {
|
||||
auto res{node().walletLoader().restoreWallet(path, wallet_name, m_warning_message, /*load_after_restore=*/false)};
|
||||
|
||||
if (!res) {
|
||||
m_error_message = util::ErrorString(res);
|
||||
QTimer::singleShot(0, this, &MigrateWalletActivity::finish);
|
||||
return;
|
||||
}
|
||||
QTimer::singleShot(0, this, [this, wallet_name] {
|
||||
do_migrate(wallet_name);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void MigrateWalletActivity::finish()
|
||||
{
|
||||
if (!m_error_message.empty()) {
|
||||
|
||||
@ -187,6 +187,7 @@ class MigrateWalletActivity : public WalletControllerActivity
|
||||
public:
|
||||
MigrateWalletActivity(WalletController* wallet_controller, QWidget* parent) : WalletControllerActivity(wallet_controller, parent) {}
|
||||
|
||||
void restore_and_migrate(const fs::path& path, const std::string& wallet_name);
|
||||
void migrate(const std::string& path);
|
||||
|
||||
Q_SIGNALS:
|
||||
@ -195,6 +196,7 @@ Q_SIGNALS:
|
||||
private:
|
||||
QString m_success_message;
|
||||
|
||||
void do_migrate(const std::string& name);
|
||||
void finish();
|
||||
};
|
||||
|
||||
|
||||
@ -597,16 +597,15 @@ public:
|
||||
return util::Error{error};
|
||||
}
|
||||
}
|
||||
util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) override
|
||||
util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings, bool load_after_restore) override
|
||||
{
|
||||
DatabaseStatus status;
|
||||
bilingual_str error;
|
||||
std::unique_ptr<Wallet> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))};
|
||||
if (wallet) {
|
||||
return wallet;
|
||||
} else {
|
||||
std::unique_ptr<Wallet> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings, load_after_restore))};
|
||||
if (!error.empty()) {
|
||||
return util::Error{error};
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
util::Result<WalletMigrationResult> migrateWallet(const std::string& name, const SecureString& passphrase) override
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user