descriptors.md raw

Support for Output Descriptors in Bitcoin Core

Many Bitcoin Core RPCs support Output Descriptors. This is a simple language which can be used to describe collections of output scripts. The wallet code internally stores and operates on these descriptors to reason about the sets of outputs that belong to the wallet.

This document describes the language. For the specifics on usage, see the RPC documentation.

Features

Output descriptors currently support:

Examples

Reference

Descriptors consist of several types of expressions. The top level expression is either a SCRIPT, or SCRIPT#CHECKSUM where CHECKSUM is an 8-character alphanumeric descriptor checksum.

SCRIPT expressions, defined in BIP 380:

KEY expressions, defined in BIP 380:

- An open bracket [ - Exactly 8 hex characters for the fingerprint of the key where the derivation starts (see BIP 32) - Followed by zero or more /NUM or /NUM' path elements to indicate unhardened or hardened derivation steps between the fingerprint and the key or xpub/xprv root that follows - A closing bracket ]

- Hex encoded public keys (either 66 characters starting with 02 or 03 for a compressed pubkey, or 130 characters starting with 04 for an uncompressed pubkey). - Inside wpkh and wsh, only compressed public keys are permitted. - Inside tr and rawtr, x-only pubkeys are also permitted (64 hex characters). - WIF encoded private keys may be specified instead of the corresponding public key, with the same meaning. - xpub encoded extended public key or xprv encoded extended private key (as defined in BIP 32). - Followed by zero or more /NUM unhardened and /NUM' hardened BIP32 derivation steps. - No more than one of these derivation steps may be of the form <NUM;NUM;...;NUM> (including hardened indicators with either or both NUM). If such specifiers are included, the descriptor will be parsed as multiple descriptors where the first descriptor uses all of the first NUM in the pair, and the second descriptor uses the second NUM in the pair for all KEY expressions, and so on. Defined in BIP 389. - Optionally followed by a single /* or /*' final step to denote all (direct) unhardened or hardened children. - The usage of hardened derivation steps requires providing the private key. - musig(KEY,KEY,...) to represent the MuSig2 key aggregation of the relevant keys, only inside tr() expressions. It may be followed by unhardened /NUM derivation steps if all KEY subexpressions are xpubs or derived thereof, and none use /* or /<NUM;NUM;...>. Defined in BIP 390.

(Anywhere a ' suffix is permitted to denote hardened derivation, the suffix h can be used instead.)

TREE expressions, defined in BIP 386:

ADDR expressions are any type of supported address, defined in BIP 385:

Explanation

Single-key scripts

Many single-key constructions are used in practice, generally including P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH. Many more combinations are imaginable, though they may not be optimal: P2SH-P2PK, P2SH-P2PKH, P2WSH-P2PK, P2WSH-P2PKH, P2SH-P2WSH-P2PK, P2SH-P2WSH-P2PKH.

To describe these, we model these as functions. The functions pk (P2PK), pkh (P2PKH) and wpkh (P2WPKH) take as input a KEY expression, and return the corresponding scriptPubKey. The functions sh (P2SH) and wsh (P2WSH) take as input a SCRIPT expression, and return the script describing P2SH and P2WSH outputs with the input as embedded script. The names of the functions do not contain "p2" for brevity.

Multisig

Several pieces of software use multi-signature (multisig) scripts based on Bitcoin's OP_CHECKMULTISIG opcode. To support these, we introduce the multi(k,key_1,key_2,...,key_n) and sortedmulti(k,key_1,key_2,...,key_n) functions. They represent a k-of-n multisig policy, where any k out of the n provided KEY expressions must sign.

Key order is significant for multi(). A multi() expression describes a multisig script with keys in the specified order, and in a search for TXOs, it will not match outputs with multisig scriptPubKeys that have the same keys in a different order. Also, to prevent a combinatorial explosion of the search space, if more than one of the multi() key arguments is a BIP32 wildcard path ending in /* or *', the multi() expression only matches multisig scripts with the ith child key from each wildcard path in lockstep, rather than scripts with any combination of child keys from each wildcard path.

Key order does not matter for sortedmulti(). sortedmulti() behaves in the same way 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.

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 a single multipath descriptor: wsh(sortedmulti(<M>,XPUB1/<0;1>/*,XPUB2/<0;1>/*,…,XPUBN/<0;1>/*)) This single descriptor specifies both receiving (/0) and change (/1) addresses. Every participant does this. All key origin information (master key fingerprint and all derivation steps) should be included with xpubs for proper support of hardware devices / external signers 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 (mth) 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 is meant to be documentation as much as it is a functional test, so it is kept as simple and readable as possible.

Basic Miniscript-enabled "decaying" multisig example

For an example of a multisig that starts as 4-of-4 and "decays" to 3-of-4, 2-of-4, and finally 1-of-4 at each future halvening block height, see this functional test.

This has the same "architecture" and signing flow as the above Basic multisig example. The basic steps are identical aside from the descriptor that defines this wallet, which is of the form: wsh(thresh(4,pk(XPUB1),s:pk(XPUB2),s:pk(XPUB3),s:pk(XPUB4),sln:after(t1),sln:after(t2),sln:after(t3))).

The test 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 BIP32 ("HD keys"). We support these directly by permitting strings consisting of an extended public key (commonly referred to as an xpub) plus derivation path anywhere a public key is expected. The derivation path consists of a sequence of 0 or more integers (in the range 0..2<sup>31</sup>-1) each optionally followed by ' or h, and separated by / characters. The string may optionally end with the literal /* or /*' (or /*h) to refer to all unhardened or hardened child keys in a configurable range (by default 0-1000, inclusive).

Whenever a public key is described using a hardened derivation step, the script cannot be computed without access to the corresponding private key.

Key origin identification

In order to describe scripts whose signing keys reside on another device, it may be necessary to identify the master key and derivation path an xpub was derived with.

For example, when following BIP44, it would be useful to describe a change chain directly as xpub.../44'/0'/0'/1/* where xpub... corresponds with the master key m. Unfortunately, since there are hardened derivation steps that follow the xpub, this descriptor does not let you compute scripts without access to the corresponding private keys. Instead, it should be written as xpub.../1/*, where xpub corresponds to m/44'/0'/0'.

When interacting with a hardware device, it may be necessary to include the entire path from the master down. BIP 174 standardizes this by providing the master key fingerprint (first 32 bits of the Hash160 of the master pubkey), plus all derivation steps. To support constructing these, we permit providing this key origin information inside the descriptor language, even though it does not affect the actual scriptPubKeys it refers to.

Every public key can be prefixed by an 8-character hexadecimal fingerprint plus optional derivation steps (hardened and unhardened) surrounded by brackets, identifying the master and derivation path the key or xpub that follows was derived with.

Note that the fingerprint of the parent only serves as a fast way to detect parent and child nodes in software, and software must be willing to deal with collisions.

Including private keys

Often it is useful to communicate a description of scripts along with the necessary private keys. For this reason, anywhere a public key or xpub is supported, a private key in WIF format or xprv may be provided instead. This is useful when private keys are necessary for hardened derivation steps, for signing transactions, or for dumping wallet descriptors including private key material.

For example, after importing the following 2-of-3 multisig descriptor into a wallet, one could use signrawtransactionwithwallet to sign a transaction with the first key:

sh(multi(2,xprv.../84'/0'/0'/0/0,xpub1...,xpub2...))

Note how the first key is an xprv private key with a specific derivation path, while the other two are public keys.

Specifying receiving and change descriptors in one descriptor

Since receiving and change addresses are frequently derived from the same extended key(s) but with a single derivation index changed, it is convenient to be able to specify a descriptor that can derive at the two different indexes. Thus a single tuple of indexes is allowed in each derivation path following the extended key. When this descriptor is parsed, multiple descriptors will be produced, the first one will use the first index in the tuple for all key expressions, the second will use the second index, the third will use the third index, and so on..

For example, a descriptor of the form:

multi(2,xpub.../<0;1;2>/0/,xpub.../<2;3;4>/)

will expand to the 3 descriptors

multi(2,xpub.../0/0/,xpub.../2/) multi(2,xpub.../1/0/,xpub.../3/) multi(2,xpub.../2/0/,xpub.../4/)

When this tuple contains only two elements, wallet implementations can use the first descriptor for receiving addresses and the second descriptor for change addresses.

Compatibility with old wallets

In order to easily represent the sets of scripts currently supported by existing Bitcoin Core wallets, a convenience function combo is provided, which takes as input a public key, and describes a set of P2PK, P2PKH, P2WPKH, and P2SH-P2WPKH scripts for that key. In case the key is uncompressed, the set only includes P2PK and P2PKH scripts.

Checksums

Descriptors can optionally be suffixed with a checksum to protect against typos or copy-paste errors.

These checksums consist of 8 alphanumeric characters. As long as errors are restricted to substituting characters in 0123456789()[],'/*abcdefgh@:$%{} for others in that set and changes in letter case, up to 4 errors will always be detected in descriptors up to 501 characters, and up to 3 errors in longer ones. For larger numbers of errors, or other types of errors, there is a roughly 1 in a trillion chance of not detecting the errors.

All RPCs in Bitcoin Core will include the checksum in their output. Only certain RPCs require checksums on input, including deriveaddresses and importdescriptors. The checksum for a descriptor without one can be computed using the getdescriptorinfo RPC.