Merge bitcoin/bitcoin#34100: doc: Use multipath descriptors in descriptors.md and linked test
552bc82b17doc: Use multipath descriptors in descriptors.md and linked test (Anurag chavan) Pull request description: Updates documentation and `wallet_miniscript_decaying_multisig_descriptor_psbt.py` to use single multipath descriptors with `<0;1>` syntax instead of separate external/internal descriptors. ## Changes - **doc/descriptors.md**: Update examples (lines 70-71) to use `/<0;1>/*` multipath syntax - **doc/descriptors.md**: Update Basic Multisig Example instructions (line 179) to use single multipath descriptor - **test/functional/wallet_miniscript_decaying_multisig_descriptor_psbt.py**: Refactor to use single multipath descriptor pattern matching `wallet_multisig_descriptor_psbt.py` ## Implementation - `_get_xpub()` now extracts external descriptor and converts to multipath format - `create_multisig()` imports single descriptor that expands to receive and change addresses - Removed fake checksums from documentation examples - Added clear comments documenting multipath convention Fixes #34086 ACKs for top commit: yashbhutwala: ACK552bc82b17achow101: ACK552bc82b17rkrux: lgtm tACK552bc82Tree-SHA512: cc99271a3955daa475242d9f4ef8f09f4c94c64e48ec4647ecfd95dceb38bb0cdd91b78ec2d5f033b449d175eaecbdda49d6c766c8a1e1a01fed93be4eb0cfc0
This commit is contained in:
2 files changed
+17
-23
No files matched your search
@@ -28,32 +28,26 @@ class WalletMiniscriptDecayingMultisigDescriptorPSBTTest(BitcoinTestFramework):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
@staticmethod
|
||||
def _get_xpub(wallet, internal):
|
||||
def _get_xpub(wallet):
|
||||
"""Extract the wallet's xpubs using `listdescriptors` and pick the one from the `pkh` descriptor since it's least likely to be accidentally reused (legacy addresses)."""
|
||||
pkh_descriptor = next(filter(lambda d: d["desc"].startswith("pkh(") and d["internal"] == internal, wallet.listdescriptors()["descriptors"]))
|
||||
pkh_descriptor = next(filter(lambda d: d["desc"].startswith("pkh(") and not d["internal"], wallet.listdescriptors()["descriptors"]))
|
||||
# keep all key origin information (master key fingerprint and all derivation steps) for proper support of hardware devices
|
||||
# see section 'Key origin identification' in 'doc/descriptors.md' for more details...
|
||||
return pkh_descriptor["desc"].split("pkh(")[1].split(")")[0]
|
||||
# Replace the change index with the multipath convention
|
||||
return pkh_descriptor["desc"].split("pkh(")[1].split(")")[0].replace("/0/*", "/<0;1>/*")
|
||||
|
||||
def create_multisig(self, external_xpubs, internal_xpubs):
|
||||
"""The multisig is created by importing the following descriptors. The resulting wallet is watch-only and every signer can do this."""
|
||||
def create_multisig(self, xpubs):
|
||||
"""The multisig is created by importing a single multipath descriptor. The resulting wallet is watch-only and every signer can do this."""
|
||||
self.node.createwallet(wallet_name=f"{self.name}", blank=True, disable_private_keys=True)
|
||||
multisig = self.node.get_wallet_rpc(f"{self.name}")
|
||||
# spending policy: `thresh(4,pk(key_1),pk(key_2),pk(key_3),pk(key_4),after(t1),after(t2),after(t3))`
|
||||
# IMPORTANT: when backing up your descriptor, the order of key_1...key_4 must be correct!
|
||||
external = multisig.getdescriptorinfo(f"wsh(thresh({self.N},pk({'),s:pk('.join(external_xpubs)}),sln:after({'),sln:after('.join(map(str, self.locktimes))})))")
|
||||
internal = multisig.getdescriptorinfo(f"wsh(thresh({self.N},pk({'),s:pk('.join(internal_xpubs)}),sln:after({'),sln:after('.join(map(str, self.locktimes))})))")
|
||||
multisig_desc = f"wsh(thresh({self.N},pk({'),s:pk('.join(xpubs)}),sln:after({'),sln:after('.join(map(str, self.locktimes))})))"
|
||||
checksum = multisig.getdescriptorinfo(multisig_desc)["checksum"]
|
||||
result = multisig.importdescriptors([
|
||||
{ # receiving addresses (internal: False)
|
||||
"desc": external["descriptor"],
|
||||
{ # Multipath descriptor expands to receive and change
|
||||
"desc": f"{multisig_desc}#{checksum}",
|
||||
"active": True,
|
||||
"internal": False,
|
||||
"timestamp": "now",
|
||||
},
|
||||
{ # change addresses (internal: True)
|
||||
"desc": internal["descriptor"],
|
||||
"active": True,
|
||||
"internal": True,
|
||||
"timestamp": "now",
|
||||
},
|
||||
])
|
||||
@@ -73,10 +67,10 @@ class WalletMiniscriptDecayingMultisigDescriptorPSBTTest(BitcoinTestFramework):
|
||||
|
||||
self.log.info("Create the signer wallets and get their xpubs...")
|
||||
signers = [self.node.get_wallet_rpc(self.node.createwallet(wallet_name=f"signer_{i}")["name"]) for i in range(self.N)]
|
||||
external_xpubs, internal_xpubs = [[self._get_xpub(signer, internal) for signer in signers] for internal in [False, True]]
|
||||
xpubs = [self._get_xpub(signer) for signer in signers]
|
||||
|
||||
self.log.info("Create the watch-only decaying multisig using signers' xpubs...")
|
||||
multisig = self.create_multisig(external_xpubs, internal_xpubs)
|
||||
multisig = self.create_multisig(xpubs)
|
||||
|
||||
self.log.info("Get a mature utxo to send to the multisig...")
|
||||
coordinator_wallet = self.node.get_wallet_rpc(self.node.createwallet(wallet_name="coordinator")["name"])
|
||||
|
||||
Reference in new issue
Block a user