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.
251w5 = get_wallet(node, "w5")252assert_equal(w5.getbalances()["mine"]["immature"], 50)254competing_wallet_dir = os.path.join(self.options.tmpdir, 'competing_walletdir')255os.mkdir(competing_wallet_dir)256self.restart_node(0, ['-nowallet', '-walletdir=' + competing_wallet_dir])257node.createwallet(self.default_wallet_name)258exp_stderr = f"Error: SQLiteDatabase: Unable to obtain an exclusive lock on the database, is it being used by another instance of {self.config['environment']['CLIENT_NAME']}?"259self.nodes[1].assert_start_raises_init_error(['-walletdir=' + competing_wallet_dir], exp_stderr, match=ErrorMatch.PARTIAL_REGEX)261def test_balances_and_fees(self, node, wallet_names, in_wallet_dir):262self.log.info("Test balances and fees")263self.restart_node(0)264for wallet_name in wallet_names:265node.loadwallet(wallet_name)267assert_equal(sorted(map(lambda w: w['name'], node.listwalletdir()['wallets'])), sorted(in_wallet_dir))269wallets = [get_wallet(node, w) for w in wallet_names]270wallet_bad = get_wallet(node, "bad")272# check wallet names and balances273self.generatetoaddress(node, nblocks=1, address=wallets[0].getnewaddress(), sync_fun=self.no_op)274for wallet_name, wallet in zip(wallet_names, wallets):275info = wallet.getwalletinfo()276assert_equal(wallet.getbalances()["mine"]["immature"], 50 if wallet is wallets[0] else 0)277assert_equal(info['walletname'], wallet_name)279# accessing invalid wallet fails280assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", wallet_bad.getwalletinfo)282# accessing wallet RPC without using wallet endpoint fails283assert_raises_rpc_error(-19, "Multiple wallets are loaded. Please select which wallet", node.getwalletinfo)285w1, w2, w3, w4, *_ = wallets286self.generatetoaddress(node, nblocks=COINBASE_MATURITY + 1, address=w1.getnewaddress(), sync_fun=self.no_op)287assert_equal(w1.getbalance(), 100)288assert_equal(w2.getbalance(), 0)289assert_equal(w3.getbalance(), 0)290assert_equal(w4.getbalance(), 0)292w1.sendtoaddress(w2.getnewaddress(), 1)293w1.sendtoaddress(w3.getnewaddress(), 2)294w1.sendtoaddress(w4.getnewaddress(), 3)295self.generatetoaddress(node, nblocks=1, address=w1.getnewaddress(), sync_fun=self.no_op)296assert_equal(w2.getbalance(), 1)297assert_equal(w3.getbalance(), 2)298assert_equal(w4.getbalance(), 3)300batch = w1.batch([w1.getblockchaininfo.get_request(), w1.getwalletinfo.get_request()])301assert_equal(batch[0]["result"]["chain"], self.chain)302assert_equal(batch[1]["result"]["walletname"], "w1")304def test_loading(self, node, wallet_names):305self.log.info("Test dynamic wallet loading")307self.restart_node(0, ['-nowallet'])308assert_equal(node.listwallets(), [])309assert_raises_rpc_error(-18, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)", node.getwalletinfo)311self.log.info("Load first wallet")312loadwallet_name = node.loadwallet(wallet_names[0])313assert_equal(loadwallet_name['name'], wallet_names[0])314assert_equal(node.listwallets(), wallet_names[0:1])315node.getwalletinfo()316w1 = get_wallet(node, wallet_names[0])317w1.getwalletinfo()319self.log.info("Load second wallet")320loadwallet_name = node.loadwallet(wallet_names[1])321assert_equal(loadwallet_name['name'], wallet_names[1])322assert_equal(node.listwallets(), wallet_names[0:2])323assert_raises_rpc_error(-19, "Multiple wallets are loaded. Please select which wallet", node.getwalletinfo)324w2 = get_wallet(node, wallet_names[1])325w2.getwalletinfo()327self.log.info("Concurrent wallet loading")328threads = []329for _ in range(3):330n = node.create_new_rpc_connection()331t = Thread(target=test_load_unload, args=(n, wallet_names[2]))332t.start()333threads.append(t)334for t in threads:335t.join()336global got_loading_error337assert_equal(got_loading_error, True)339self.log.info("Load remaining wallets")340for wallet_name in wallet_names[2:]:341loadwallet_name = node.loadwallet(wallet_name)342assert_equal(loadwallet_name['name'], wallet_name)344assert_equal(set(node.listwallets()), set(wallet_names))346# Fail to load if wallet doesn't exist347path = wallet_dir(node, "wallets")348assert_raises_rpc_error(-18, "Wallet file verification failed. Failed to load database path '{}'. Path does not exist.".format(path), node.loadwallet, 'wallets')350# Fail to load duplicate wallets351assert_raises_rpc_error(-35, "Wallet \"w1\" is already loaded.", node.loadwallet, wallet_names[0])352# Fail to load if wallet file is a symlink353if self.check_symlinks:354assert_raises_rpc_error(-4, "Wallet file verification failed. Invalid -wallet path 'w8_symlink'", node.loadwallet, 'w8_symlink')356# Fail to load if a directory is specified that doesn't contain a wallet357os.mkdir(wallet_dir(node, 'empty_wallet_dir'))358path = wallet_dir(node, "empty_wallet_dir")359assert_raises_rpc_error(-18, "Wallet file verification failed. Failed to load database path '{}'. Data is not in recognized format.".format(path), node.loadwallet, 'empty_wallet_dir')361return w1, w2363def test_creation(self, node, in_wallet_dir):364self.log.info("Test dynamic wallet creation")366# should raise rpc error if wallet path can't be created367err_code = -4368assert_raises_rpc_error(err_code, "Wallet file verification failed. ", node.createwallet, "w8/bad")370# Fail to create a wallet if it already exists.371path = wallet_dir(node, "w2")372assert_raises_rpc_error(-4, "Failed to create database path '{}'. Database already exists.".format(path), node.createwallet, 'w2')374# Successfully create a wallet with a new name375loadwallet_name = node.createwallet('w9')376in_wallet_dir.append('w9')377assert_equal(loadwallet_name['name'], 'w9')378w9 = get_wallet(node, 'w9')379assert_equal(w9.getwalletinfo()['walletname'], 'w9')381assert 'w9' in node.listwallets()383# Successfully create a wallet using a full path384new_wallet_dir = os.path.join(self.options.tmpdir, 'new_walletdir')385new_wallet_name = os.path.join(new_wallet_dir, 'w10')386loadwallet_name = node.createwallet(new_wallet_name)387assert_equal(loadwallet_name['name'], new_wallet_name)388w10 = get_wallet(node, new_wallet_name)389assert_equal(w10.getwalletinfo()['walletname'], new_wallet_name)391assert new_wallet_name in node.listwallets()393def test_unloading(self, node, in_wallet_dir, w1, w2):394self.log.info("Test dynamic wallet unloading")396# Test `unloadwallet` errors397assert_raises_rpc_error(-8, "Either the RPC endpoint wallet or the wallet name parameter must be provided", node.unloadwallet)398assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", node.unloadwallet, "dummy")399assert_raises_rpc_error(-18, "Requested wallet does not exist or is not loaded", get_wallet(node, "dummy").unloadwallet)400assert_raises_rpc_error(-8, "The RPC endpoint wallet and the wallet name parameter specify different wallets", w1.unloadwallet, "w2"),402# Successfully unload the specified wallet name403node.unloadwallet("w1")404assert 'w1' not in node.listwallets()406# Unload w1 again, this time providing the wallet name twice407node.loadwallet("w1")408assert 'w1' in node.listwallets()409w1.unloadwallet("w1")410assert 'w1' not in node.listwallets()412# Successfully unload the wallet referenced by the request endpoint413# Also ensure unload works during walletpassphrase timeout414w2.encryptwallet('test')415w2.walletpassphrase('test', 1)416w2.unloadwallet()417ensure_for(duration=1.1, f=lambda: 'w2' not in node.listwallets())419# Successfully unload all wallets420for wallet_name in node.listwallets():421node.unloadwallet(wallet_name)422assert_equal(node.listwallets(), [])423assert_raises_rpc_error(-18, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)", node.getwalletinfo)425# Successfully load a previously unloaded wallet426node.loadwallet('w1')427assert_equal(node.listwallets(), ['w1'])428assert_equal(w1.getwalletinfo()['walletname'], 'w1')430assert_equal(sorted(map(lambda w: w['name'], node.listwalletdir()['wallets'])), sorted(in_wallet_dir))432def test_backup_and_restore(self, node, wallet_names, empty_wallet, empty_created_wallet):433self.log.info("Test wallet backup and restore")434self.restart_node(0, ['-nowallet'])435for wallet_name in wallet_names:436node.loadwallet(wallet_name)437for wallet_name in wallet_names:438rpc = get_wallet(node, wallet_name)439addr = rpc.getnewaddress()440backup = os.path.join(self.options.tmpdir, 'backup.dat')441if os.path.exists(backup):442os.unlink(backup)443rpc.backupwallet(backup)444node.unloadwallet(wallet_name)445shutil.copyfile(empty_created_wallet if wallet_name == self.default_wallet_name else empty_wallet, self.wallet_file(node, wallet_name))446node.loadwallet(wallet_name)447assert_equal(rpc.getaddressinfo(addr)['ismine'], False)448node.unloadwallet(wallet_name)449shutil.copyfile(backup, self.wallet_file(node, wallet_name))450node.loadwallet(wallet_name)451assert_equal(rpc.getaddressinfo(addr)['ismine'], True)453def test_lock_file_closed(self, node):454self.log.info("Test wallet lock file is closed")455self.start_node(1)456wallet = os.path.join(self.options.tmpdir, 'my_wallet')457node.createwallet(wallet)458assert_raises_rpc_error(-4, "Unable to obtain an exclusive lock", self.nodes[1].loadwallet, wallet)459node.unloadwallet(wallet)460self.nodes[1].loadwallet(wallet)462def test_invalid_wallet_names(self):463self.log.info("Test weird paths are not allowed as wallet names")464NON_NORMALIZED = ["bad/./path", "bad/../path", "/bad/./path", "/bad/../path", "../", "./", "./wallet", "../wallets/../wallets/wallet"]465for name in NON_NORMALIZED:466assert_raises_rpc_error(-4, "Wallet name given as a path must be normalized", self.nodes[0].createwallet, name)468INVALID_RELPATH = ["../wallets/wallet", "..", "."]469for name in INVALID_RELPATH:470assert_raises_rpc_error(-4, "Wallet name given as a relative path cannot begin with ./ or ../", self.nodes[0].createwallet, name)472INVALID_ROOT = ["/"]473if platform.system() == "Windows":474INVALID_ROOT.extend(["C:\\", "C:"])475for name in INVALID_ROOT:476assert_raises_rpc_error(-4, "Wallet name cannot be the root path", self.nodes[0].createwallet, name)478if __name__ == '__main__':479MultiWalletTest(__file__).main()
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.