doc: update multisig tutorial to use multipath descriptors #33286

pull BenWestgate wants to merge 1 commits into bitcoin:master from BenWestgate:change-and-receiving-single-descriptor changing 2 files +28 −38
  1. BenWestgate commented at 8:28 pm on September 2, 2025: contributor

    Summary

    Update doc/multisig-tutorial.md to use multipath descriptor format
    instead of separate external/internal descriptors. The tutorial now:

    • extracts a single xpub_n per participant
    • constructs a multipath wsh(sortedmulti(...)) descriptor with <0;1>
      change index semantics
    • uses getdescriptorinfo to compute descriptor checksum
    • explains that importdescriptors expands the multipath descriptor
      into internal and external descriptors
    • update /test/functional/wallet_multisig_descriptor_psbt.py functional test / documentation to use multi-path descriptors

    Motivation

    A single multipath descriptor is the most convenient pattern for multisig; our documentation should use it.


    What changed

    • replaced extraction of external_xpub_n and internal_xpub_n with
      extraction of a single xpub_n
    • removed instructions to create and import separate external/internal
      descriptors
    • added instructions to build a multipath wsh(sortedmulti(...))
      descriptor and derive checksum with getdescriptorinfo
    • checksum field is parsed and appended as the multipath descriptor is not the canonical “desc” output
    • clarified that importdescriptors automatically expands multipath
      descriptors into internal and external forms
    • similar changes to the functional test: wallet_multisig_descriptor_psbt.

    Testing

    I have run the updated shell snippets and confirmed the multipath descriptor produces the same listdescriptors output after importing as the two descriptor method in bitcoin:master.


    This tutorial change references the multipath descriptor consolidation (see commit / PR referenced in the change). The commit message points to bitcoin#22838 as the upstream change that enables this behavior.


    Release note (for changelog)

    Documentation: update multisig tutorial and multisig functional test to use multipath descriptors

  2. DrahtBot added the label Docs on Sep 2, 2025
  3. DrahtBot commented at 8:28 pm on September 2, 2025: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33286.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK Sjors, kannapoix
    Concept ACK w0xlt, rkrux

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #32784 (wallet: derivehdkey RPC to get xpub at arbitrary path by Sjors)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  4. BenWestgate marked this as a draft on Sep 2, 2025
  5. BenWestgate marked this as ready for review on Sep 2, 2025
  6. Sjors commented at 10:06 am on September 3, 2025: member

    Concept ACK

    #32784 contains a similar change, but it’s nice to do that separately and earlier.

    You could probably just squash these commits.

    Can you also update https://github.com/bitcoin/bitcoin/blob/master/test/functional/wallet_multisig_descriptor_psbt.py to use multipath descriptors? That test is quite similar to this document.

  7. w0xlt commented at 7:06 pm on September 3, 2025: contributor
    Concept ACK
  8. in doc/multisig-tutorial.md:80 in cf2986684b outdated
    87 
    88-`external_desc` and `internal_desc` specify the output type (`wsh`, in this case) and the xpubs involved. They also use BIP 67 (`sortedmulti`), so the wallet can be recreated without worrying about the order of xpubs. Conceptually, descriptors describe a list of scriptPubKey (along with information for spending from it) [[source](https://github.com/bitcoin/bitcoin/issues/21199#issuecomment-780772418)].
    89+`desc` specifies the output type (`wsh`, in this case) and the xpubs involved. It also uses BIP 67 (`sortedmulti`), so the wallet can be recreated without worrying about the order of xpubs. Conceptually, descriptors describe a list of scriptPubKey (along with information for spending from it) [[source](https://github.com/bitcoin/bitcoin/issues/21199#issuecomment-780772418)].
    90 
    91-Note that at least two descriptors are usually used, one for internal derivation paths and one for external ones. There are discussions about eliminating this redundancy, as can be seen in the issue [#17190](https://github.com/bitcoin/bitcoin/issues/17190).
    92+Note that previously at least two descriptors were usually used, one for internal derivation paths and one for external ones. Since https://github.com/bitcoin/bitcoin/pull/22838 this redundancy has been eliminated by a multipath descriptor with <code><0;1></code> as the change index.
    


    rkrux commented at 2:12 pm on September 4, 2025:

    In cf2986684ba0db4e0f7b32deb65d7767f80e9c01 “Update multisig-tutorial.md to use multipath descriptors”

    Can consider moving this note in the previous section where the multipath descriptor is actually sed-ed.

     0diff --git a/doc/multisig-tutorial.md b/doc/multisig-tutorial.md
     1index fa6366df91..c59359de0a 100644
     2--- a/doc/multisig-tutorial.md
     3+++ b/doc/multisig-tutorial.md
     4@@ -63,6 +63,8 @@ for x in "${!xpubs[@]}"; do printf "[%s]=%s\n" "$x" "${xpubs[$x]}" ; done
     5 
     6 As previously mentioned, this step extracts the `m/84'/1'/0'` account instead of the path defined in [BIP 45](https://github.com/bitcoin/bips/blob/master/bip-0045.mediawiki) or [BIP 87](https://github.com/bitcoin/bips/blob/master/bip-0087.mediawiki), since there is no way to extract a specific path in Bitcoin Core at the time of writing.
     7 
     8+Note that previously at least two descriptors were usually used, one for internal derivation paths and one for external ones. Since [#22838](/bitcoin-bitcoin/22838/) this redundancy has been eliminated by a multipath descriptor with <code><0;1></code> as the change index.
     9+
    10 ### 1.2 Define the Multisig Descriptor
    11 
    12 Define the multisig descriptor, add the checksum and then, wrap it in a JSON array.
    13@@ -77,8 +79,6 @@ multisig_desc="[{\"desc\": \"${desc}#${checksum}\", \"active\": true, \"timestam
    14 
    15 `desc` specifies the output type (`wsh`, in this case) and the xpubs involved. It also uses BIP 67 (`sortedmulti`), so the wallet can be recreated without worrying about the order of xpubs. Conceptually, descriptors describe a list of scriptPubKey (along with information for spending from it) [[source](/bitcoin-bitcoin/21199/#issuecomment-780772418)].
    16 
    17-Note that previously at least two descriptors were usually used, one for internal derivation paths and one for external ones. Since [#22838](/bitcoin-bitcoin/22838/) this redundancy has been eliminated by a multipath descriptor with <code><0;1></code> as the change index.
    18-
    19 After creating the descriptor, it is necessary to add the checksum, which is required by the `importdescriptors` RPC.
    20 
    21 The checksum for a descriptor without one can be computed using the `getdescriptorinfo` RPC. The response has the `descriptor` field, which is the descriptor with the checksum added.
    

    BenWestgate commented at 4:25 am on September 6, 2025:
    Good idea. I moved that note to section 1.1, right before our snippet with sed. I’d rather explain it in words before the command.
  9. rkrux commented at 2:13 pm on September 4, 2025: contributor

    Concept ACK 226836e70501abf9ac2434900e74eec31edd716e

    As mentioned in this comment #33286 (comment) as well, I think all these commits can be squashed into one.

  10. kannapoix commented at 6:05 am on September 5, 2025: none

    ACK 226836e70501abf9ac2434900e74eec31edd716e

    I followed the new instruction and successfully spend from multisig wallet: https://mempool.space/signet/tx/6b5b7922b68b6becfc3aea5a541ce700837d5105d332889929b46cf1428df4a4

    Although not directly related to this PR, I have a minor suggestion: it might be helpful to add a loadwallet command for multisig_wallet_01, not just for participant wallets.

    0diff --git a/doc/multisig-tutorial.md b/doc/multisig-tutorial.md
    1index fa6366df91d..3527b1cd17d 100644
    2--- a/doc/multisig-tutorial.md
    3+++ b/doc/multisig-tutorial.md
    4@@ -115,6 +115,7 @@ Once the wallets have already been created and this tutorial needs to be repeate
    5 
    6```bash
    7 for ((n=1;n<=3;n++)); do ./build/bin/bitcoin-cli -signet loadwallet "participant_${n}"; done
    8+./build/bin/bitcoin-cli -signet loadwallet "multisig_wallet_01"
    9```
    
  11. DrahtBot requested review from Sjors on Sep 5, 2025
  12. DrahtBot requested review from rkrux on Sep 5, 2025
  13. BenWestgate force-pushed on Sep 6, 2025
  14. doc: Update multisig-tutorial.md to use multipath descriptors
    Update doc/multisig-tutorial.md to use a single multipath descriptor
    instead of separate external/internal descriptors, per PR #22838.
    Extract one xpub per participant, build a multipath descriptor with
    <0;1> change index, and use getdescriptorinfo to append the checksum.
    Clarify importdescriptors expands multipath descriptors into internal
    and external forms. Tested shell snippets to confirm equivalent
    listdescriptors output as the two-descriptor method.
    
    Added missing loadwallet command for multisig_wallet_01
    
    test: Use multipath descriptors in the functional wallet test
    wallet_multisig_descriptor_psbt as this is intended as documentation
    5424b4f1ce
  15. BenWestgate force-pushed on Sep 6, 2025
  16. BenWestgate commented at 5:31 am on September 6, 2025: contributor

    Thanks for the suggestion @Sjors. I’ve updated the test to use multi-path descriptors as well.

    Although not directly related to this PR, I have a minor suggestion: it might be helpful to add a loadwallet command for multisig_wallet_01, not just for participant wallets.

    I agree it’s a flaw to not load multisig_wallet_01 so I added it to this PR, we’ll see if that’s OK or reviewers want it in a separate commit or PR.

  17. in doc/multisig-tutorial.md:118 in 5424b4f1ce
    114@@ -120,6 +115,7 @@ Once the wallets have already been created and this tutorial needs to be repeate
    115 
    116 ```bash
    117 for ((n=1;n<=3;n++)); do ./build/bin/bitcoin-cli -signet loadwallet "participant_${n}"; done
    118+./build/bin/bitcoin-cli -signet loadwallet "multisig_wallet_01"
    


    Sjors commented at 6:18 am on September 8, 2025:
    nit: you could use ./build/bin/bitcoin rpc instead. This removes the need for -named elsewhere in the tutorial.

    BenWestgate commented at 8:18 pm on September 8, 2025:

    I don’t understand this nit. I tried:

    0for ((n=1;n<=3;n++))
    1do
    2 ./build/bin/bitcoin rpc -signet createwallet "participant_${n}"
    3done
    

    and got: bash: ./build/bin/bitcoin: No such file or directory


    kannapoix commented at 7:39 am on September 11, 2025:

    It looks like the bitcoin binary might not have been built.
    As far as I know, BUILD_BITCOIN_BIN=ON is the default, but maybe you built with a non-default setting.
    If you build with bitcoin binary explicitly enabled, it should be generated at the path:

    0cmake -B build -DBUILD_BITCOIN_BIN=ON
    

    Sjors commented at 10:00 am on September 11, 2025:
    It should be built by default, as of a few months ago.
  18. in test/functional/wallet_multisig_descriptor_psbt.py:34 in 5424b4f1ce
    32+        pkh_descriptor = next(filter(lambda d: d["desc"].startswith("pkh(") and not d["internal"], wallet.listdescriptors()["descriptors"]))
    33         # Keep all key origin information (master key fingerprint and all derivation steps) for proper support of hardware devices
    34         # See section 'Key origin identification' in 'doc/descriptors.md' for more details...
    35-        return pkh_descriptor["desc"].split("pkh(")[1].split(")")[0]
    36+        # Replace the change index with the multipath convention
    37+        return pkh_descriptor["desc"].split("pkh(")[1].split(")")[0].replace("/0/*", "/<0;1>/*")
    


    Sjors commented at 6:22 am on September 8, 2025:
    You could also drop /0/* because it’s not part of the origin. Then later on where you use the xpub, add /<0;1>/*.

    BenWestgate commented at 8:11 pm on September 8, 2025:
    Master returns xpub with change index so I replace() inline to maintain the same derivation depth. This matches the method in our Tutorial and is less code. Finally, if the future wallet ever outputs a multipath descriptor, we’ll get an xpub in this format and not have to add /<0;1>/*.
  19. Sjors approved
  20. Sjors commented at 6:23 am on September 8, 2025: member

    utACK 5424b4f1ce74c82b7ae01034bbc1592088048128

    I didn’t test the tutorial.

  21. DrahtBot requested review from kannapoix on Sep 11, 2025
  22. kannapoix commented at 7:43 am on September 11, 2025: none

    reACK 5424b4f1ce74c82b7ae01034bbc1592088048128

    Tested and reviewed the new functional test.


github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-09-12 12:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me