Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
501{502"desc": desc2,503"keypool": True,504"timestamp": "now",505}506])507assert_equal(res[0]["success"], True)508assert_equal(res[1]["success"], True)509# Before migrating, we can fetch addr1 from the keypool510assert_equal(watchonly1.getnewaddress(address_type="bech32"), addr1)512_, watchonly1 = self.migrate_and_get_rpc("watchonly1")513info = watchonly1.getwalletinfo()514assert_equal(info["descriptors"], True)515assert_equal(info["private_keys_enabled"], False)516self.assert_is_sqlite("watchonly1")517# After migrating, the "keypool" is empty518assert_raises_rpc_error(-4, "Error: This wallet has no available keys", watchonly1.getnewaddress)520self.log.info("Test migration of a watch-only empty wallet")521for idx, is_blank in enumerate([True, False], start=1):522wallet_name = f"watchonly_empty{idx}"523self.create_legacy_wallet(wallet_name, disable_private_keys=True, blank=is_blank)524_, watchonly_empty = self.migrate_and_get_rpc(wallet_name)525info = watchonly_empty.getwalletinfo()526assert_equal(info["private_keys_enabled"], False)527assert_equal(info["blank"], is_blank)529def test_pk_coinbases(self):530self.log.info("Test migration of a wallet using old pk() coinbases")531wallet = self.create_legacy_wallet("pkcb")533addr = wallet.getnewaddress()534addr_info = wallet.getaddressinfo(addr)535desc = descsum_create("pk(" + addr_info["pubkey"] + ")")537self.generatetodescriptor(self.master_node, 1, desc)539bals = wallet.getbalances()540bals["mine"]["nonmempool"] = Decimal('0.0')542_, wallet = self.migrate_and_get_rpc("pkcb")544assert_equal(bals, wallet.getbalances())546def test_encrypted(self):547self.log.info("Test migration of an encrypted wallet")548wallet = self.create_legacy_wallet("encrypted")549default = self.master_node.get_wallet_rpc(self.default_wallet_name)551wallet.encryptwallet("pass")552addr = wallet.getnewaddress()553txid = default.sendtoaddress(addr, 1)554self.generate(self.master_node, 1)555bals = wallet.getbalances()556bals["mine"]["nonmempool"] = Decimal('0.0')558# Use self.migrate_and_get_rpc to test this error to get everything copied over to the master node559assert_raises_rpc_error(-4, "Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect", self.migrate_and_get_rpc, "encrypted")561# Use the RPC directly on the master node for the rest of these checks562self.master_node.bumpmocktime(1) # Prevents filename duplication on wallet backups which is a problem on Windows563assert_raises_rpc_error(-4, "Error: Wallet decryption failed, the wallet passphrase was not provided or was incorrect", self.master_node.migratewallet, "encrypted", "badpass")565self.master_node.bumpmocktime(1) # Prevents filename duplication on wallet backups which is a problem on Windows566assert_raises_rpc_error(-4, "The passphrase contains a null character", self.master_node.migratewallet, "encrypted", "pass\0with\0null")568# Verify we can properly migrate the encrypted wallet569self.master_node.bumpmocktime(1) # Prevents filename duplication on wallet backups which is a problem on Windows570self.master_node.migratewallet("encrypted", passphrase="pass")571wallet = self.master_node.get_wallet_rpc("encrypted")573info = wallet.getwalletinfo()574assert_equal(info["descriptors"], True)575assert_equal(info["format"], "sqlite")576assert_equal(info["unlocked_until"], 0)577wallet.gettransaction(txid)579assert_equal(bals, wallet.getbalances())581def test_nonexistent(self):582self.log.info("Check migratewallet errors for nonexistent wallets")583default = self.master_node.get_wallet_rpc(self.default_wallet_name)584assert_raises_rpc_error(-8, "The RPC endpoint wallet and the wallet name parameter specify different wallets", default.migratewallet, "someotherwallet")585assert_raises_rpc_error(-8, "Either the RPC endpoint wallet or the wallet name parameter must be provided", self.master_node.migratewallet)586assert_raises_rpc_error(-4, "Error: Wallet does not exist", self.master_node.migratewallet, "notawallet")588def test_unloaded_by_path(self):589self.log.info("Test migration of a wallet that isn't loaded, specified by path")590wallet = self.create_legacy_wallet("notloaded2")591default = self.master_node.get_wallet_rpc(self.default_wallet_name)593addr = wallet.getnewaddress()594txid = default.sendtoaddress(addr, 1)595self.generate(self.master_node, 1)596bals = wallet.getbalances()597bals["mine"]["nonmempool"] = Decimal('0.0')599wallet.unloadwallet()601wallet_file_path = self.old_node.wallets_path / "notloaded2"602self.master_node.migratewallet(wallet_file_path)604# Because we gave the name by full path, the loaded wallet's name is that path too.605wallet = self.master_node.get_wallet_rpc(str(wallet_file_path))607info = wallet.getwalletinfo()608assert_equal(info["descriptors"], True)609assert_equal(info["format"], "sqlite")610wallet.gettransaction(txid)612assert_equal(bals, wallet.getbalances())614def test_wallet_with_path(self, wallet_path):615self.log.info("Test migrating a wallet with the following path/name: %s", wallet_path)616# the wallet data is actually inside of path/that/ends/617wallet = self.create_legacy_wallet(wallet_path)618default = self.master_node.get_wallet_rpc(self.default_wallet_name)620addr = wallet.getnewaddress()621txid = default.sendtoaddress(addr, 1)622self.generate(self.master_node, 1)623bals = wallet.getbalances()624bals["mine"]["nonmempool"] = Decimal('0.0')626_, wallet = self.migrate_and_get_rpc(wallet_path)628assert wallet.gettransaction(txid)630assert_equal(bals, wallet.getbalances())632def clear_default_wallet(self, backup_file):633# Test cleanup: Clear unnamed default wallet for subsequent tests634(self.old_node.wallets_path / "wallet.dat").unlink()635(self.master_node.wallets_path / "wallet.dat").unlink(missing_ok=True)636with suppress(FileNotFoundError):637(self.master_node.wallets_path / "default_wallet_watchonly" / "wallet.dat").unlink()638(self.master_node.wallets_path / "default_wallet_watchonly").rmdir()640(self.master_node.wallets_path / "default_wallet_solvables" / "wallet.dat").unlink()641(self.master_node.wallets_path / "default_wallet_solvables").rmdir()642backup_file.unlink()644def test_default_wallet(self):645self.log.info("Test migration of the wallet named as the empty string")646wallet = self.create_legacy_wallet("")648res, wallet = self.migrate_and_get_rpc("")649info = wallet.getwalletinfo()650assert_equal(info["descriptors"], True)651assert_equal(info["format"], "sqlite")653walletdir_list = wallet.listwalletdir()654assert {"name": info["walletname"]} in [{"name": w["name"]} for w in walletdir_list["wallets"]]656# Make sure the backup uses a non-empty filename657# migrate_and_get_rpc already checks for backup file existence658assert os.path.basename(res["backup_path"]).startswith("default_wallet")660wallet.unloadwallet()661self.clear_default_wallet(backup_file=Path(res["backup_path"]))663def test_default_wallet_watch_only(self):664self.log.info("Test unnamed (default) watch-only wallet migration")665master_wallet = self.master_node.get_wallet_rpc(self.default_wallet_name)666wallet = self.create_legacy_wallet("", blank=True)667wallet.importaddress(master_wallet.getnewaddress(address_type="legacy"))669res, wallet = self.migrate_and_get_rpc("")671info = wallet.getwalletinfo()672assert_equal(info["descriptors"], True)673assert_equal(info["format"], "sqlite")674assert_equal(info["private_keys_enabled"], False)675assert_equal(info["walletname"], "default_wallet_watchonly")676# Check the default wallet is not available anymore677assert not (self.master_node.wallets_path / "wallet.dat").exists()679wallet.unloadwallet()680self.clear_default_wallet(backup_file=Path(res["backup_path"]))682def test_migration_failure(self, wallet_name):683is_default = wallet_name == ""684wallet_pretty_name = "unnamed (default)" if is_default else f'"{wallet_name}"'685self.log.info(f"Test failure during migration of wallet named: {wallet_pretty_name}")686# Preface, set up legacy wallet and unload it687master_wallet = self.master_node.get_wallet_rpc(self.default_wallet_name)688wallet = self.create_legacy_wallet(wallet_name, blank=True)689wallet.importaddress(master_wallet.getnewaddress(address_type="legacy"))690wallet.unloadwallet()692if os.path.isabs(wallet_name):693old_path = master_path = Path(wallet_name)694else:695old_path = self.old_node.wallets_path / wallet_name696master_path = self.master_node.wallets_path / wallet_name697os.makedirs(master_path, exist_ok=True)698shutil.copyfile(old_path / "wallet.dat", master_path / "wallet.dat")700# This will be the watch-only directory the migration tries to create,701# we make migration fail by placing a wallet.dat file there.702wo_prefix = wallet_name or "default_wallet"703# wo_prefix might have path characters in it, this corresponds with704# DoMigration().705wo_dirname = f"{wo_prefix}_watchonly"706watch_only_dir = self.master_node.wallets_path / wo_dirname707os.mkdir(watch_only_dir)708shutil.copyfile(old_path / "wallet.dat", watch_only_dir / "wallet.dat")710mocked_time = int(time.time())711self.master_node.setmocktime(mocked_time)712assert_raises_rpc_error(-4, "Failed to create database", self.master_node.migratewallet, wallet_name)713self.master_node.setmocktime(0)715# Verify the /wallets/ path exists.716assert self.master_node.wallets_path.exists()718# Verify both wallet paths exist.719assert Path(old_path / "wallet.dat").exists()720assert Path(master_path / "wallet.dat").exists()722backup_prefix = "default_wallet" if is_default else os.path.basename(os.path.abspath(master_path))723backup_path = self.master_node.wallets_path / f"{backup_prefix}_{mocked_time}.legacy.bak"724assert backup_path.exists()726self.assert_is_bdb(wallet_name)728# Cleanup729if is_default:730self.clear_default_wallet(backup_path)731else:732backup_path.unlink()733Path(watch_only_dir / "wallet.dat").unlink()734Path(watch_only_dir).rmdir()735Path(master_path / "wallet.dat").unlink()736Path(old_path / "wallet.dat").unlink(missing_ok=True)738def test_direct_file(self):739self.log.info("Test migration of a wallet that is not in a wallet directory")740wallet = self.create_legacy_wallet("plainfile")741wallet.unloadwallet()743shutil.copyfile(744self.old_node.wallets_path / "plainfile" / "wallet.dat" ,745self.master_node.wallets_path / "plainfile"746)747assert (self.master_node.wallets_path / "plainfile").is_file()749mocked_time = int(time.time())750self.master_node.setmocktime(mocked_time)
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.