Miniscript & output descriptors

Writing complex spending policies safely.

Raw Script is powerful but easy to get wrong. A small mistake can make coins unspendable, or spendable by the wrong person. Two tools make advanced wallets safer.

Output descriptors

A descriptor is a string that describes exactly which scripts a wallet owns:

  • wpkh(xpub…/0/*): native SegWit single-key.
  • wsh(multi(2,xpubA…,xpubB…,xpubC…)): 2-of-3 P2WSH multisig.
  • tr(KEY,{pk(A),pk(B)}): Taproot with a key path and two script leaves.

Key origins like [fingerprint/84h/0h/0h] tell signers which key to use, and a checksum after # catches typos. Descriptors are standardized in BIPs 380–386. Bitcoin Core wallets have been descriptor-based by default since version 23.

Miniscript

Miniscript, designed by Pieter Wuille, Andrew Poelstra and Sanket Kanjalkar and specified in BIP379, is a structured subset of Script. You write a policy:

or(pk(A), and(pk(B), older(12960)))

"A can spend at any time, or B can spend after 12,960 blocks (about 90 days)." A compiler turns this into a miniscript, which maps directly to Script. The result looks something like:

or_d(pk(A),and_v(v:pk(B),older(12960)))

Why it helps

  • Analyzable: software can calculate every way to spend, the maximum witness size (so fees can be estimated), and which keys are needed.
  • Composable: pieces like pk(), multi(), thresh(), older(), after() and sha256() fit together in a type-checked way.
  • Signer-friendly: any compliant wallet can sign for any miniscript without custom code, together with PSBTs.

Real-world use

Miniscript enables inheritance and decaying multisig wallets, such as "2-of-3 now, 1-of-3 after a year", which used to require custom scripts. Bitcoin Core supports miniscript in descriptors for P2WSH and Tapscript.

Limits

Miniscript covers most useful Script, but not every possible script. It also cannot prevent a bad policy, like giving the recovery key to the wrong person.