Skip to content

Commit

Permalink
gui: Use wallet name for wallet migration rather than WalletModel
Browse files Browse the repository at this point in the history
To prepare for migrating wallets that are not loaded, when migration
occurs in the GUI, it should not rely on a WalletModel existing.
  • Loading branch information
achow101 committed Jul 11, 2024
1 parent 3eb67dc commit f1ea58f
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 22 deletions.
8 changes: 7 additions & 1 deletion src/qt/askpassphrasedialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureStri
ui->passEdit1->hide();
setWindowTitle(tr("Encrypt wallet"));
break;
case UnlockMigration:
case Unlock: // Ask passphrase
ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
ui->passLabel2->hide();
Expand Down Expand Up @@ -80,7 +81,7 @@ void AskPassphraseDialog::setModel(WalletModel *_model)
void AskPassphraseDialog::accept()
{
SecureString oldpass, newpass1, newpass2;
if (!model && mode != Encrypt)
if (!model && mode != Encrypt && mode != UnlockMigration)
return;
oldpass.reserve(MAX_PASSPHRASE_SIZE);
newpass1.reserve(MAX_PASSPHRASE_SIZE);
Expand Down Expand Up @@ -181,6 +182,10 @@ void AskPassphraseDialog::accept()
QMessageBox::critical(this, tr("Wallet unlock failed"), e.what());
}
break;
case UnlockMigration:
Assume(m_passphrase_out)->assign(oldpass);
QDialog::accept();
break;
case ChangePass:
if(newpass1 == newpass2)
{
Expand Down Expand Up @@ -224,6 +229,7 @@ void AskPassphraseDialog::textChanged()
case Encrypt: // New passphrase x2
acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
break;
case UnlockMigration:
case Unlock: // Old passphrase x1
acceptable = !ui->passEdit1->text().isEmpty();
break;
Expand Down
1 change: 1 addition & 0 deletions src/qt/askpassphrasedialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class AskPassphraseDialog : public QDialog
Encrypt, /**< Ask passphrase twice and encrypt */
Unlock, /**< Ask passphrase and unlock */
ChangePass, /**< Ask old passphrase + new passphrase twice */
UnlockMigration, // Ask passphrase for unlocking during migration
};

explicit AskPassphraseDialog(Mode mode, QWidget *parent, SecureString* passphrase_out = nullptr);
Expand Down
2 changes: 1 addition & 1 deletion src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ void BitcoinGUI::createActions()
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());
activity->migrate(walletFrame->currentWalletModel()->wallet().getWalletName());
});
connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::setPrivacy);
connect(m_mask_values_action, &QAction::toggled, this, &BitcoinGUI::enableHistoryAction);
Expand Down
46 changes: 29 additions & 17 deletions src/qt/walletcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,15 @@ WalletModel* WalletController::getOrCreateWallet(std::unique_ptr<interfaces::Wal
return wallet_model;
}

WalletModel* WalletController::getWallet(const std::string& name)
{
auto it = std::find_if(m_wallets.begin(), m_wallets.end(),
[&name](WalletModel* model) {
return name == model->wallet().getWalletName();
});
return it == m_wallets.end() ? nullptr : *it;
}

void WalletController::removeAndDeleteWallet(WalletModel* wallet_model)
{
// Unregister wallet model.
Expand Down Expand Up @@ -436,47 +445,50 @@ void RestoreWalletActivity::finish()
Q_EMIT finished();
}

void MigrateWalletActivity::migrate(WalletModel* wallet_model)
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(wallet_model->getDisplayName())));
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;
"an incorrect migration, the backup can be restored with the \"Restore Wallet\" functionality.\n\n"
"If your wallet is encrypted, please provide the passphrase now as by choosing \"Yes, encrypted\"."));
QPushButton* yes_enc_button = box.addButton(tr("Yes, encrypted"), QMessageBox::YesRole);
QPushButton* yes_button = box.addButton(QMessageBox::Yes);
QPushButton* cancel_button = box.addButton(QMessageBox::Cancel);
box.setDefaultButton(yes_button);
box.exec();
if (!box.clickedButton() || box.clickedButton() == (QAbstractButton*)cancel_button) 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();
if (box.clickedButton() == (QAbstractButton*)yes_enc_button) {
// Get the passphrase for the wallet
AskPassphraseDialog dlg(AskPassphraseDialog::UnlockMigration, m_parent_widget, &passphrase);
if (dlg.exec() == QDialog::Rejected) return;
}

// 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);
if (WalletModel* wallet = m_wallet_controller->getWallet(name)) {
m_wallet_controller->removeAndDeleteWallet(wallet);
};

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()));
m_success_message = tr("The wallet '%1' was migrated successfully.").arg(GUIUtil::HtmlEscape(GUIUtil::WalletDisplayName(res->wallet->getWalletName())));
if (res->watchonly_wallet_name) {
m_success_message += QChar(' ') + tr("Watchonly scripts have been migrated to a new wallet named '%1'.").arg(GUIUtil::HtmlEscape(res->watchonly_wallet_name.value()));
m_success_message += QChar(' ') + tr("Watchonly scripts have been migrated to a new wallet named '%1'.").arg(GUIUtil::HtmlEscape(GUIUtil::WalletDisplayName(res->watchonly_wallet_name.value())));
}
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(res->solvables_wallet_name.value()));
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));
} else {
Expand Down
5 changes: 2 additions & 3 deletions src/qt/walletcontroller.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class WalletController : public QObject
~WalletController();

WalletModel* getOrCreateWallet(std::unique_ptr<interfaces::Wallet> wallet);
WalletModel* getWallet(const std::string& name);

//! Returns all wallet names in the wallet dir mapped to whether the wallet
//! is loaded.
Expand All @@ -66,8 +67,6 @@ class WalletController : public QObject
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);
Expand Down Expand Up @@ -186,7 +185,7 @@ class MigrateWalletActivity : public WalletControllerActivity
public:
MigrateWalletActivity(WalletController* wallet_controller, QWidget* parent) : WalletControllerActivity(wallet_controller, parent) {}

void migrate(WalletModel* wallet_model);
void migrate(const std::string& path);

Q_SIGNALS:
void migrated(WalletModel* wallet_model);
Expand Down

0 comments on commit f1ea58f

Please sign in to comment.