From 1d4662441feed1b143695134f001070000f37dbe Mon Sep 17 00:00:00 2001 From: furszy Date: Fri, 26 Dec 2025 20:23:02 -0500 Subject: [PATCH] test: add coverage for unnamed wallet migration failure Verifies that a failed migration of the unnamed (default) wallet does not erase the main /wallets/ directory, and also that the backup file exists. Github-Pull: bitcoin/bitcoin#34156 Rebased-From: 36093bde63286e19821a9e62cdff1712b6245dc7 --- test/functional/wallet_migration.py | 38 +++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/test/functional/wallet_migration.py b/test/functional/wallet_migration.py index 48ad8e4f2a1..9cf2020803b 100755 --- a/test/functional/wallet_migration.py +++ b/test/functional/wallet_migration.py @@ -4,6 +4,7 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test Migrating a wallet from legacy to descriptor.""" +import os import random import shutil import struct @@ -558,6 +559,42 @@ class WalletMigrationTest(BitcoinTestFramework): assert_equal(str(backup_path), res['backup_path']) assert {"name": backup_filename} not in walletdir_list["wallets"] + self.nodes[0].unloadwallet("") + + def test_default_wallet_failure(self): + self.log.info("Test failure during unnamed (default) wallet migration") + master_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name) + wallet = self.create_legacy_wallet("", blank=True) + wallet.importaddress(master_wallet.getnewaddress(address_type="legacy")) + + # Create wallet directory with the watch-only name and a wallet file. + # Because the wallet dir exists, this will cause migration to fail. + watch_only_dir = self.nodes[0].wallets_path / "_watchonly" + os.mkdir(watch_only_dir) + shutil.copyfile(self.nodes[0].wallets_path / "wallet.dat", watch_only_dir / "wallet.dat") + + mocked_time = int(time.time()) + self.nodes[0].setmocktime(mocked_time) + assert_raises_rpc_error(-4, "Wallet file creation failed", self.nodes[0].migratewallet, "") + self.nodes[0].setmocktime(0) + + # Verify the /wallets/ path exists + assert self.nodes[0].wallets_path.exists() + # Check backup file exists. Because the wallet has no name, the backup is prefixed with 'default_wallet' + backup_path = self.nodes[0].wallets_path / f"default_wallet_{mocked_time}.legacy.bak" + assert backup_path.exists() + # Verify the original unnamed wallet was restored + assert (self.nodes[0].wallets_path / "wallet.dat").exists() + # And verify it is still a BDB wallet + with open(self.nodes[0].wallets_path / "wallet.dat", "rb") as f: + data = f.read(16) + _, _, magic = struct.unpack("QII", data) + assert_equal(magic, BTREE_MAGIC) + + # Test cleanup: clear default wallet for next test + wallet.unloadwallet() + os.remove(self.nodes[0].wallets_path / "wallet.dat") + def test_direct_file(self): self.log.info("Test migration of a wallet that is not in a wallet directory") wallet = self.create_legacy_wallet("plainfile") @@ -1025,6 +1062,7 @@ class WalletMigrationTest(BitcoinTestFramework): self.test_encrypted() self.test_unloaded() self.test_unloaded_by_path() + self.test_default_wallet_failure() self.test_default_wallet() self.test_direct_file() self.test_addressbook()