Skip to content

Conversation

@mjdietzx
Copy link
Contributor

@mjdietzx mjdietzx commented May 26, 2021

Aims to resolve issue #21278. I try to follow the steps laanwj outlined there exactly, with the exception of using combinepsbt instead of joinpsbts. I wrote a functional test to make sure it works as expected before doing the docs, and figured it would also be a good source of documentation. So I kept the test as simple as possible and didn't go crazy with edge-cases and various checks. I do have a lot more test-cases I've written that I will follow up with (either in a separate PR or another commit - lmk if you have a preference), but I want to do it in a way that doesn't bloat this test so it remains useful as a quickstart (unless that's a bad idea)?

@mjdietzx mjdietzx force-pushed the multisig_descriptor_wallet_psbt_signing_flow branch from ec90947 to 648d111 Compare May 26, 2021 01:10
@mjdietzx mjdietzx force-pushed the multisig_descriptor_wallet_psbt_signing_flow branch from 648d111 to 4069660 Compare May 26, 2021 01:23
Copy link
Member

@Sjors Sjors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

This documentation and example also help illustrate where things could be made easier, e.g.:

  • having a wallet with just a seed, but no descriptors, and a way to ask it for an xpub
  • and RPC call (or wallet-tool command) to create a multisig descriptor given a bunch xpubs

@mjdietzx mjdietzx force-pushed the multisig_descriptor_wallet_psbt_signing_flow branch from 69b071e to 178681b Compare May 26, 2021 14:38
@mjdietzx
Copy link
Contributor Author

Thanks for the thorough review and suggestions @Sjors ! I've addressed all your feedback in my latest push.

This documentation and example also help illustrate where things could be made easier, e.g.:

  • having a wallet with just a seed, but no descriptors, and a way to ask it for an xpub

I see the benefit of this - I found it tricky to extract a wallet's xpubs in bitcoin core (didn't find a way to do this w/ the GUI, the only way I know is w/ the rpc command listdescritptors as documented/tested here, but that means users will need to use the console for this). While most other wallets seem to make this easily accessible

  • and RPC call (or wallet-tool command) to create a multisig descriptor given a bunch xpubs

Interesting idea - I guess this would take care of step 2 in one easy command? Is the reason you suggest this to push forward "standardization" of multisigs similar to the approach outlined here?

@mjdietzx mjdietzx force-pushed the multisig_descriptor_wallet_psbt_signing_flow branch from 178681b to 932de9b Compare May 26, 2021 14:50
@Sjors
Copy link
Member

Sjors commented May 26, 2021

Eventually it would be nice if step (1) and (2) are trivial to do with RPC or standalone tools. And then hopefully also easy to add GUI support for them. E.g. a screen where you can share your xpub, copy-paste xpubs from your co-signers, set the threshold, etc. Standardisation is another issue.

@mjdietzx
Copy link
Contributor Author

mjdietzx commented May 26, 2021

Any thoughts about me adding some caution/disclaimer text in the docs about the interoperability of this mulitsig with (external) common hardware wallets? Based on my testing so far it isn't as straightforward as just getting an xpub from your HW device and using that as a signer in the multisig. For example, ColdCard has some restrictions/checks (and a proprietary configuration text file for multisig), and I haven't been able to get a ColdCard to sign one of these PSBTs (even after trying to setup everything how they want it 😕). It's strange, and I plan on following up with popular HW wallet providers because I would expect it to work seamlessly, but as of now it doesn't seem to (and could lead to locked funds if someone tries this before HW wallets get updated).

How I would expect a wallet like ColdCard to handle this is when the user goes to sign the PSBT w/ their HW wallet:

  1. The wallet runs > decodepsbt "psbt" (the PSBT base64 string) and sees something like:
{
  tx: {
    txid: '...',
    hash: '...',
    version: 2,
    size: 94,
    vsize: 94,
    weight: 376,
    ...
    vin: [ [Object] ],
    vout: [ [Object] ]
  },
  ...
  inputs: [
    {
      witness_utxo: [Object],
      non_witness_utxo: [Object],
      witness_script: [Object],
      bip32_derivs: [Array]
    }
  ],
  outputs: [ {} ],
}
  1. Now (before signing the PSBT) the HW wallet can just check the inputs: witness_script.asm to verify this is a standard N-of-M multisig transfer, and bip32_derivs to verify that this device's master_fingerprint is present and to determine the path/pubkey it needs to sign for:
