Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate legacy wallets that are not loaded #824

Merged
merged 5 commits into from
Aug 14, 2024

Conversation

achow101
Copy link
Member

Currently the Migrate Wallet menu item can only be used to migrate the currently loaded wallet. This is not suitable for the future when legacy wallets can no longer be loaded at all, but should still be able to be migrated. This PR changes that menu item into a menu list like Open Wallet and lets users migrate any legacy wallet in their wallet directory regardless of the wallets loaded.

One issue I ran into was dealing with encrypted wallets. Ideally, we would detect whether a wallet is encrypted, and prompt the user for their passphrase at that time. However, that's actually difficult to do in the GUI since migration will unload the wallet if it was already loaded, and reload it without connecting it to any signals or interfaces. Only then can it detect whether a wallet is encrypted, but then there is no WalletModel or even an interfaces::Wallet that the GUI could use to unlock it via a callback.

To deal with this, I've opted to just add a button to the migration dialog box that has the user enter their passphrase first, along with instructional text to use that button if their wallet was encrypted. If the user enters the wrong passphrase or clicked the other button that does not prompt for the passphrase, migration will fail with a message indicating that the passphrase was incorrect.

@DrahtBot
Copy link
Contributor

DrahtBot commented Jun 10, 2024

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK hebasto, furszy
Stale ACK pablomartin4btc

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #753 (Add new "address type" column to the "receiving tab" address book page by pablomartin4btc)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@achow101 achow101 added this to the 28.0 milestone Jun 10, 2024
@achow101 achow101 removed this from the 28.0 milestone Jun 10, 2024
@hebasto hebasto changed the title gui: Migrate legacy wallets that are not loaded Migrate legacy wallets that are not loaded Jun 11, 2024
@hebasto
Copy link
Member

hebasto commented Jun 11, 2024

Concept ACK.

@luke-jr
Copy link
Member

luke-jr commented Jun 12, 2024

To deal with this, I've opted to just add a button to the migration dialog box that has the user enter their passphrase first, along with instructional text to use that button if their wallet was encrypted.

If we're preemptively making UX changes just to avoid changing UX in the future, it seems like we shouldn't take shortcuts like this... :/

@achow101
Copy link
Member Author

To deal with this, I've opted to just add a button to the migration dialog box that has the user enter their passphrase first, along with instructional text to use that button if their wallet was encrypted.

If we're preemptively making UX changes just to avoid changing UX in the future, it seems like we shouldn't take shortcuts like this... :/

We already do this in the RPC too, for exactly the same reason.

Comment on lines -69 to -70
void migrateWallet(WalletModel* wallet_model, QWidget* parent = nullptr);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently, this code has been dead since introducing in #738.

