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.
1#!/usr/bin/env python32# Copyright (c) 2018-present The Bitcoin Core developers3# Distributed under the MIT software license, see the accompanying4# file COPYING or http://www.opensource.org/licenses/mit-license.php.5"""Test createwallet arguments.6"""7import os8import stat10from test_framework.descriptors import descsum_create11from test_framework.extendedkey import ExtendedPrivateKey12from test_framework.test_framework import BitcoinTestFramework13from test_framework.util import (14assert_equal,15assert_raises_rpc_error,16is_dir_writable,17wallet_importprivkey,18)19from test_framework.wallet_util import generate_keypair, WalletUnlock22EMPTY_PASSPHRASE_MSG = "Empty string given as passphrase, wallet will not be encrypted."25class CreateWalletTest(BitcoinTestFramework):26def set_test_params(self):27self.num_nodes = 129def skip_test_if_missing_module(self):30self.skip_if_no_wallet()32def test_bad_dir_permissions(self, node):33self.log.info("Test wallet creation failure due to non-writable directory")34wallet_name = "bad_permissions"35dir_path = node.wallets_path / wallet_name36dir_path.mkdir(parents=True)37original_dir_perms = dir_path.stat().st_mode38os.chmod(dir_path, original_dir_perms & ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH))39if is_dir_writable(dir_path):40self.log.warning("Skipping non-writable directory test: unable to enforce read-only permissions")41else:42# Run actual test43assert_raises_rpc_error(-4, f"SQLiteDatabase: Failed to open database in directory '{str(dir_path)}': directory is not writable", node.createwallet, wallet_name=wallet_name)44# Reset directory permissions for cleanup45dir_path.chmod(original_dir_perms)48def run_test(self):49node = self.nodes[0]51self.test_bad_dir_permissions(node)53self.log.info("Run createwallet with invalid parameters.")54# Run createwallet with invalid parameters. This must not prevent a new wallet with the same name from being created with the correct parameters.55assert_raises_rpc_error(-4, "Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.",56self.nodes[0].createwallet, wallet_name='w0', disable_private_keys=True, passphrase="passphrase")57assert_raises_rpc_error(-8, "Wallet name cannot be empty", self.nodes[0].createwallet, "")59self.nodes[0].createwallet(wallet_name='w0')60w0 = node.get_wallet_rpc('w0')61address1 = w0.getnewaddress()63self.log.info("Test disableprivatekeys creation.")64self.nodes[0].createwallet(wallet_name='w1', disable_private_keys=True)65w1 = node.get_wallet_rpc('w1')66assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w1.getnewaddress)67assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w1.getrawchangeaddress)68import_res = w1.importdescriptors([{"desc": w0.getaddressinfo(address1)['desc'], "timestamp": "now"}])69assert_equal(import_res[0]["success"], True)70assert_equal(sorted(w1.getwalletinfo()["flags"]), sorted(["last_hardened_xpub_cached", "descriptor_wallet", "disable_private_keys"]))72self.log.info('Test that private keys cannot be imported')73privkey, pubkey = generate_keypair(wif=True)74result = w1.importdescriptors([{'desc': descsum_create('wpkh(' + privkey + ')'), 'timestamp': 'now'}])75assert not result[0]['success']76assert 'warnings' not in result[0]77assert_equal(result[0]['error']['code'], -4)78assert_equal(result[0]['error']['message'], 'Cannot import private keys to a wallet with private keys disabled')80self.log.info("Test blank creation with private keys disabled.")81self.nodes[0].createwallet(wallet_name='w2', disable_private_keys=True, blank=True)82w2 = node.get_wallet_rpc('w2')83assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w2.getnewaddress)84assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w2.getrawchangeaddress)85import_res = w2.importdescriptors([{"desc": w0.getaddressinfo(address1)['desc'], "timestamp": "now"}])86assert_equal(import_res[0]["success"], True)88self.log.info("Test blank creation with private keys enabled.")89self.nodes[0].createwallet(wallet_name='w3', disable_private_keys=False, blank=True)90w3 = node.get_wallet_rpc('w3')91assert_equal(w3.getwalletinfo()['keypoolsize'], 0)92assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress)93assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getrawchangeaddress)94# Import private key95wallet_importprivkey(w3, generate_keypair(wif=True)[0], "now")96# Imported private keys are currently ignored by the keypool97assert_equal(w3.getwalletinfo()['keypoolsize'], 0)98assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress)99# Set the seed100w3.importdescriptors([{101'desc': descsum_create(f'wpkh({ExtendedPrivateKey.generate().to_string()}/0h/*)'),102'timestamp': 'now',103'active': True104},105{106'desc': descsum_create(f'wpkh({ExtendedPrivateKey.generate().to_string()}/1h/*)'),107'timestamp': 'now',108'active': True,109'internal': True110}])111assert_equal(w3.getwalletinfo()['keypoolsize'], 1)112w3.getnewaddress()113w3.getrawchangeaddress()115self.log.info("Test blank creation with privkeys enabled and then encryption")116self.nodes[0].createwallet(wallet_name='w4', disable_private_keys=False, blank=True)117w4 = node.get_wallet_rpc('w4')118assert_equal(w4.getwalletinfo()['keypoolsize'], 0)119assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getnewaddress)120assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getrawchangeaddress)121# Encrypt the wallet. Nothing should change about the keypool122w4.encryptwallet('pass')123assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getnewaddress)124assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getrawchangeaddress)125with WalletUnlock(w4, "pass"):126# Now set a seed and it should work. Wallet should also be encrypted127w4.importdescriptors([{128'desc': descsum_create(f'wpkh({ExtendedPrivateKey.generate().to_string()}/0h/*)'),129'timestamp': 'now',130'active': True131},132{133'desc': descsum_create(f'wpkh({ExtendedPrivateKey.generate().to_string()}/1h/*)'),134'timestamp': 'now',135'active': True,136'internal': True137}])138w4.getnewaddress()139w4.getrawchangeaddress()141self.log.info("Test blank creation with privkeys disabled and then encryption")142self.nodes[0].createwallet(wallet_name='w5', disable_private_keys=True, blank=True)143w5 = node.get_wallet_rpc('w5')144assert_equal(w5.getwalletinfo()['keypoolsize'], 0)145assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress)146assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress)147# Encrypt the wallet148assert_raises_rpc_error(-16, "Error: wallet does not contain private keys, nothing to encrypt.", w5.encryptwallet, 'pass')149assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress)150assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress)152self.log.info('New blank and encrypted wallets can be created')153self.nodes[0].createwallet(wallet_name='wblank', disable_private_keys=False, blank=True, passphrase='thisisapassphrase')154wblank = node.get_wallet_rpc('wblank')155assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", wblank.signmessage, "needanargument", "test")156with WalletUnlock(wblank, "thisisapassphrase"):157assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getnewaddress)158assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getrawchangeaddress)160self.log.info('Test creating a new encrypted wallet.')161# Born encrypted wallet is created (has keys)162self.nodes[0].createwallet(wallet_name='w6', disable_private_keys=False, blank=False, passphrase='thisisapassphrase')163w6 = node.get_wallet_rpc('w6')164assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", w6.signmessage, "needanargument", "test")165with WalletUnlock(w6, "thisisapassphrase"):166w6.signmessage(w6.getnewaddress('', 'legacy'), "test")167w6.keypoolrefill(1)168# There should only be 1 key for legacy, 3 for descriptors169walletinfo = w6.getwalletinfo()170keys = 4171assert_equal(walletinfo['keypoolsize'], keys)172assert_equal(walletinfo['keypoolsize_hd_internal'], keys)173# Allow empty passphrase, but there should be a warning174resp = self.nodes[0].createwallet(wallet_name='w7', disable_private_keys=False, blank=False, passphrase='')175assert_equal(resp["warnings"], [EMPTY_PASSPHRASE_MSG])177w7 = node.get_wallet_rpc('w7')178assert_raises_rpc_error(-15, 'Error: running with an unencrypted wallet, but walletpassphrase was called.', w7.walletpassphrase, '', 60)180self.log.info('Test making a wallet with avoid reuse flag')181self.nodes[0].createwallet('w8', False, False, '', True) # Use positional arguments to check for bug where avoid_reuse could not be set for wallets without needing them to be encrypted182w8 = node.get_wallet_rpc('w8')183assert_raises_rpc_error(-15, 'Error: running with an unencrypted wallet, but walletpassphrase was called.', w7.walletpassphrase, '', 60)184assert_equal(w8.getwalletinfo()["avoid_reuse"], True)186self.log.info('Using a passphrase with private keys disabled returns error')187assert_raises_rpc_error(-4, 'Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.', self.nodes[0].createwallet, wallet_name='w9', disable_private_keys=True, passphrase='thisisapassphrase')189self.log.info("Test that legacy wallets cannot be created")190assert_raises_rpc_error(-4, 'descriptors argument must be set to "true"; it is no longer possible to create a legacy wallet.', self.nodes[0].createwallet, wallet_name="legacy", descriptors=False)192self.log.info("Check that the version number is being logged correctly")194# Craft the expected version message.195client_version = node.getnetworkinfo()["version"]196version_message = f"Last client version = {client_version}"198# Should not be logged when creating.199with node.assert_debug_log(expected_msgs=[], unexpected_msgs=[version_message]):200node.createwallet("version_check")201node.unloadwallet("version_check")202# Should be logged when loading.203with node.assert_debug_log(expected_msgs=[version_message]):204node.loadwallet("version_check")207if __name__ == '__main__':208CreateWalletTest(__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.