Merge bitcoin-core/gui#953: Adds option to not load the wallet after migration

4cea59573c add release notes (Pol Espinasa)
492a715d78 gui: Adds option to not load the wallet after migration (Pol Espinasa)

Pull request description:

  Following https://github.com/bitcoin/bitcoin/pull/35266 this PR adds the option to not load the wallet after migrating to the GUI.

  It is only added for the `migrate` option, not for the `restore_and_migrate`. I guess if we are restoring the wallet we always want to load it.
  In any case, it's pretty straightforward to implement it there too.

  Inside the original migration pop-up box it appears a checkbox that allows the user to choose if want to load the wallet or not, it is checked by default:

  <img width="497" height="388" alt="imagen" src="https://github.com/user-attachments/assets/79c76f9b-9b06-4fcb-88fe-3b5db3eaf14f" />

  If yes, the wallet is loaded and shown, if not the wallet gets migrated and the GUI returns to it's state.

  The checkbox has a tooltip that informs when not loading a migrated wallet can be useful:
  <img width="503" height="494" alt="imagen" src="https://github.com/user-attachments/assets/3a3404ff-1fd3-44ef-8f9d-db526c9f032f" />

ACKs for top commit:
  achow101:
    ACK 4cea59573c
  pablomartin4btc:
    ACK 4cea59573c
  hebasto:
    ACK 4cea59573c, I have reviewed the code and it looks OK.

Tree-SHA512: 6256849ecca3888fe24866ed539b262be6275c6192d29d272e7ad1475943c2947c04a3fadaae94e1843b3fcfa43a1f84edb02365933bf954b8ba7d0ae53eda32
This commit is contained in:
Hennadii Stepanov
2026-07-29 19:41:43 +01:00
5 changed files with 25 additions and 10 deletions

5
doc/release-notes-953.md Normal file
View File

@@ -0,0 +1,5 @@
GUI Changes
---
The migrate wallet option now allows to disable wallet loading after migrating.
It is useful in case the node is pruned and the wallet was created before the pruned height.

View File

@@ -323,7 +323,7 @@ public:
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;
virtual util::Result<WalletMigrationResult> migrateWallet(const std::string& name, const SecureString& passphrase, bool load_wallet) = 0;
//! Returns true if wallet stores encryption keys
virtual bool isEncrypted(const std::string& wallet_name) = 0;

View File

@@ -23,6 +23,7 @@
#include <chrono>
#include <QApplication>
#include <QCheckBox>
#include <QMessageBox>
#include <QMetaObject>
#include <QMutexLocker>
@@ -439,7 +440,7 @@ void RestoreWalletActivity::finish()
Q_EMIT finished();
}
void MigrateWalletActivity::do_migrate(const std::string& name)
void MigrateWalletActivity::do_migrate(const std::string& name, bool load_wallet)
{
SecureString passphrase;
if (node().walletLoader().isEncrypted(name)) {
@@ -450,8 +451,8 @@ void MigrateWalletActivity::do_migrate(const std::string& name)
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)};
QTimer::singleShot(0, worker(), [this, name, passphrase, load_wallet] {
auto res{node().walletLoader().migrateWallet(name, passphrase, load_wallet)};
if (res) {
m_success_message = tr("The wallet '%1' was migrated successfully.").arg(GUIUtil::HtmlEscape(GUIUtil::WalletDisplayName(name)));
@@ -461,7 +462,12 @@ void MigrateWalletActivity::do_migrate(const std::string& name)
if (res->solvables_wallet_name) {
m_success_message += QChar(' ') + tr("Solvable but not watched scripts have been migrated to a new wallet named '%1'.").arg(GUIUtil::HtmlEscape(GUIUtil::WalletDisplayName(res->solvables_wallet_name.value())));
}
m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(res->wallet));
if (load_wallet) {
assert(res->wallet);
m_wallet_model = m_wallet_controller->getOrCreateWallet(std::move(res->wallet));
} else {
m_success_message += QChar(' ') + tr("The wallet was not loaded after migration. You can open it from the \"File > Open wallet\" menu.");
}
} else {
m_error_message = util::ErrorString(res);
}
@@ -482,11 +488,15 @@ void MigrateWalletActivity::migrate(const std::string& name)
"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."));
auto* load_wallet_checkbox = new QCheckBox(tr("Load wallet after migration"), &box);
load_wallet_checkbox->setToolTip(tr("If the node is pruned and the wallet was created before the pruned height, the migration process may fail trying to load the migrated wallet."));
load_wallet_checkbox->setChecked(true);
box.setCheckBox(load_wallet_checkbox);
box.setStandardButtons(QMessageBox::Yes|QMessageBox::Cancel);
box.setDefaultButton(QMessageBox::Yes);
if (box.exec() != QMessageBox::Yes) return;
do_migrate(name);
do_migrate(name, load_wallet_checkbox->isChecked());
}
void MigrateWalletActivity::restore_and_migrate(const fs::path& path, const std::string& wallet_name)
@@ -523,7 +533,7 @@ void MigrateWalletActivity::restore_and_migrate(const fs::path& path, const std:
return;
}
QTimer::singleShot(0, this, [this, wallet_name] {
do_migrate(wallet_name);
do_migrate(wallet_name, /*load_wallet=*/true);
});
});
}

View File

@@ -196,7 +196,7 @@ Q_SIGNALS:
private:
QString m_success_message;
void do_migrate(const std::string& name);
void do_migrate(const std::string& name, bool load_wallet);
void finish();
};

View File

@@ -601,9 +601,9 @@ public:
}
return wallet;
}
util::Result<WalletMigrationResult> migrateWallet(const std::string& name, const SecureString& passphrase) override
util::Result<WalletMigrationResult> migrateWallet(const std::string& name, const SecureString& passphrase, bool load_wallet) override
{
auto res = wallet::MigrateLegacyToDescriptor(name, passphrase, m_context);
auto res = wallet::MigrateLegacyToDescriptor(name, passphrase, m_context, load_wallet);
if (!res) return util::Error{util::ErrorString(res)};
WalletMigrationResult out{
.wallet = MakeWallet(m_context, res->wallet),