-
Notifications
You must be signed in to change notification settings - Fork 38.7k
Test and document a basic M-of-N multisig using descriptor wallets and PSBTs #22067
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test and document a basic M-of-N multisig using descriptor wallets and PSBTs #22067
Conversation
ec90947 to
648d111
Compare
648d111 to
4069660
Compare
Sjors
left a comment
There was a problem hiding this 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
69b071e to
178681b
Compare
|
Thanks for the thorough review and suggestions @Sjors ! I've addressed all your feedback in my latest push.
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
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? |
178681b to
932de9b
Compare
|
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. |
|
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:
{
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: [ {} ],
}
...
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 |
|
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. |
|
Thanks for the explanation and links, very helpful. I'll look into all of this more.
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):
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) |
|
@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. |
Isn't that checked against here, where every participant checks the PSBT w/ |
|
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. |
lsilva01
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested ACK 932de9b
|
Concept ACK |
|
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):
I agree this is the case for now, but hopefully in the future Bitcoin Core can be a full fledged coordinator.
This isn't the proper way to write two descriptors (see here). I think using a descriptor template would be better. |
932de9b to
13edc4d
Compare
|
@Rspigler Thanks for the review, re point 2:
|
|
@laanwj If you have a chance can you give this a quick review? |
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:
And maybe templates not be mentioned at all. Sorry for flip flopping on you |
13edc4d to
d1ce7bb
Compare
|
Good point @Rspigler I removed the descriptor templates, but fixed as you suggest: 911ed48#diff-00ec9f97461f6bb94a37daf8069e5acf832ea4d5a31a8d7d4968c285d2fcac9bR144 |
|
ACK d1ce7bb4fb1f8cd929e23eae7aa9dd0862e938f2 (doc changes; not yet fully comfortable with my understanding of the tests in Core). |
|
ACK d1ce7bb (tests pass) |
lsilva01
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reACK d1ce7bb
|
ACK e05cd05 |
|
Started review |
|
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) |
S3RK
left a comment
There was a problem hiding this 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:
- Import multisig descriptor into the wallet you used to generate xpub. You can do it by taking your
xprivand others'xpub. Additionally you can disable the original descriptors. The downside you'd have disabled and unused descriptors lingering in the wallet. - 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.
|
Concept ACK, very nice. |
|
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.
|
@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:
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 |
|
@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. |
|
I think how it is done currently with 2 wallets is better for same reasons as described here |
|
@Rspigler that's a good argument. I need to think about it more and will come back with a reply |
|
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 |
|
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 |
…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
|
It looks some CI task fail: https://cirrus-ci.com/build/6343453790437376 Conflict with #23207? |
Should be fixed in #23303. |
…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
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: justs ==> just
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
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
Aims to resolve issue #21278. I try to follow the steps laanwj outlined there exactly, with the exception of using
combinepsbtinstead ofjoinpsbts. 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)?