Skip to content

Commit 5a1473e

Browse files
committed
Merge bitcoin/bitcoin#28976: wallet: Fix migration of blank wallets
c11c404 tests: Test migration of blank wallets (Andrew Chow) 563b2a6 wallet: Better error message when missing LegacySPKM during migration (Andrew Chow) b1d2c77 wallet: Check for descriptors flag before migration (Andrew Chow) 8c127ff wallet: Skip key and script migration for blank wallets (Andrew Chow) Pull request description: Blank wallets (wallets without any keys are scripts) are being detected as already being descriptor wallets even though they are not. This is because the check for whether a wallet is already a descriptor wallet uses the presence of a `LegacyScriptPubKeyMan` which is only setup when keys or scripts are found. This PR resolves this issue by checking for the descriptor wallet flag instead and subsequently skipping the keys and scripts part of migration for blank wallets. Fixes the issue mentioned in bitcoin/bitcoin#28868 (comment) ACKs for top commit: furszy: reACK c11c404. CI failure is unrelated. ryanofsky: Code review ACK c11c404 Tree-SHA512: 2466fdf1542eb8489c841253191f85dc88365493f0bb3395b67dee3e43709a9993c68b9d7623657b54b779adbe68fc81962d60efef4802c5d461f154167af7f4
2 parents 3c13f5d + c11c404 commit 5a1473e

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

src/wallet/wallet.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3864,7 +3864,11 @@ std::optional<MigrationData> CWallet::GetDescriptorsForLegacy(bilingual_str& err
38643864
AssertLockHeld(cs_wallet);
38653865

38663866
LegacyScriptPubKeyMan* legacy_spkm = GetLegacyScriptPubKeyMan();
3867-
assert(legacy_spkm);
3867+
if (!Assume(legacy_spkm)) {
3868+
// This shouldn't happen
3869+
error = Untranslated(STR_INTERNAL_BUG("Error: Legacy wallet data missing"));
3870+
return std::nullopt;
3871+
}
38683872

38693873
std::optional<MigrationData> res = legacy_spkm->MigrateToDescriptor();
38703874
if (res == std::nullopt) {
@@ -3879,8 +3883,9 @@ bool CWallet::ApplyMigrationData(MigrationData& data, bilingual_str& error)
38793883
AssertLockHeld(cs_wallet);
38803884

38813885
LegacyScriptPubKeyMan* legacy_spkm = GetLegacyScriptPubKeyMan();
3882-
if (!legacy_spkm) {
3883-
error = _("Error: This wallet is already a descriptor wallet");
3886+
if (!Assume(legacy_spkm)) {
3887+
// This shouldn't happen
3888+
error = Untranslated(STR_INTERNAL_BUG("Error: Legacy wallet data missing"));
38843889
return false;
38853890
}
38863891

@@ -4215,7 +4220,7 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle
42154220
}
42164221

42174222
// Before anything else, check if there is something to migrate.
4218-
if (!local_wallet->GetLegacyScriptPubKeyMan()) {
4223+
if (local_wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
42194224
return util::Error{_("Error: This wallet is already a descriptor wallet")};
42204225
}
42214226

@@ -4248,8 +4253,11 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle
42484253
// First change to using SQLite
42494254
if (!local_wallet->MigrateToSQLite(error)) return util::Error{error};
42504255

4251-
// Do the migration, and cleanup if it fails
4252-
success = DoMigration(*local_wallet, context, error, res);
4256+
// Do the migration of keys and scripts for non-blank wallets, and cleanup if it fails
4257+
success = local_wallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET);
4258+
if (!success) {
4259+
success = DoMigration(*local_wallet, context, error, res);
4260+
}
42534261
}
42544262

42554263
// In case of reloading failure, we need to remember the wallet dirs to remove

test/functional/wallet_migration.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,12 @@ def assert_is_sqlite(self, wallet_name):
5252
assert_equal(file_magic, b'SQLite format 3\x00')
5353
assert_equal(self.nodes[0].get_wallet_rpc(wallet_name).getwalletinfo()["format"], "sqlite")
5454

55-
def create_legacy_wallet(self, wallet_name, disable_private_keys=False):
56-
self.nodes[0].createwallet(wallet_name=wallet_name, descriptors=False, disable_private_keys=disable_private_keys)
55+
def create_legacy_wallet(self, wallet_name, **kwargs):
56+
self.nodes[0].createwallet(wallet_name=wallet_name, descriptors=False, **kwargs)
5757
wallet = self.nodes[0].get_wallet_rpc(wallet_name)
5858
info = wallet.getwalletinfo()
5959
assert_equal(info["descriptors"], False)
6060
assert_equal(info["format"], "bdb")
61-
assert_equal(info["private_keys_enabled"], not disable_private_keys)
6261
return wallet
6362

6463
def assert_addr_info_equal(self, addr_info, addr_info_old):
@@ -876,6 +875,13 @@ def test_failed_migration_cleanup(self):
876875
_, _, magic = struct.unpack("QII", data)
877876
assert_equal(magic, BTREE_MAGIC)
878877

878+
def test_blank(self):
879+
self.log.info("Test that a blank wallet is migrated")
880+
wallet = self.create_legacy_wallet("blank", blank=True)
881+
assert_equal(wallet.getwalletinfo()["blank"], True)
882+
wallet.migratewallet()
883+
assert_equal(wallet.getwalletinfo()["blank"], True)
884+
879885

880886
def test_avoidreuse(self):
881887
self.log.info("Test that avoidreuse persists after migration")
@@ -987,6 +993,7 @@ def run_test(self):
987993
self.test_failed_migration_cleanup()
988994
self.test_avoidreuse()
989995
self.test_preserve_tx_extra_info()
996+
self.test_blank()
990997

991998
if __name__ == '__main__':
992999
WalletMigrationTest().main()

0 commit comments

Comments
 (0)