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.
751self.test_importdesc({"desc": descsum_create(f"wsh(multi(2,{xprv1}/{change_derivation_path}/*,{xprv2}/{change_derivation_path}/*,{xprv3}/{change_derivation_path}/*))"),752"active": True,753"internal" : True,754"range": 1000,755"next_index": 0,756"timestamp": "now"},757success=True,758wallet=wmulti_priv)760assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1001) # Range end (1000) is inclusive, so 1001 addresses generated762addr = wmulti_priv.getnewaddress('', 'bech32') # uses receive 0763expected_addr = script_to_p2wsh(keys_to_multisig_script([k.derive_path("m/0").pubkey.get_bytes() for k in [acc_xpub1_key, acc_xpub2_key, acc_xpub3_key]], k=2))764assert_equal(addr, expected_addr) # Derived at m/84'/0'/0'/0766change_addr = wmulti_priv.getrawchangeaddress('bech32') # uses change 0767expected_change_addr = script_to_p2wsh(keys_to_multisig_script([k.derive_path("m/0").pubkey.get_bytes() for k in [chg_xpub1_key, chg_xpub2_key, chg_xpub3_key]], k=2))768assert_equal(change_addr, expected_change_addr) # Derived at m/84'/1'/0'/0769assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1000)771txid = w0.sendtoaddress(addr, 10)772self.generate(self.nodes[0], 6)773send_txid = wmulti_priv.sendtoaddress(w0.getnewaddress(), 8) # uses change 1774decoded = wmulti_priv.gettransaction(txid=send_txid, verbose=True)['decoded']775assert_equal(len(decoded['vin'][0]['txinwitness']), 4)776self.sync_all()778self.nodes[1].createwallet(wallet_name="wmulti_pub", disable_private_keys=True, blank=True)779wmulti_pub = self.nodes[1].get_wallet_rpc("wmulti_pub")780assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 0)782self.test_importdesc({"desc": descsum_create(f"wsh(multi(2,[{xprv1_fingerprint}/{derivation_path}]{acc_xpub1}/*,[{xprv2_fingerprint}/{derivation_path}]{acc_xpub2}/*,[{xprv3_fingerprint}/{derivation_path}]{acc_xpub3}/*))"),783"active": True,784"range": 1000,785"next_index": 0,786"timestamp": "now"},787success=True,788wallet=wmulti_pub)789self.test_importdesc({"desc": descsum_create(f"wsh(multi(2,[{xprv1_fingerprint}/{change_derivation_path}]{chg_xpub1}/*,[{xprv2_fingerprint}/{change_derivation_path}]{chg_xpub2}/*,[{xprv3_fingerprint}/{change_derivation_path}]{chg_xpub3}/*))"),790"active": True,791"internal" : True,792"range": 1000,793"next_index": 0,794"timestamp": "now"},795success=True,796wallet=wmulti_pub)798assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 1000) # The first one was already consumed by previous import and is detected as used799addr = wmulti_pub.getnewaddress('', 'bech32') # uses receive 1800expected_addr = script_to_p2wsh(keys_to_multisig_script([k.derive_path("m/1").pubkey.get_bytes() for k in [acc_xpub1_key, acc_xpub2_key, acc_xpub3_key]], k=2))801assert_equal(addr, expected_addr) # Derived at m/84'/0'/0'/1802assert_equal(wmulti_pub.getaddressinfo(addr)["desc"].count(f"{derivation_path}/1"), 3) # Derived at m/84h/0h/0h/1 for all three keys803change_addr = wmulti_pub.getrawchangeaddress('bech32') # uses change 2804expected_change_addr = script_to_p2wsh(keys_to_multisig_script([k.derive_path("m/2").pubkey.get_bytes() for k in [chg_xpub1_key, chg_xpub2_key, chg_xpub3_key]], k=2))805assert_equal(change_addr, expected_change_addr) # Derived at m/84'/1'/0'/2806assert_equal(wmulti_pub.getaddressinfo(change_addr)["desc"].count(f"{change_derivation_path}/2"), 3) # Derived at m/84h/1h/0h/1 for all three keys807assert send_txid in self.nodes[0].getrawmempool(True)808assert send_txid in (x['txid'] for x in wmulti_pub.listunspent(0))809assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 999)811# generate some utxos for next tests812utxo = self.create_outpoints(w0, outputs=[{addr: 10}])[0]814addr2 = wmulti_pub.getnewaddress('', 'bech32')815utxo2 = self.create_outpoints(w0, outputs=[{addr2: 10}])[0]817self.generate(self.nodes[0], 6)818assert_equal(wmulti_pub.getbalance(), wmulti_priv.getbalance())820# Make sure that descriptor wallets containing multiple xpubs in a single descriptor load correctly821wmulti_pub.unloadwallet()822self.nodes[1].loadwallet('wmulti_pub')824self.log.info("Multisig with distributed keys")825self.nodes[1].createwallet(wallet_name="wmulti_priv1")826wmulti_priv1 = self.nodes[1].get_wallet_rpc("wmulti_priv1")827res = wmulti_priv1.importdescriptors([828{829"desc": descsum_create(f"wsh(multi(2,{xprv1}/{derivation_path}/*,[{xprv2_fingerprint}/{derivation_path}]{acc_xpub2}/*,[{xprv3_fingerprint}/{derivation_path}]{acc_xpub3}/*))"),830"active": True,831"range": 1000,832"next_index": 0,833"timestamp": "now"834},835{836"desc": descsum_create(f"wsh(multi(2,{xprv1}/{change_derivation_path}/*,[{xprv2_fingerprint}/{change_derivation_path}]{chg_xpub2}/*,[{xprv3_fingerprint}/{change_derivation_path}]{chg_xpub3}/*))"),837"active": True,838"internal" : True,839"range": 1000,840"next_index": 0,841"timestamp": "now"842}])843assert_equal(res[0]['success'], True)844assert_equal(res[0]['warnings'][0], MISSING_KEYS_WARNING)845assert_equal(res[1]['success'], True)846assert_equal(res[1]['warnings'][0], MISSING_KEYS_WARNING)848self.nodes[1].createwallet(wallet_name='wmulti_priv2', blank=True)849wmulti_priv2 = self.nodes[1].get_wallet_rpc('wmulti_priv2')850res = wmulti_priv2.importdescriptors([851{852"desc": descsum_create(f"wsh(multi(2,[{xprv1_fingerprint}/{derivation_path}]{acc_xpub1}/*,{xprv2}/{derivation_path}/*,[{xprv3_fingerprint}/{derivation_path}]{acc_xpub3}/*))"),853"active": True,854"range": 1000,855"next_index": 0,856"timestamp": "now"857},858{859"desc": descsum_create(f"wsh(multi(2,[{xprv1_fingerprint}/{change_derivation_path}]{chg_xpub1}/*,{xprv2}/{change_derivation_path}/*,[{xprv3_fingerprint}/{change_derivation_path}]{chg_xpub3}/*))"),860"active": True,861"internal" : True,862"range": 1000,863"next_index": 0,864"timestamp": "now"865}])866assert_equal(res[0]['success'], True)867assert_equal(res[0]['warnings'][0], MISSING_KEYS_WARNING)868assert_equal(res[1]['success'], True)869assert_equal(res[1]['warnings'][0], MISSING_KEYS_WARNING)871rawtx = self.nodes[1].createrawtransaction([utxo], {w0.getnewaddress(): 9.999})872tx_signed_1 = wmulti_priv1.signrawtransactionwithwallet(rawtx)873assert_equal(tx_signed_1['complete'], False)874tx_signed_2 = wmulti_priv2.signrawtransactionwithwallet(tx_signed_1['hex'])875assert_equal(tx_signed_2['complete'], True)876self.nodes[1].sendrawtransaction(tx_signed_2['hex'])878self.log.info("We can create and use a huge multisig under P2WSH")879self.nodes[1].createwallet(wallet_name='wmulti_priv_big', blank=True)880wmulti_priv_big = self.nodes[1].get_wallet_rpc('wmulti_priv_big')881xprv = ExtendedPrivateKey.generate().to_string()882xkey = f"{xprv}/*"883xkey_int = f"{xprv}/1/*"884res = wmulti_priv_big.importdescriptors([885{886"desc": descsum_create(f"wsh(sortedmulti(20,{(xkey + ',') * 19}{xkey}))"),887"active": True,888"range": 1000,889"next_index": 0,890"timestamp": "now"891},892{893"desc": descsum_create(f"wsh(sortedmulti(20,{(xkey_int + ',') * 19}{xkey_int}))"),894"active": True,895"internal": True,896"range": 1000,897"next_index": 0,898"timestamp": "now"899}])900assert_equal(res[0]['success'], True)901assert_equal(res[1]['success'], True)903addr = wmulti_priv_big.getnewaddress()904w0.sendtoaddress(addr, 10)905self.generate(self.nodes[0], 1)906# It is standard and would relay.907txid = wmulti_priv_big.sendtoaddress(w0.getnewaddress(), 9.999)908decoded = wmulti_priv_big.gettransaction(txid=txid, verbose=True)['decoded']909# 20 sigs + dummy + witness script910assert_equal(len(decoded['vin'][0]['txinwitness']), 22)913self.log.info("Under P2SH, multisig are standard with up to 15 "914"compressed keys")915self.nodes[1].createwallet(wallet_name='multi_priv_big_legacy',916blank=True)917multi_priv_big = self.nodes[1].get_wallet_rpc('multi_priv_big_legacy')918res = multi_priv_big.importdescriptors([919{920"desc": descsum_create(f"sh(multi(15,{(xkey + ',') * 14}{xkey}))"),921"active": True,922"range": 1000,923"next_index": 0,924"timestamp": "now"925},926{927"desc": descsum_create(f"sh(multi(15,{(xkey_int + ',') * 14}{xkey_int}))"),928"active": True,929"internal": True,930"range": 1000,931"next_index": 0,932"timestamp": "now"933}])934assert_equal(res[0]['success'], True)935assert_equal(res[1]['success'], True)937addr = multi_priv_big.getnewaddress("", "legacy")938w0.sendtoaddress(addr, 10)939self.generate(self.nodes[0], 6)940# It is standard and would relay.941txid = multi_priv_big.sendtoaddress(w0.getnewaddress(), 10, "", "", True)942decoded = multi_priv_big.gettransaction(txid=txid, verbose=True)['decoded']944self.log.info("Amending multisig with new private keys")945self.nodes[1].createwallet(wallet_name="wmulti_priv3")946wmulti_priv3 = self.nodes[1].get_wallet_rpc("wmulti_priv3")947res = wmulti_priv3.importdescriptors([948{949"desc": descsum_create(f"wsh(multi(2,{xprv1}/{derivation_path}/*,[{xprv2_fingerprint}/{derivation_path}]{acc_xpub2}/*,[{xprv3_fingerprint}/{derivation_path}]{acc_xpub3}/*))"),950"active": True,951"range": 1000,952"next_index": 0,953"timestamp": "now"954}])955assert_equal(res[0]['success'], True)956res = wmulti_priv3.importdescriptors([957{958"desc": descsum_create(f"wsh(multi(2,{xprv1}/{derivation_path}/*,[{xprv2_fingerprint}/{derivation_path}]{acc_xprv2}/*,[{xprv3_fingerprint}/{derivation_path}]{acc_xpub3}/*))"),959"active": True,960"range": 1000,961"next_index": 0,962"timestamp": "now"963}])964assert_equal(res[0]['success'], True)966rawtx = self.nodes[1].createrawtransaction([utxo2], {w0.getnewaddress(): 9.999})967tx = wmulti_priv3.signrawtransactionwithwallet(rawtx)968assert_equal(tx['complete'], True)969self.nodes[1].sendrawtransaction(tx['hex'])971self.log.info("Combo descriptors cannot be active")972self.test_importdesc({"desc": descsum_create(f"combo({ExtendedPrivateKey.generate().pubkey().to_string()}/*)"),973"active": True,974"range": 1,975"timestamp": "now"},976success=False,977error_code=-4,978error_message="Combo descriptors cannot be set to active")980self.log.info("Descriptors with no type cannot be active")981self.test_importdesc({"desc": descsum_create(f"pk({ExtendedPrivateKey.generate().pubkey().to_string()}/*)"),982"active": True,983"range": 1,984"timestamp": "now"},985success=True,986warnings=["Unknown output type, cannot set descriptor to active."])988self.log.info("Test importing a descriptor to an encrypted wallet")990descriptor = {"desc": descsum_create("pkh(" + xpriv + "/1h/*h)"),991"timestamp": "now",992"active": True,993"range": [0,4000],994"next_index": 4000}996self.nodes[0].createwallet("temp_wallet", blank=True)997temp_wallet = self.nodes[0].get_wallet_rpc("temp_wallet")998temp_wallet.importdescriptors([descriptor])999self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, temp_wallet.getnewaddress())1000self.generatetoaddress(self.nodes[0], COINBASE_MATURITY + 1, temp_wallet.getnewaddress())
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.