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.
501success=False,502error_code=-4,503error_message='Cannot import private keys to a wallet with private keys disabled')505self.log.info("Should not import a descriptor with hardened derivations when private keys are disabled")506self.test_importdesc({"desc": descsum_create("wpkh(" + xpub + "/1h/*)"),507"timestamp": "now",508"range": 1},509success=False,510error_code=-4,511error_message='Cannot expand descriptor. Probably because of hardened derivations without private keys provided')513for address in addresses:514test_address(w1,515address,516ismine=False,517solvable=False)519self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": -1},520success=False, error_code=-8, error_message='End of range is too high')522self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [-1, 10]},523success=False, error_code=-8, error_message='Range should be greater or equal than 0')525self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]},526success=False, error_code=-8, error_message='End of range is too high')528self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [2, 1]},529success=False, error_code=-8, error_message='Range specified as [begin,end] must not have begin after end')531self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now", "range": [0, 1000001]},532success=False, error_code=-8, error_message='Range is too large')534self.log.info("Verify we can only extend descriptor's range")535range_request = {"desc": descsum_create(desc), "timestamp": "now", "range": [5, 10], 'active': True}536self.test_importdesc(range_request, wallet=wpriv, success=True)537assert_equal(wpriv.getwalletinfo()['keypoolsize'], 6)538self.test_importdesc({**range_request, "range": [0, 10]}, wallet=wpriv, success=True)539assert_equal(wpriv.getwalletinfo()['keypoolsize'], 11)540self.test_importdesc({**range_request, "range": [0, 20]}, wallet=wpriv, success=True)541assert_equal(wpriv.getwalletinfo()['keypoolsize'], 21)542# Can keep range the same543self.test_importdesc({**range_request, "range": [0, 20]}, wallet=wpriv, success=True)544assert_equal(wpriv.getwalletinfo()['keypoolsize'], 21)546self.test_importdesc({**range_request, "range": [5, 10]}, wallet=wpriv, success=False,547error_code=-4, error_message=f"Could not add descriptor '{range_request['desc']}': new range must include current range = [0,20]")548self.test_importdesc({**range_request, "range": [0, 10]}, wallet=wpriv, success=False,549error_code=-4, error_message=f"Could not add descriptor '{range_request['desc']}': new range must include current range = [0,20]")550self.test_importdesc({**range_request, "range": [5, 20]}, wallet=wpriv, success=False,551error_code=-4, error_message=f"Could not add descriptor '{range_request['desc']}': new range must include current range = [0,20]")552assert_equal(wpriv.getwalletinfo()['keypoolsize'], 21)554self.log.info("Check we can change descriptor internal flag")555self.test_importdesc({**range_request, "range": [0, 20], "internal": True}, wallet=wpriv, success=True)556assert_equal(wpriv.getwalletinfo()['keypoolsize'], 0)557assert_raises_rpc_error(-4, 'This wallet has no available keys', wpriv.getnewaddress, '', 'p2sh-segwit')558assert_equal(wpriv.getwalletinfo()['keypoolsize_hd_internal'], 21)559wpriv.getrawchangeaddress('p2sh-segwit')561self.test_importdesc({**range_request, "range": [0, 20], "internal": False}, wallet=wpriv, success=True)562assert_equal(wpriv.getwalletinfo()['keypoolsize'], 21)563wpriv.getnewaddress('', 'p2sh-segwit')564assert_equal(wpriv.getwalletinfo()['keypoolsize_hd_internal'], 0)565assert_raises_rpc_error(-4, 'This wallet has no available keys', wpriv.getrawchangeaddress, 'p2sh-segwit')567# Make sure ranged imports import keys in order568w1 = self.nodes[1].get_wallet_rpc('w1')569self.log.info('Key ranges should be imported in order')570xpub = "tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY"571addresses = [572'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv', # m/0'/0'/0573'bcrt1q8vprchan07gzagd5e6v9wd7azyucksq2xc76k8', # m/0'/0'/1574'bcrt1qtuqdtha7zmqgcrr26n2rqxztv5y8rafjp9lulu', # m/0'/0'/2575'bcrt1qau64272ymawq26t90md6an0ps99qkrse58m640', # m/0'/0'/3576'bcrt1qsg97266hrh6cpmutqen8s4s962aryy77jp0fg0', # m/0'/0'/4577]579self.test_importdesc({'desc': descsum_create('wpkh([80002067/0h/0h]' + xpub + '/*)'),580'active': True,581'range' : [0, 2],582'timestamp': 'now'583},584success=True)585self.test_importdesc({'desc': descsum_create('sh(wpkh([abcdef12/0h/0h]' + xpub + '/*))'),586'active': True,587'range' : [0, 2],588'timestamp': 'now'589},590success=True)591self.test_importdesc({'desc': descsum_create('pkh([12345678/0h/0h]' + xpub + '/*)'),592'active': True,593'range' : [0, 2],594'timestamp': 'now'595},596success=True)598assert_equal(w1.getwalletinfo()['keypoolsize'], 5 * 3)599for i, expected_addr in enumerate(addresses):600received_addr = w1.getnewaddress('', 'bech32')601assert_raises_rpc_error(-4, 'This wallet has no available keys', w1.getrawchangeaddress, 'bech32')602assert_equal(received_addr, expected_addr)603bech32_addr_info = w1.getaddressinfo(received_addr)604assert_equal(bech32_addr_info['desc'][:23], 'wpkh([80002067/0h/0h/{}]'.format(i))606shwpkh_addr = w1.getnewaddress('', 'p2sh-segwit')607shwpkh_addr_info = w1.getaddressinfo(shwpkh_addr)608assert_equal(shwpkh_addr_info['desc'][:26], 'sh(wpkh([abcdef12/0h/0h/{}]'.format(i))610pkh_addr = w1.getnewaddress('', 'legacy')611pkh_addr_info = w1.getaddressinfo(pkh_addr)612assert_equal(pkh_addr_info['desc'][:22], 'pkh([12345678/0h/0h/{}]'.format(i))614assert_equal(w1.getwalletinfo()['keypoolsize'], 4 * 3) # After retrieving a key, we don't refill the keypool again, so it's one less for each address type615w1.keypoolrefill()616assert_equal(w1.getwalletinfo()['keypoolsize'], 5 * 3)618self.log.info("Check we can change next_index")619# go back and forth with next_index620for i in [4, 0, 2, 1, 3]:621# Sometimes use h, sometimes use ' for hardened indicator622hard = "'" if i & 2 == 0 else "h"623self.test_importdesc({'desc': descsum_create(f'wpkh([80002067/0{hard}/0{hard}]' + xpub + '/*)'),624'active': True,625'range': [0, 9],626'next_index': i,627'timestamp': 'now'628},629success=True)630assert_equal(w1.getnewaddress('', 'bech32'), addresses[i])632self.log.info("Equivalent Miniscript descriptors should not be duplicated")633self.nodes[1].createwallet(wallet_name="wminiscript", disable_private_keys=True, blank=True)634wminiscript = self.nodes[1].get_wallet_rpc("wminiscript")635miniscript_request = {636'active': True,637'range': [0, 9],638'timestamp': 'now',639}640self.test_importdesc({641**miniscript_request,642'desc': descsum_create(f"wsh(and_v(v:pk([80002067/0h/0h]{xpub}/*),older(1)))"),643}, success=True, wallet=wminiscript)644self.test_importdesc({645**miniscript_request,646'desc': descsum_create(f"wsh(and_v(v:pk([80002067/0'/0']{xpub}/*),older(1)))"),647}, success=True, wallet=wminiscript)648assert_equal(len(wminiscript.listdescriptors()["descriptors"]), 1)650# Check active=False default651self.log.info('Check imported descriptors are not active by default')652self.test_importdesc({'desc': descsum_create('pkh([12345678/1h]' + xpub + '/*)'),653'range' : [0, 2],654'timestamp': 'now',655'internal': True656},657success=True)658assert_raises_rpc_error(-4, 'This wallet has no available keys', w1.getrawchangeaddress, 'legacy')660self.log.info('Check can activate inactive descriptor')661self.test_importdesc({'desc': descsum_create('pkh([12345678]' + xpub + '/*)'),662'range': [0, 5],663'active': True,664'timestamp': 'now',665'internal': True666},667success=True)668address = w1.getrawchangeaddress('legacy')669assert_equal(address, "mpA2Wh9dvZT7yfELq1UnrUmAoc5qCkMetg")671self.log.info('Check can deactivate active descriptor')672self.test_importdesc({'desc': descsum_create('pkh([12345678]' + xpub + '/*)'),673'range': [0, 5],674'active': False,675'timestamp': 'now',676'internal': True677},678success=True)679assert_raises_rpc_error(-4, 'This wallet has no available keys', w1.getrawchangeaddress, 'legacy')681self.log.info('Verify activation state is persistent')682w1.unloadwallet()683self.nodes[1].loadwallet('w1')684assert_raises_rpc_error(-4, 'This wallet has no available keys', w1.getrawchangeaddress, 'legacy')686# # Test importing a descriptor containing a WIF private key687wif_priv = "cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh"688address = "2MuhcG52uHPknxDgmGPsV18jSHFBnnRgjPg"689desc = "sh(wpkh(" + wif_priv + "))"690self.log.info("Should import a descriptor with a WIF private key as spendable")691self.test_importdesc({"desc": descsum_create(desc),692"timestamp": "now"},693success=True,694wallet=wpriv)696self.log.info('Test can import same descriptor with private key twice')697self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now"}, success=True, wallet=wpriv)699test_address(wpriv,700address,701solvable=True,702ismine=True)703txid = w0.sendtoaddress(address, 49.99995540)704self.generatetoaddress(self.nodes[0], 6, w0.getnewaddress())705tx = wpriv.createrawtransaction([{"txid": txid, "vout": 0}], {w0.getnewaddress(): 49.999})706signed_tx = wpriv.signrawtransactionwithwallet(tx)707w1.sendrawtransaction(signed_tx['hex'])709# Make sure that we can use import and use multisig as addresses710self.log.info('Test that multisigs can be imported, signed for, and getnewaddress\'d')711self.nodes[1].createwallet(wallet_name="wmulti_priv", disable_private_keys=False, blank=True)712wmulti_priv = self.nodes[1].get_wallet_rpc("wmulti_priv")713assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 0)715derivation_path = "84h/0h/0h"716change_derivation_path = "84h/1h/0h"717extended_key_1 = ExtendedPrivateKey.generate()718xprv1 = extended_key_1.to_string()719xprv1_fingerprint = extended_key_1._fingerprint().hex()720acc_xpub1_key = extended_key_1.derive_path(derivation_path).pubkey()721acc_xpub1 = acc_xpub1_key.to_string()722chg_xpub1_key = extended_key_1.derive_path(change_derivation_path).pubkey()723chg_xpub1 = chg_xpub1_key.to_string()725extended_key_2 = ExtendedPrivateKey.generate()726xprv2 = extended_key_2.to_string()727xprv2_fingerprint = extended_key_2._fingerprint().hex()728acc_xprv2 = extended_key_2.derive_path(derivation_path).to_string()729acc_xpub2_key = extended_key_2.derive_path(derivation_path).pubkey()730acc_xpub2 = acc_xpub2_key.to_string()731chg_xpub2_key = extended_key_2.derive_path(change_derivation_path).pubkey()732chg_xpub2 = chg_xpub2_key.to_string()734extended_key_3 = ExtendedPrivateKey.generate()735xprv3 = extended_key_3.to_string()736xprv3_fingerprint = extended_key_3._fingerprint().hex()737acc_xpub3_key = extended_key_3.derive_path(derivation_path).pubkey()738acc_xpub3 = acc_xpub3_key.to_string()739chg_xpub3_key = extended_key_3.derive_path(change_derivation_path).pubkey()740chg_xpub3 = chg_xpub3_key.to_string()742self.test_musig_private_key_warnings(xprv1, acc_xprv2, acc_xpub2, derivation_path)744self.test_importdesc({"desc": descsum_create(f"wsh(multi(2,{xprv1}/{derivation_path}/*,{xprv2}/{derivation_path}/*,{xprv3}/{derivation_path}/*))"),745"active": True,746"range": 1000,747"next_index": 0,748"timestamp": "now"},749success=True,750wallet=wmulti_priv)
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.