...
witness_script: {
  asm: '2 <pubkeyA> <pubkeyB> <pubkeyC> 3 OP_CHECKMULTISIG',
  hex: '...',
  type: 'multisig'
},
bip32_derivs: [
  {
    pubkey: <pubkeyA>,
    master_fingerprint: <deviceAFingerprint>,
    path: 'm/0/0'
  },
  {
    pubkey: <pubkeyB>,
    master_fingerprint: <deviceBFingerprint>,
    path: 'm/0/0'
  },
  {
    pubkey: <pubkeyC>,
    master_fingerprint: <deviceCFingerprint>,
    path: 'm/0/0'
  }
]

And after these very simple checks it should be able to sign the PSBT without any additional setup/configuration from the end user. Am I over simplifying this or missing anything? Just want to get some feedback before I chase issues down with HW wallets

@Sjors
Copy link
Member

Sjors commented May 26, 2021

I think the ColdCard file format for communicating wallet info is essentially the Electrum format.

Afaik with Trezor and Ledger it is a simple matter of getting an xpub (e.g. using HWI).

It's probably still most practical to use something Specter Desktop to configure multisig wallets. Once setup, spending can be done with just Bitcoin Core afaik.

Note that for signing each device should not just check that it's own keys are present, but also that cosigners weren't changed. So these need to be registered. ColdCard does that, which is why it's a bit more complicated to setup. Trezor and Ledger don't, so they're easier to setup, but also easier to fool.

There are folks working on standardization of the setup process, e.g. BIP 86 and BIP 129.

Also take a look at a PSBT extension that would includes xpubs: #17034: that could theoretically let you switch to trust-on-first-use when spending. But you really should verify an address before receiving coins on it, not when you spend from it.

@mjdietzx
Copy link
Contributor Author

Thanks for the explanation and links, very helpful. I'll look into all of this more.

But you really should verify an address before receiving coins on it, not when you spend from it.

I guess this last sentence is where I get caught up. By the time I try to sign a PSBT (as a multisig co-signer):

  1. The watch-only multisig has funds I am trying to spend
  2. I really care about where I am sending these funds, the amount, and the fee. And that's what I'm verifying on my device, as usual

So is there a practical attack vector where somehow I am given a PSBT that has changed/different cosigners? I guess I'm missing the point of the extra complexity and setup on the HW side (and now I have to trust software outside of bitcoin core like Specter). Especially when I would think a lot of multisigs are either self-contained (ie my own M-of-N multis) or between "friends" (it's not like I'm signing random PSBTs I get from who knows where). Or I'm still missing something?

I guess the worst case scenarios is the multisig "coordinator" gets me to sign a PSBT that's still a standard M-of-N multisig as documented here, and that I'm a cosigner for, but the other cosigners have been changed? Maybe they can get me to do this a few times (to extract some info?) but what's the harm since they shouldn't be able to trick me into sending funds anywhere?

Sending to the multisig seems like an entirely separate concern, and seems to be handled pretty well in this process (as outlined in these docs) because participants create/import their watch-only multisig once, and then would obviously generate new receive addresses there (and all participants are checking that the receive addresses match)

@Sjors
Copy link
Member

Sjors commented May 26, 2021

@mjdietzx one thing to worry about is an attacker modifying the change address to a 2-of-3, with two of his keys, and hold you ransom.

@mjdietzx
Copy link
Contributor Author

one thing to worry about is an attacker modifying the change address to a 2-of-3, with two of his keys, and hold you ransom.

Isn't that checked against here, where every participant checks the PSBT w/ decodepsbt with their watch-only multisig before signing (step 6 in the docs this PR adds)? https://github.com/bitcoin/bitcoin/pull/22067/files#diff-94f52fa5de899f58d07aca5026545378bc3da616d4927d71435fa0224eda589bR41

@Sjors
Copy link
Member

Sjors commented May 26, 2021

Yes, but the reason you can do this check is because you imported the xpubs from other devices. That's what makes the setup tedious.

Copy link
Contributor

@lsilva01 lsilva01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested ACK 932de9b

@theStack
Copy link
Contributor

theStack commented Jun 9, 2021

Concept ACK

@Rspigler
Copy link
Contributor

Thank you for working on this!

I think this is a great first step, but ultimately we will need BIP 129, BIP 87, (possibly) BIP 88, and PSBT v2 support.

As @Sjors pointed out, I think this is useful because it also provides us a list of To Do's (besides the above):

  • having a wallet with just a seed, but no descriptors, and a way to ask it for an xpub
  • RPC call (or wallet-tool command) to create a multisig descriptor given a bunch xpubs
  • GUI support

