Crate sapio_miniscript
source ·Expand description
Miniscript and Output Descriptors
Introduction
Bitcoin Script
In Bitcoin, spending policies are defined and enforced by means of a stack-based programming language known as Bitcoin Script. While this language appears to be designed with tractable analysis in mind (e.g. there are no looping or jumping constructions), in practice this is extremely difficult. As a result, typical wallet software supports only a small set of script templates, cannot interoperate with other similar software, and each wallet contains independently written ad-hoc manually verified code to handle these templates. Users who require more complex spending policies, or who want to combine signing infrastructure which was not explicitly designed to work together, are simply out of luck.
Miniscript
Miniscript is an alternative to Bitcoin Script which eliminates these problems. It can be efficiently and simply encoded as Script to ensure that it works on the Bitcoin blockchain, but its design is very different. Essentially, a Miniscript is a monotone function (tree of ANDs, ORs and thresholds) of signature requirements, hash preimage requirements, and timelocks.
A full description of Miniscript is available here.
Miniscript also admits a more human-readable encoding.
Output Descriptors
While spending policies in Bitcoin are entirely defined by Script; there are multiple ways of embedding these Scripts in transaction outputs; for example, P2SH or Segwit v0. These different embeddings are expressed by Output Descriptors, which are described here
Examples
Deriving an address from a descriptor
extern crate bitcoin;
extern crate sapio_miniscript as miniscript;
use std::str::FromStr;
use miniscript::{DescriptorTrait};
fn main() {
let desc = miniscript::Descriptor::<
bitcoin::PublicKey,
>::from_str("\
sh(wsh(or_d(\
c:pk_k(020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261),\
c:pk_k(0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352)\
)))\
").unwrap();
// Derive the P2SH address
assert_eq!(
desc.address(bitcoin::Network::Bitcoin).unwrap().to_string(),
"3CJxbQBfWAe1ZkKiGQNEYrioV73ZwvBWns"
);
// Check whether the descriptor is safe
// This checks whether all spend paths are accessible in bitcoin network.
// It maybe possible that some of the spend require more than 100 elements in Wsh scripts
// Or they contain a combination of timelock and heightlock.
assert!(desc.sanity_check().is_ok());
// Estimate the satisfaction cost
assert_eq!(desc.max_satisfaction_weight().unwrap(), 293);
}
Re-exports
pub extern crate bitcoin;
pub use descriptor::Descriptor;
pub use descriptor::DescriptorPublicKey;
pub use descriptor::DescriptorTrait;
pub use interpreter::Interpreter;
pub use miniscript::decode::Terminal;
pub use miniscript::satisfy::Preimage32;
pub use miniscript::satisfy::Satisfier;
pub use miniscript::Miniscript;
Modules
- Output Descriptors
- Function-like Expression Language
- Interpreter
- Abstract Syntax Tree
- Script Policies
- Partially-Signed Bitcoin Transactions
Structs
- Dummy key which de/serializes to the empty string; useful sometimes for testing
- Dummy keyhash which de/serializes to the empty string; useful sometimes for testing
Enums
- Bare ScriptContext To be used as raw script pubkeys In general, it is not recommended to use Bare descriptors as they as strongly limited by standardness policies.
- Miniscript
- Either a key or a keyhash
- Legacy ScriptContext To be used as P2SH scripts For creation of Bare scriptpubkeys, construct the Miniscript under
Bare
ScriptContext - Script descriptor
- Segwitv0 ScriptContext
- Tap ScriptContext
Traits
- Trait describing the ability to iterate over every key
- Public key trait which can be converted to Hash type
- A general trait for Pre taproot bitcoin descriptor. Similar to
DescriptorTrait
, butexplicit_script
andscript_code
methods cannot fail - The ScriptContext for Miniscript. Additional type information associated with miniscript that is used for carrying out checks that dependent on the context under which the script is used. For example, disallowing uncompressed keys in Segwit context
- Trait describing public key types which can be converted to bitcoin pubkeys
- Convert a descriptor using abstract keys to one using specific keys This will panic if translatefpk returns an uncompressed key when converting to a Segwit descriptor. To prevent this panic, ensure translatefpk returns an error in this case instead.
- Variant of
TranslatePk
where P and Q both have the same hash type, and the hashes can be converted by just cloning them - Variant of
TranslatePk
where P’s hash is P, so the hashes can be converted by reusing the key-conversion function - Variant of
TranslatePk
where Q’s hash ishash160
so we can derive hashes by callinghash_to_hash160
Functions
- The size of an encoding of a number in Script