Skip to content

Commit 64e4545

Browse files
committed
Merge #519: Add some compiler documentation
360eed7 Add some compiler documentation (sanket1729) Pull request description: Fixes #128 ACKs for top commit: apoelstra: ACK 360eed7 Tree-SHA512: 70f544962ac824d0355d091d1c1dfc81b2e9f0d3896402c12911bae1e13b80b19fc90b43c5ad4a49d8c15e7edf6d6a6b543cdab915a003f0ae9be807f02dcbbf
2 parents bc687d2 + 360eed7 commit 64e4545

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

doc/compiler.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
## Miniscript Compiler
2+
3+
This library provides a Policy compiler that converts bitcoin Policy to Miniscript which can
4+
be used with "compiler" feature. The compiler offers a simple way to interface with
5+
Miniscript and often the first place beginners start to play with Miniscript. There are
6+
however several limitations and caveats to the compiler. This document tries to explain the compiler
7+
inner working as well as the guarantees it offers (or does not offer).
8+
9+
### The Miniscript compiler
10+
11+
As mentioned, the policy compiler takes in input a policy and converts it to a Miniscript. The
12+
compiler algorithm is essentially a brute force based algorithm with some heuristics to
13+
reduce the search space. For each sub-policy, and for each Miniscript type, satisfaction probability
14+
and dissatisfaction probability, the compiler tries to find a Miniscript that minimizes the spending
15+
weight. The spending weight is computed as
16+
17+
`spending_weight = spk_cost + witness_cost`
18+
19+
where `spk_cost` is the cost of the scriptPubKey and `witness_cost` is the expected cost of the witness
20+
with the given satisfaction and dissatisfaction probabilities.
21+
22+
### Compiler guarantees/limitations
23+
24+
If the compiler is able to output a Miniscript
25+
26+
- the Miniscript it produces is a valid Miniscript.
27+
- It also guarantees that the Miniscript produced will be spendable (assuming available witness) under the standardness rules.
28+
29+
The compiler does not guarantee that the Miniscript it produces is the most efficient Miniscript. It maybe possible
30+
to re-arrange the policy tree to produce a even more efficient Miniscript. When dealing with large policies, the compiler also does not guarantee that it will be able to produce a Miniscript even if there exists some Miniscript that can be used to spend the policy. The compiler also does not optimize 1 of n ORs or split thresh into respective ANDs and ORs. Overall, the compiler should be seen as doing a good enough job, but not the best possible job. In our experience, it is still almost always better than hand-written (mini)scripts or scripts. As an example, the compiler was able to produce better versions of lightning HTLC scripts than the ones designed by LN experts. See the following issues for more details: https://github.com/rust-bitcoin/rust-miniscript/issues/126 and https://github.com/rust-bitcoin/rust-miniscript/issues/114
31+
32+
It is possible that higher weight, but lower opcode exists sub-compilation might be best compilation, because the smaller weight sub-policy compilation that we chose exceeds the op-code count. There is also a similar issue with initial stack element count. The compiler does not try to optimize for these cases. If the final compiler output is not a valid Miniscript, it will simply fail and not try sub-optimal compilation that could fit inside these resource limits.
33+
34+
These problems are addressed to a large extent with taproot descriptors as the resource limitations are either really large or completely removed.
35+
This library also supports a taproot descriptor compiler. The details of taproot compiler are can be found in the [taproot compiler document](doc/taproot_compiler.md).
36+
37+
### Non-determinism and stability guarantees of compiler
38+
39+
The compiler outputs are not stable. They can change from version to version, machine to machine or even execution to execution on the same machine. The rust and C++ versions can produce different outputs even if the policy is the same. There could also be other implementations of compiler optimizing for different resource limits.
40+
However, the compiler will **always** output a valid Miniscript which might not be the same as some previous execution. As a simple example, `and_b(A,B)` could become `and_b(B,A)`. Therefore, it is **not recommended** to use policy as a stable identifier for a Miniscript. You should use the policy compiler once, and then use the Miniscript output as a stable identifier.

src/policy/concrete.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,13 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
483483
/// Compile the [`Policy`] into desc_ctx [`Descriptor`]
484484
///
485485
/// In case of [Tr][`DescriptorCtx::Tr`], `internal_key` is used for the Taproot comilation when
486-
/// no public key can be inferred from the given policy
486+
/// no public key can be inferred from the given policy.
487+
///
488+
/// # NOTE:
489+
///
490+
/// It is **not recommended** to use policy as a stable identifier for a miniscript.
491+
/// You should use the policy compiler once, and then use the miniscript output as a stable identifier.
492+
/// See the compiler document in doc/compiler.md for more details.
487493
#[cfg(feature = "compiler")]
488494
pub fn compile_to_descriptor<Ctx: ScriptContext>(
489495
&self,
@@ -506,6 +512,12 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
506512
}
507513

508514
/// Compile the descriptor into an optimized `Miniscript` representation
515+
///
516+
/// # NOTE:
517+
///
518+
/// It is **not recommended** to use policy as a stable identifier for a miniscript.
519+
/// You should use the policy compiler once, and then use the miniscript output as a stable identifier.
520+
/// See the compiler document in doc/compiler.md for more details.
509521
#[cfg(feature = "compiler")]
510522
pub fn compile<Ctx: ScriptContext>(&self) -> Result<Miniscript<Pk, Ctx>, CompilerError> {
511523
self.is_valid()?;

0 commit comments

Comments
 (0)