It's probably still most practical to use something Specter Desktop to configure multisig wallets. Once setup, spending can be done with just Bitcoin Core afaik.

I agree this is the case for now, but hopefully in the future Bitcoin Core can be a full fledged coordinator.

  1. Create a watch-only descriptor wallet (blank, private keys disabled). Now the multisig is created by importing the
    following descriptors: wsh(sortedmulti(<M>,xpubA/<0,1>/*,xpubB/<0,1>/*,…,xpubN/<0,1>/*))

This isn't the proper way to write two descriptors (see here). I think using a descriptor template would be better.

@mjdietzx mjdietzx force-pushed the multisig_descriptor_wallet_psbt_signing_flow branch from 932de9b to 13edc4d Compare July 14, 2021 20:33
@mjdietzx
Copy link
Contributor Author

@Rspigler Thanks for the review, re point 2:

This isn't the proper way to write two descriptors (see here). I think using a descriptor template would be better.

Is this better? https://github.com/bitcoin/bitcoin/pull/22067/files#diff-00ec9f97461f6bb94a37daf8069e5acf832ea4d5a31a8d7d4968c285d2fcac9bR144

@mjdietzx
Copy link
Contributor Author

@laanwj If you have a chance can you give this a quick review?

@Rspigler
Copy link
Contributor

wsh(sortedmulti(<M>,XPUB1/**,XPUB2/**,…,XPUBN/**)) /0/*,/1/*

Yes, that is the proper template!

However, now that I think about it again, since this is documenting the setup for Bitcoin Core which doesn't have support for templates yet, the directions should probably write out explicitly the importing of both descriptors separately - which is what users will have to do. So something like this:

Now the multisig is created by importing the two descriptors; For example:
wsh(sortedmulti(<M>,XPUB1/0/*,XPUB2/0/*,...XPUBN/0/*))
wsh(sortedmulti(<M>,XPUB1/1/*,XPUB2/1/*,...XPUBN/1/*))

(one descriptor w/ 0 in the derivation path for receiving addresses and another w/ 1 for change). Every participant does this

And maybe templates not be mentioned at all. Sorry for flip flopping on you

@mjdietzx mjdietzx force-pushed the multisig_descriptor_wallet_psbt_signing_flow branch from 13edc4d to d1ce7bb Compare July 15, 2021 14:20
@mjdietzx
Copy link
Contributor Author

Good point @Rspigler I removed the descriptor templates, but fixed as you suggest: 911ed48#diff-00ec9f97461f6bb94a37daf8069e5acf832ea4d5a31a8d7d4968c285d2fcac9bR144

@Rspigler
Copy link
Contributor

ACK d1ce7bb4fb1f8cd929e23eae7aa9dd0862e938f2 (doc changes; not yet fully comfortable with my understanding of the tests in Core).

@OliverOffing
Copy link

ACK d1ce7bb (tests pass)

Copy link
Contributor

@lsilva01 lsilva01 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reACK d1ce7bb

@fanquake fanquake requested a review from achow101 August 16, 2021 05:51
@achow101
Copy link
Member

ACK e05cd05

@S3RK
Copy link
Contributor

S3RK commented Aug 26, 2021

Started review

@josibake
Copy link
Member

josibake commented Sep 1, 2021

Concept ACK

Reading through the documentation, it sounds good. Also rebased and ran the new test. Setting aside time later today to try and follow your documentation step by step and will post some feedback (if any)

Copy link
Contributor

@S3RK S3RK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not have just one wallet? Having two wallets is less intuitive, complicates backups and could lead to user confusion and even loss of funds. Especially taking into account that you need to backup both wallets to restore your funds. This doesn't come through the documentation.

There are two possibilities here:

  1. Import multisig descriptor into the wallet you used to generate xpub. You can do it by taking your xpriv and others' xpub. Additionally you can disable the original descriptors. The downside you'd have disabled and unused descriptors lingering in the wallet.
  2. Import multisig descriptor with your xpriv into new wallet and then drop the original wallet. You have a perfectly clean setup, but you still need two create two wallets and drop one of them.

I also left a bunch of nits, but they are secondary compared to my concern with two wallets.

@jonatack
Copy link
Member

jonatack commented Sep 2, 2021

Concept ACK, very nice.

@michaelfolkson
Copy link

Concept ACK. Functional test is nice addition.

wallet_multisig_descriptor_psbt.py is refactored in this commit. While
behavior doesn't change we do cleanup the way wallets are accessed
throughout the test as this is done a lot for the various signers
and their multisigs. We also get rid of some shallow methods and
instead inline them for improved readability.

descriptors.md is improved to be more explicit about which wallet
(ie the signer or multisig) is required for each step.
@mjdietzx
Copy link
Contributor Author

mjdietzx commented Sep 3, 2021

@S3RK thank you for the review and great suggestions.

Because I feel this PR is already pretty far along and has a lot of reviews, I addressed your minor/refactor comments in an additional commit: f9479e4. I thought this made most sense, but I can squash it into 1f20501 (and the doc changes into 17dd657) if I get some comments suggesting that'd be better.

As for your main concern:

Why not have just one wallet? Having two wallets is less intuitive, complicates backups and could lead to user confusion and even loss of funds. Especially taking into account that you need to backup both wallets to restore your funds. This doesn't come through the documentation.

I think it's a great point. And your ideas on how to do this are really good. I have plans to add test coverage and capabilities to multsigs like this. And it's something I will try out and hopefully have a followup PR for. But for this PR I want to keep things as basic and simple as possible. Therefore I am shelving this (unless someone else gets to it first), but will def follow up (whether as an author or reviewer). For now though, I thought it was best (and good in general) to add a disclaimer in the docs: 9de0d94 highlighting some shortcomings of this basic example

@S3RK
Copy link
Contributor

S3RK commented Sep 16, 2021

@mjdietzx thanks for addressing my nits.

The rest is just my opinion and I don't know what other contributors think about it.

I understand that you want to keep things simple, but we shouldn't sacrifice safety for it. The key problem is separation of multisig metadata (i.e. descriptor with other xpubs and derivation paths) and the keys. These things are pointless on their own and I'm not comfortable ACKing an approach where we separate them into two wallets. You can ignore the rest of my suggestions to disable descriptors or use temporary wallet to generate xprv. Agree, this is all icing on a cake.

From user perspective one wallet is simpler than two. So I don't think workflow with one wallet will be overall more complicated than with two.

Happy to help with implementation or advice.

@Rspigler
Copy link
Contributor

I think how it is done currently with 2 wallets is better for same reasons as described here

@S3RK
Copy link
Contributor

S3RK commented Sep 27, 2021

@Rspigler that's a good argument. I need to think about it more and will come back with a reply

@S3RK
Copy link
Contributor

S3RK commented Oct 7, 2021

Code review ACK 9de0d94. Rspigler's argument convinced me that we should leave the workflow with two wallets. I assume using multisig with external signers is a popular use-case and it's important to keep compatibility.

Edit@laanwj: removed @ from ACK message for merge

@laanwj
Copy link
Member

laanwj commented Oct 13, 2021

Thanks for adding this example, and the test. I was initially confused by the need to use two wallets but I understand it.

Code and documentation review ACK 9de0d94

@laanwj laanwj merged commit ff65b69 into bitcoin:master Oct 18, 2021
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Oct 18, 2021
…descriptor wallets and PSBTs

9de0d94 doc: add disclaimer highlighting shortcomings of the basic multisig example (Michael Dietz)
f9479e4 test, doc: basic M-of-N multisig minor cleanup and clarifications (Michael Dietz)
e05cd05 doc: add another signing flow for multisig with descriptor wallets and PSBTs (Michael Dietz)
17dd657 doc: M-of-N multisig using descriptor wallets and PSBTs, as well as a signing flow (Michael Dietz)
1f20501 test: add functional test for multisig flow with descriptor wallets and PSBTs (Michael Dietz)

Pull request description:

  Aims to resolve issue bitcoin#21278. I try to follow the steps laanwj outlined there exactly, with the exception of using `combinepsbt` instead of `joinpsbts`. I wrote a functional test to make sure it works as expected before doing the docs, and figured it would also be a good source of documentation. So I kept the test as simple as possible and didn't go crazy with edge-cases and various checks. I do have a lot more test-cases I've written that I will follow up with (either in a separate PR or another commit - lmk if you have a preference), but I want to do it in a way that doesn't bloat this test so it remains useful as a quickstart (unless that's a bad idea)?

ACKs for top commit:
  S3RK:
    Code review ACK 9de0d94. Rspigler's argument convinced me that we should leave the workflow with two wallets. I assume using multisig with external signers is a popular use-case and it's important to keep compatibility.
  laanwj:
    Code and documentation review ACK 9de0d94

Tree-SHA512: 6c76e787c21f09d8be5eaa11f3ca3eaa4868497824050562bdfb2095c73b90f5e8987a8775119891d6bfde586e3f31ad1b13e4b67b0802e1d23ef050227a1211
@hebasto
Copy link
Member

hebasto commented Oct 18, 2021

@hebasto
Copy link
Member

hebasto commented Oct 18, 2021

It looks some CI task fail: https://cirrus-ci.com/build/6343453790437376

Conflict with #23207?

Should be fixed in #23303.

maflcko pushed a commit to bitcoin-core/gui that referenced this pull request Oct 19, 2021
…t.py

ffdd94d test: Fix wallet_multisig_descriptor_psbt.py (Hennadii Stepanov)

Pull request description:

  The `wallet_multisig_descriptor_psbt.py`, which was introduced in the recent bitcoin/bitcoin#22067, has a merge conflict with the previously merged bitcoin/bitcoin#23207.

  Fixed in this PR.

ACKs for top commit:
  mjdietzx:
    Tested ACK ffdd94d
  S3RK:
    ACK ffdd94d

Tree-SHA512: e8871aeebbe119e22347de19f62b4524e191885d66f94af802a33793dfa413790901fd54aeea1ab3d1b1487cb457e8a58b0aef19d0dc78b12a583646ba4af67e
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Oct 19, 2021
ffdd94d test: Fix wallet_multisig_descriptor_psbt.py (Hennadii Stepanov)

Pull request description:

  The `wallet_multisig_descriptor_psbt.py`, which was introduced in the recent bitcoin#22067, has a merge conflict with the previously merged bitcoin#23207.

  Fixed in this PR.

ACKs for top commit:
  mjdietzx:
    Tested ACK ffdd94d
  S3RK:
    ACK ffdd94d

Tree-SHA512: e8871aeebbe119e22347de19f62b4524e191885d66f94af802a33793dfa413790901fd54aeea1ab3d1b1487cb457e8a58b0aef19d0dc78b12a583646ba4af67e
# This wallet will be the participant's `signer` for the resulting multisig. Avoid reusing this wallet for any other purpose (for privacy reasons).
"signers": [node.get_wallet_rpc(node.createwallet(wallet_name=f"participant_{self.nodes.index(node)}", descriptors=True)["name"]) for node in self.nodes],
# After participants generate and exchange their xpubs they will each create their own watch-only multisig.
# Note: these multisigs are all the same, this justs highlights that each participant can independently verify everything on their own node.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: justs ==> just

@hebasto hebasto mentioned this pull request Nov 13, 2021
maflcko pushed a commit to bitcoin-core/gui that referenced this pull request Dec 14, 2021
1ef2c03 Add multisig tutorial (lsilva01)

Pull request description:

  This PR adds a mutisig tutorial, as requested in bitcoin/bitcoin#21278

  Although there is already a brief explanation and a functional test about the multisig implemented in bitcoin/bitcoin#22067, this tutorial proposes to use the signet (instead of regtest), bringing the reader closer to a real environment and explaining some functions in more detail.

  I'm not sure if this format should be in this repository or on some wiki page. But as there is an open issue regarding this matter, that is my suggestion.

ACKs for top commit:
  Sjors:
    re-utACK 1ef2c03
  prayank23:
    ACK bitcoin/bitcoin@1ef2c03

Tree-SHA512: 2c3f17a8c50e554f802029dceb28ab90a77021f135b8cbd77dca3879ba1f1a0eac6bda0afb90d1ff6b8116fb0628471687d3fb77bb255ef5d8b9590b775cbce9
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Dec 14, 2021
1ef2c03 Add multisig tutorial (lsilva01)

Pull request description:

  This PR adds a mutisig tutorial, as requested in bitcoin#21278

  Although there is already a brief explanation and a functional test about the multisig implemented in bitcoin#22067, this tutorial proposes to use the signet (instead of regtest), bringing the reader closer to a real environment and explaining some functions in more detail.

  I'm not sure if this format should be in this repository or on some wiki page. But as there is an open issue regarding this matter, that is my suggestion.

ACKs for top commit:
  Sjors:
    re-utACK 1ef2c03
  prayank23:
    ACK bitcoin@1ef2c03

Tree-SHA512: 2c3f17a8c50e554f802029dceb28ab90a77021f135b8cbd77dca3879ba1f1a0eac6bda0afb90d1ff6b8116fb0628471687d3fb77bb255ef5d8b9590b775cbce9
@bitcoin bitcoin locked and limited conversation to collaborators Nov 7, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.