mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-09-21 19:31:34 +02:00
Merge bitcoin/bitcoin#22067: Test and document a basic M-of-N multisig using descriptor wallets and PSBTs
9de0d94508
doc: add disclaimer highlighting shortcomings of the basic multisig example (Michael Dietz)f9479e4626
test, doc: basic M-of-N multisig minor cleanup and clarifications (Michael Dietz)e05cd0546a
doc: add another signing flow for multisig with descriptor wallets and PSBTs (Michael Dietz)17dd657300
doc: M-of-N multisig using descriptor wallets and PSBTs, as well as a signing flow (Michael Dietz)1f20501efc
test: add functional test for multisig flow with descriptor wallets and PSBTs (Michael Dietz) Pull request description: Aims to resolve issue https://github.com/bitcoin/bitcoin/issues/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 ACK9de0d94
. 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 ACK9de0d94508
Tree-SHA512: 6c76e787c21f09d8be5eaa11f3ca3eaa4868497824050562bdfb2095c73b90f5e8987a8775119891d6bfde586e3f31ad1b13e4b67b0802e1d23ef050227a1211
This commit is contained in:
@@ -139,6 +139,47 @@ Key order does not matter for `sortedmulti()`. `sortedmulti()` behaves in the sa
|
||||
as `multi()` does but the keys are reordered in the resulting script such that they
|
||||
are lexicographically ordered as described in BIP67.
|
||||
|
||||
#### Basic multisig example
|
||||
|
||||
For a good example of a basic M-of-N multisig between multiple participants using descriptor
|
||||
wallets and PSBTs, as well as a signing flow, see [this functional test](/test/functional/wallet_multisig_descriptor_psbt.py).
|
||||
|
||||
Disclaimers: It is important to note that this example serves as a quick-start and is kept basic for readability. A downside of the approach
|
||||
outlined here is that each participant must maintain (and backup) two separate wallets: a signer and the corresponding multisig.
|
||||
It should also be noted that privacy best-practices are not "by default" here - participants should take care to only use the signer to sign
|
||||
transactions related to the multisig. Lastly, it is not recommended to use anything other than a Bitcoin Core descriptor wallet to serve as your
|
||||
signer(s). Other wallets, whether hardware or software, likely impose additional checks and safeguards to prevent users from signing transactions that
|
||||
could lead to loss of funds, or are deemed security hazards. Conforming to various 3rd-party checks and verifications is not in the scope of this example.
|
||||
|
||||
The basic steps are:
|
||||
|
||||
1. Every participant generates an xpub. The most straightforward way is to create a new descriptor wallet which we will refer to as
|
||||
the participant's signer wallet. Avoid reusing this wallet for any purpose other than signing transactions from the
|
||||
corresponding multisig we are about to create. Hint: 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)
|
||||
2. Create a watch-only descriptor wallet (blank, private keys disabled). Now the multisig is created by importing the two descriptors:
|
||||
`wsh(sortedmulti(<M>,XPUB1/0/*,XPUB2/0/*,…,XPUBN/0/*))` and `wsh(sortedmulti(<M>,XPUB1/1/*,XPUB2/1/*,…,XPUBN/1/*))`
|
||||
(one descriptor w/ `0` for receiving addresses and another w/ `1` for change). Every participant does this
|
||||
3. A receiving address is generated for the multisig. As a check to ensure step 2 was done correctly, every participant
|
||||
should verify they get the same addresses
|
||||
4. Funds are sent to the resulting address
|
||||
5. A sending transaction from the multisig is created using `walletcreatefundedpsbt` (anyone can initiate this). It is simple to do
|
||||
this in the GUI by going to the `Send` tab in the multisig wallet and creating an unsigned transaction (PSBT)
|
||||
6. At least `M` participants check the PSBT with their multisig using `decodepsbt` to verify the transaction is OK before signing it.
|
||||
7. (If OK) the participant signs the PSBT with their signer wallet using `walletprocesspsbt`. It is simple to do this in the GUI by
|
||||
loading the PSBT from file and signing it
|
||||
8. The signed PSBTs are collected with `combinepsbt`, finalized w/ `finalizepsbt`, and then the resulting transaction is broadcasted
|
||||
to the network. Note that any wallet (eg one of the signers or multisig) is capable of doing this.
|
||||
9. Checks that balances are correct after the transaction has been included in a block
|
||||
|
||||
You may prefer a daisy chained signing flow where each participant signs the PSBT one after another until
|
||||
the PSBT has been signed `M` times and is "complete." For the most part, the steps above remain the same, except (6, 7)
|
||||
change slightly from signing the original PSBT in parallel to signing it in series. `combinepsbt` is not necessary with
|
||||
this signing flow and the last (`m`th) signer can just broadcast the PSBT after signing. Note that a parallel signing flow may be
|
||||
preferable in cases where there are more signers. This signing flow is also included in the test / Python example.
|
||||
[The test](/test/functional/wallet_multisig_descriptor_psbt.py) is meant to be documentation as much as it is a functional test, so
|
||||
it is kept as simple and readable as possible.
|
||||
|
||||
### BIP32 derived keys and chains
|
||||
|
||||
Most modern wallet software and hardware uses keys that are derived using
|
||||
|
Reference in New Issue
Block a user