Comment on lines 465 to 472
// Menu items remove single &. Single & are shown when && is in
// the string, but only the first occurrence. So replace only
// the first & with &&.
name.replace(name.indexOf(QChar('&')), 1, QString("&&"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#828 can relevant to this code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since #828 has been merged, please keep in mind this update...

Suggested change
// Menu items remove single &. Single & are shown when && is in
// the string, but only the first occurrence. So replace only
// the first & with &&.
name.replace(name.indexOf(QChar('&')), 1, QString("&&"));
// Single & are shown when && is in the string. So replace & with &&.
name.replace(QChar('&'), QString("&&"));

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed during rebase.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed during rebase.

It still needs to be fixed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, missed one, fixed.

src/qt/askpassphrasedialog.h Outdated Show resolved Hide resolved
src/interfaces/wallet.h Outdated Show resolved Hide resolved
@hebasto
Copy link
Member

hebasto commented Jul 14, 2024

This PR changes that menu item into a menu list like Open Wallet and lets users migrate any legacy wallet in their wallet directory regardless of the wallets loaded.

Tested d45ac03. The "Migrate Wallet" menu item is still disabled when no wallet is loaded.

@hebasto
Copy link
Member

hebasto commented Jul 29, 2024

Please rebase.

Copy link
Contributor

@pablomartin4btc pablomartin4btc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK d45ac03

Created a couple of legacy wallets (encrypted and not) to begin with.

edit: running ./configure with: --with-bdb.

Using bitcoind (./src/bitcoind -regtest -deprecatedrpc=create_bdb ) and bitcoin-cli (./src/bitcoin-cli -regtest createwallet legacyWallet false false "" false false ) or directly on the rpc-console (createwallet legacyWalletEnc false false "passphrase" false false) in bitcoin-qt (./src/qt/bitcoin-qt -regtest -deprecatedrpc=create_bdb).

{
  "name": "legacyWalletEnc",
  "warnings": [
    "Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future."
  ]
}
{
  "name": "legacyWallet",
  "warnings": [
    "Empty string given as passphrase, wallet will not be encrypted.",
    "Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future."
  ]
}
The menu item "Migrate Wallet" is shown when there are already wallets loaded.

image

But "Migrate Wallet" is disabled when there are no wallets loaded as @hebasto mentioned above.

image

  • I think that should be solved by removing the migration action from BitcoinGUI::setWalletActionsEnabled (the migration action has the same behaviour as the restore action which is not there).
"Migrate Wallet" is shown when there are no wallets available at all.

image

Tested migration of encrypted wallet with and without providing the passphrase, working both cases.

image

image

Every migration failure on a particular wallet still creates a backup file. Do we want this?

image

@DrahtBot DrahtBot requested a review from hebasto July 31, 2024 21:42
@achow101 achow101 added this to the 28.0 milestone Aug 8, 2024
@achow101
Copy link
Member Author

achow101 commented Aug 8, 2024

Tested d45ac03. The "Migrate Wallet" menu item is still disabled when no wallet is loaded.

Should be fixed now.

"Migrate Wallet" is shown when there are no wallets available at all.

I think that's ok.

@pablomartin4btc
Copy link
Contributor

"Migrate Wallet" is shown when there are no wallets available at all.

I think that's ok.

Yeah, it was just an observation (mainly to compare when the menu is disabled), thanks!

Copy link
Contributor

@pablomartin4btc pablomartin4btc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested d45ac03. The "Migrate Wallet" menu item is still disabled when no wallet is loaded.

Should be fixed now.

re-ACK bcf47b9

Copy link
Member

@furszy furszy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few comments. Will continue reviewing.

src/qt/bitcoingui.cpp Outdated Show resolved Hide resolved
Comment on lines +476 to +477
connect(action, &QAction::triggered, [this, wallet_name] {
auto activity = new MigrateWalletActivity(m_wallet_controller, this);
connect(activity, &MigrateWalletActivity::migrated, this, &BitcoinGUI::setCurrentWallet);
activity->migrate(wallet_name);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Compilation error: error: 'wallet_name' in capture list does not name a variable.

It seems the lambda expression cannot capture the structured binding. A local reference of the variable fixes it.

Same happens on the m_open_wallet_menu action lambda with the "path" variable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What compiler? I'm not seeing this error, and it seems neither did CI.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What compiler? I'm not seeing this error, and it seems neither did CI.

clang 14.0.3 (clang-1403.0.22.14.1).

src/qt/walletcontroller.cpp Outdated Show resolved Hide resolved
Copy link
Member

@furszy furszy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worked further on your 8d0b5c1 to eliminate the need for the extra 'Yes, encrypted' button in the migration dialog, which I found quite unfriendly. Could replace it directly for furszy/bitcoin-core@e8d147e. It detects the wallet encryption status automatically regardless of its loaded/unloaded state.

Other than this, code is looking good.

achow101 and others added 4 commits August 13, 2024 11:25
Instead of having the code for the wallet display name being copy and
pasted, use a GUIUtil function to get that for us.
To prepare for migrating wallets that are not loaded, when migration
occurs in the GUI, it should not rely on a WalletModel existing.

Co-authored-by: furszy <[email protected]>
@achow101
Copy link
Member Author

Could replace it directly for furszy/bitcoin-core@e8d147e. It detects the wallet encryption status automatically regardless of its loaded/unloaded state.

Cherry picked.

Also fixed test failure.

Copy link
Member

@furszy furszy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK fd087d4

Copy link
Member

@hebasto hebasto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost ACK fd087d4.

Comment on lines 465 to 472
// Menu items remove single &. Single & are shown when && is in
// the string, but only the first occurrence. So replace only
// the first & with &&.
name.replace(name.indexOf(QChar('&')), 1, QString("&&"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed during rebase.

It still needs to be fixed.

Once legacy wallets can no longer be loaded, we need to be able to
migrate them without loading. Thus we should use a menu that lists the
wallets in the wallet directory instead of an action which migrates the
currently loaded wallet.
Copy link
Member

@hebasto hebasto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 8f2522d.

@DrahtBot DrahtBot requested a review from furszy August 14, 2024 09:11
@hebasto
Copy link
Member

hebasto commented Aug 14, 2024

cc @furszy

Copy link
Member

@furszy furszy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 8f2522d

@hebasto hebasto merged commit e682e7d into bitcoin-core:master Aug 14, 2024
16 checks passed
@hebasto hebasto added the Wallet label Aug 14, 2024
});
}
if (m_migrate_wallet_menu->isEmpty()) {
QAction* action = m_migrate_wallet_menu->addAction(tr("No wallets available"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe a more descriptive text would be good?
something like No wallets that need to be migrated

for people who don't know about the migration and why/what it is.
seeing No wallets available while they have wallet(s) might seem wrong/confusing.

sry for commenting post-merge

Copy link
Contributor

@pablomartin4btc pablomartin4btc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

post-merge tACK 8f2522d

Checked changes proposed by @furszy.

Perhaps the PR's description needs to be updated (or a note added) since the previous extra button to enter the passphrase was removed (isEncrypted is in place). Nice solution, less prone to errors too.

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants