External signer multisig support #16895

pull Sjors wants to merge 71 commits into bitcoin:master from Sjors:2019/09/hww-multisig changing 62 files +3788 −182
  1. Sjors commented at 10:43 AM on September 17, 2019: member

    This adds 7 commits on top of #16546 (External signer support) to enable multisig functionality.

    It introduces a new createmultisigwallet RPC which can also be used without external signer support (although it's only marginally easier than importing descriptors).

    It automatically fetches xpubs from connected hardware devices (using HWI), constructs BIP67 multisig descriptors (native and wrapped SegWit) and imports them into a new wallet. For not connected external signers it's also possible to manually provide an xpub.

    Use enumeratesigners to get a list of device fingerprints, and then call the new createmultisigwallet :

    createmultisigwallet "wallet_name" threshold ["fingerprint","xpub1","xpub2",...] ( avoid_reuse )
    
    Creates and loads a new multisig wallet.
    Only native segwit bech32 addresses are supported.
    Arguments:
    1. wallet_name           (string, required) The name for the new wallet. If this is a path, the wallet will be created at the path location.
    2. threshold             (numeric, required) Number of required signatures
    3. signers               (json array, required) A json array of signers identified by their BIP32 fingerprint
         [
           "fingerprint",    (string, required) master key fingerprint. Can be obtained using emumeratesigners.
           "xpub1",          (string) the xpub at deriviation path m/48h/0h/0h/1h used for P2SH_SEGWIT, obtained automatically if -signer if configured
           "xpub2",          (string) the xpub at deriviation path m/48h/0h/0h/2h used for native SegWit, obtained automatically if -signer if configured
           ...
         ]
    4. avoid_reuse           (boolean, optional, default=false) Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind.
    
    Result:
    {
      "name" :    <wallet_name>,        (string) The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path.
      "warning" : <warning>,            (string) Warning message if wallet was not loaded cleanly.
    }
    
    Examples:
    > bitcoin-cli createmultisigwallet "ManualMultisigWallet" 2 '[{"fingerprint": "d34db33f", "xpub2": "xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY"}, {"fingerprint": "3442193e", "xpub1": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"}]'
    > bitcoin-cli createmultisigwallet "AutomaticMultisigWallet" 2 '[{"fingerprint": "d34db33f"}, {"fingerprint": "3442193e"}]'
    > curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "createmultisigwallet", "params": ["ManualMultisigWallet", 2, '[{"fingerprint": "d34db33f", "xpub2": "xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY"}, {"fingerprint": "3442193e", "xpub1": "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"}]'] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/
    > curl --user myusername --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "createmultisigwallet", "params": ["AutomaticMultisigWallet", 2, '[{"fingerprint": "d34db33f"}, {"fingerprint": "3442193e"}]'] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/
    

    It uses the getxpub HWI method instead of getdescriptors, and constructs the descriptor locally.

    TODO:

    • displayaddress support for all connected devices (only ColdCard can handle this afaik, but requires producing a Multisig.txt file)
    • wait for improved change address detection support, or add strong warning

    See also: Junction or Specter Desktop for similar workflows.

    Change detection

    Note that due to limitations in HWI, hardware wallet firmware and the PSBT format, the current multisig flow is pretty unsafe. This is because change detection generally doesn't work.

    On ColdCard you can put a multisig.txt file to enable change detection:

    Name: My-2-of-2
    Policy: 2 of 2
    Derivation: m/48h/0h/0h/2h
    
    A1A1A1A1: xpub...
    B1B1B1B1: xpub...
    
  2. Sjors commented at 10:45 AM on September 17, 2019: member

    cc @justinmoon @stepansnigirev thoughts on derivation paths?

  3. Sjors cross-referenced this on Sep 17, 2019 from issue External signer support - Wallet Box edition by Sjors
  4. DrahtBot added the label Build system on Sep 17, 2019
  5. DrahtBot added the label Docs on Sep 17, 2019
  6. DrahtBot added the label GUI on Sep 17, 2019
  7. DrahtBot added the label RPC/REST/ZMQ on Sep 17, 2019
  8. DrahtBot added the label Tests on Sep 17, 2019
  9. DrahtBot added the label Utils/log/libs on Sep 17, 2019
  10. DrahtBot added the label Wallet on Sep 17, 2019
  11. stepansnigirev commented at 12:43 PM on September 17, 2019: contributor

    Using m/48h/0h/0h/1h derivation path by default is ok, but I would like to be able to change the derivation path in options. Also it would be nice to provide xpub without fingerprint, then fingerprint of the xpub and m/ as derivation path could be used, but not sure if it makes sense.

    [
           "fingerprint",   (string, required) master key fingerprint. Can be obtained using emumeratesigners.
           "derivation",    (string) deriviation path for the key, m/48h/0h/0h/1h by default
           "xpub",          (string) the xpub, obtained automatically if -signer if configured
    ]
    
  12. Sjors force-pushed on Sep 18, 2019
  13. laanwj removed the label Tests on Oct 2, 2019
  14. laanwj added the label Feature on Oct 2, 2019
  15. laanwj removed the label Utils/log/libs on Oct 2, 2019
  16. laanwj removed the label Build system on Oct 2, 2019
  17. laanwj removed the label Docs on Oct 2, 2019
  18. Sjors cross-referenced this on Oct 29, 2019 from issue Hardware wallet support by Sjors
  19. Sjors force-pushed on Oct 29, 2019
  20. Sjors commented at 3:26 PM on October 29, 2019: member

    It now uses sortedmulti() from #17056 and creates both native segwit and P2SH wrapped SegWit descriptors. This should match the derivation paths used by Electrum and ColdCard: https://github.com/spesmilo/electrum/pull/4465

    You can test this with HWI, a ColdCard simulator plus one other wallet, e.g. Trezor (Simulator) or Ledger. After you called createmultisigwallet, you need to create a multisig text file for the ColdCard simulator in work/MicroSD/multisig.txt, using fingerprints and xpubs used in the wallet. You can see those in the descriptor, by generating an address and calling getaddressinfo.

    Name: My-2-of-2
    Policy: 2 of 2
    Derivation: m/48h/0h/0h/2h
    
    A1A1A1A1: tpub...
    B1B1B1B1: tpub...
    

    Now you can send and receive, even with the GUI. Note that HWI automatically clicks Yes on the ColdCard simulator screen to sign....

  21. Sjors force-pushed on Oct 29, 2019
  22. Sjors force-pushed on Oct 29, 2019
  23. DrahtBot commented at 8:54 AM on October 30, 2019: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #18052 (Remove false positive GCC warning by hebasto)
    • #18034 (Get the OutputType for a descriptor by achow101)
    • #18032 (Output a descriptor in createmultisig and addmultisigaddress by achow101)
    • #18027 ("PSBT Operations" dialog by gwillen)
    • #17877 (qt, refactor: Make enums in BitcoinUnits class scoped by hebasto)
    • #17786 (refactor: Nuke policy/fees->mempool circular dependencies by hebasto)
    • #17681 (wallet: Keep inactive seeds after sethdseed and derive keys from them as needed by achow101)
    • #17566 (Switch to weight units for all feerates computation by darosior)
    • #16722 (build: Disable warnings for leveldb subtree by default by hebasto)
    • #16681 (Tests: Use self.chain instead of 'regtest' in all current tests by jtimon)
    • #16528 (Native Descriptor Wallets using DescriptorScriptPubKeyMan by achow101)
    • #16440 (BIP-322: Generic signed message format by kallewoof)
    • #16432 (qt: Add privacy to the Overview page by hebasto)
    • #16367 (Multiprocess build support by ryanofsky)
    • #16365 (Log RPC parameters (arguments) if -debug=rpcparams by LarryRuane)
    • #16224 (gui: Bilingual GUI error messages by hebasto)
    • #15590 (Descriptor: add GetAddressType() and IsSegWit() by Sjors)
    • #15382 (util: add runCommandParseJSON by Sjors)
    • #15112 (build: Optionally enable -Wzero-as-null-pointer-constant by Empact)
    • #14920 (Build: enable -Wdocumentation via isystem by Empact)
    • #11413 ([wallet] [rpc] sendtoaddress/sendmany: Add explicit feerate option by kallewoof)

    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.

  24. Sjors force-pushed on Oct 30, 2019
  25. Sjors force-pushed on Oct 31, 2019
  26. ryanofsky added this to the "PRs" column in a project

  27. Sjors force-pushed on Nov 7, 2019
  28. Rspigler cross-referenced this on Nov 8, 2019 from issue ui: make send a wizard by Sjors
  29. Sjors force-pushed on Dec 9, 2019
  30. Output a descriptor in createmultisig dd92677895
  31. Introduce SetType function to tell ScriptPubKeyMans the type and internal-ness of it 83a61b78f0
  32. Introduce DescriptorScriptPubKeyMan as a dummy class 3f6cbc5bb1
  33. Add WALLET_FLAG_DESCRIPTORS 949e0734d4
  34. Return nullptr from GetLegacyScriptPubKeyMan if descriptor wallet cf3bc7a550
  35. Create LegacyScriptPubKeyMan when not a descriptor wallet e40a833c3b
  36. Add a lock cs_desc_man for DescriptorScriptPubKeyMan b502a15a95
  37. Store WalletDescriptor in DescriptorScriptPubKeyMan c3bf86b9af
  38. Add LoadDescriptorScriptPubKeyMan and SetActiveScriptPubKeyMan to CWallet 9b99b52ad4
  39. Implement IsMine for DescriptorScriptPubKeyMan
    Adds a set of scriptPubKeys that DescriptorScriptPubKeyMan tracks.
    If the given script is in that set, it is considered ISMINE_SPENDABLE
    25d49c00c1
  40. Implement MarkUnusedAddresses in DescriptorScriptPubKeyMan 172a4eb3d0
  41. Implement IsHDEnabled in DescriptorScriptPubKeyMan 32f97aa7ee
  42. Implement GetID for DescriptorScriptPubKeyMan 632f0f1c5a
  43. Implement SetType in DescriptorScriptPubKeyMan 75be4afd20
  44. Load the descriptor cache from the wallet file 193d96f669
  45. Implement loading of keys for DescriptorScriptPubKeyMan a186fba22d
  46. Implement several simple functions in DescriptorScriptPubKeyMan
    Implements a bunch of one liners: UpgradeKeyMetadata, IsFirstRun, HavePrivateKeys,
    KeypoolCountExternalKeys, GetKeypoolSize, GetTimeFirstKey, CanGetAddresses,
    RewriteDB
    b683600077
  47. Implement writing descriptorkeys, descriptorckeys, and descriptors to wallet file 738e361509
  48. Implement SetupGeneration for DescriptorScriptPubKeyMan a7a85d2ae9
  49. Implement TopUp in DescriptorScriptPubKeyMan e46d3fd5d7
  50. Add IsSingleType to Descriptors
    IsSingleType will return whether the descriptor will give one or multiple scriptPubKeys
    2a0a784aa9
  51. Add a function to determine the OutputType of a scriptPubKey c80e25d874
  52. Implement GetNewDestination for DescriptorScriptPubKeyMan cafb33b3f0
  53. Implement Unlock and Encrypt in DescriptorScriptPubKeyMan 0743ed804f
  54. Implement KeepDestination and ReturnDestination in DescriptorScriptPubKeyMan 5fa5304458
  55. Implement GetReservedDestination in DescriptorScriptPubKeyMan 168dcf6fd9
  56. Implement GetKeypoolOldestTime and only display it if greater than 0 7fa74bad12
  57. Implement GetSigningProvider for descriptor wallets 7e0a7bc0af
  58. Change GetMetadata to use unique_ptr<CKeyMetadata> d3819b681f
  59. Implement GetMetadata in DescriptorScriptPubKeyMan 19715e2af6
  60. Be able to create new wallets with DescriptorScriptPubKeyMans as backing d050347076
  61. Generate new descriptors when encrypting b3d3684cf9
  62. Add IsLegacy to CWallet so that the GUI knows whether to show watchonly 0fc666f32f
  63. add importdescriptors RPC and tests for native descriptor wallets
    Co-authored-by: Andrew Chow <achow101-github@achow101.com>
    b7cf42ac12
  64. Functional tests for descriptor wallets 2de2414044
  65. Change wallet_encryption.py to use signmessage instead of dumpprivkey aef2a5cbb9
  66. Add a --descriptors option to various tests
    Adds the option to use a descriptor wallet to:
    * wallet_basic.py
    * wallet_encryption.py
    * wallet_keypool.py
    * wallet_keypool_topup.py
    * wallet_labels.py
    
    Also runs these tests with --descriptors in test_runner
    eaa391d98f
  67. [depends] update to Boost 1.72 cc443d69fe
  68. configure: add ax_boost_process
    Co-authored-by: Luke Dashjr <luke-jr+git@utopios.org>
    c1e9630ae5
  69. [build] msvc: add boost::process
    * AppVeyor boost-process vcpkg package.
    * Tell Boost linter to ignore it
    * Add HAVE_BOOST_PROCESS for MSVC build (bitcoin_config.h)
    8414896182
  70. [doc] include Doxygen comments for HAVE_BOOST_PROCESS e169a0fa6f
  71. [util] add runCommandParseJSON 6ecbcfab81
  72. configure: add --disable-external-signer
    This prepares external signer support to be enabled by default
    if Boost::Process is present. It adds a configure option to
    disable this feature.
    
    It can also be disabled using --without-boost-process
    
    This also exposes ENABLE_EXTERNAL_SIGNER to the test suite via test/config.ini
    3a2949ce54
  73. Sjors force-pushed on Jan 30, 2020
  74. Sjors force-pushed on Jan 30, 2020
  75. Sjors force-pushed on Jan 30, 2020
  76. [build] msvc: define ENABLE_EXTERNAL_SIGNER e0d2020920
  77. [doc] include Doxygen comments for ENABLE_EXTERNAL_SIGNER 75c0889287
  78. [test] framework: add skip_if_no_external_signer 678668bb69
  79. [build] add IO support for Boost::Optional af62337d24
  80. Add AddressType (base58, bech32) f5d349189f
  81. Descriptor: add GetAddressType() e458981d3e
  82. Add IsSegWit() to Descriptor b66635088d
  83. [wallet] add -signer argument for external signer command
    Create basic ExternalSigner class with contructor. A Signer(<cmd>)
    is added to CWallet on load if -signer=<cmd> is set.
    94059d47ea
  84. [test] add external signer test
    Includes a mock to mimick the HWI interace.
    addfc89fea
  85. [rpc] add external signer RPC files 9878c2a1cd
  86. [rpc] signer: add enumeratesigners to list external signers 1add4c77f4
  87. [wallet] add external_signer flag 68b9b132b7
  88. [rpc] add external_signer option to createwallet 835e2e632b
  89. [test] external_signer wallet flag is immutable d0f3a5adf1
  90. [wallet] ExternalSigner: add getDescriptors method 76112ba00e
  91. [wallet] add GetExternalSigner() 1905c6c44d
  92. [wallet] fetch keys from external signer upon creation b114902f4f
  93. Add Fingerprint() to Descriptor 08ffaef4aa
  94. [rpc] signerdisplayaddress 81ca8ab9fa
  95. [rpc] sendtoaddress and sendmany: support external signer afa9aafc0c
  96. [doc] add external-signer.md 0a0d295415
  97. [wallet] CreateMultisigWallet d78939cd3a
  98. [rpc] createmultisigwallet 4dccbcc5f0
  99. [wallet] add getxpub to external signer c1e2c521eb
  100. [rpc] createmultisigwallet: fetch xpub from signer if present f11aadad91
  101. [wallet] CreateTransaction: iterate detected external signers e0deaf5853
  102. [wallet] CreateTransaction return PSBT if incomplete 651ef6b695
  103. [rpc] walletprocesspsbt: use external signers when available 3fda68ed0a
  104. Sjors force-pushed on Jan 30, 2020
  105. Sjors cross-referenced this on Feb 13, 2020 from issue Coordinate multi-sig wallet by Sjors
  106. Sjors commented at 12:29 PM on February 19, 2020: member

    I'll look into this again when there's more progress on a standard for multisig wallet coordination, see #18142.

  107. Sjors closed this on Feb 19, 2020

  108. Rspigler cross-referenced this on Feb 3, 2021 from issue ~~$1,500 Bounty for Offline Multisignature through the GUI~~ View #24861 by Rspigler
  109. Rspigler commented at 7:37 AM on May 13, 2021: contributor

    Hi @Sjors - see BSMS for a standard for multisig wallet coordination

  110. Rspigler commented at 1:19 AM on June 26, 2021: contributor

    Should this be reopened?

  111. bitcoin deleted a comment on Jun 26, 2021
  112. Sjors commented at 1:50 PM on June 26, 2021: member

    I have some ideas on how to tackle this, but no need to reopen this PR. First step is #22341

  113. Sjors deleted the branch on Nov 18, 2021
  114. bitcoin locked this on Nov 18, 2022

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: 2026-05-20 06:54 UTC