Skip to content

Commit a156214

Browse files
Policy to single-leaf TapTree compilation done
1 parent 6d920ed commit a156214

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

src/policy/compiler.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::convert::From;
2222
use std::marker::PhantomData;
2323
use std::{cmp, error, f64, fmt, mem};
2424

25+
use miniscript::context::SigType;
2526
use miniscript::limits::MAX_PUBKEYS_PER_MULTISIG;
2627
use miniscript::types::{self, ErrorKind, ExtData, Property, Type};
2728
use miniscript::ScriptContext;
@@ -994,7 +995,9 @@ where
994995
})
995996
.collect();
996997

997-
if key_vec.len() == subs.len() && subs.len() <= MAX_PUBKEYS_PER_MULTISIG {
998+
if Ctx::sig_type() == SigType::Schnorr {
999+
insert_wrap!(AstElemExt::terminal(Terminal::MultiA(k, key_vec)));
1000+
} else if key_vec.len() == subs.len() && subs.len() <= MAX_PUBKEYS_PER_MULTISIG {
9981001
insert_wrap!(AstElemExt::terminal(Terminal::Multi(k, key_vec)));
9991002
}
10001003
// Not a threshold, it's always more optimal to translate it to and()s as we save the
@@ -1168,7 +1171,7 @@ mod tests {
11681171

11691172
use miniscript::{satisfy, Legacy, Segwitv0};
11701173
use policy::Liftable;
1171-
use script_num_size;
1174+
use {script_num_size, Tap};
11721175

11731176
type SPolicy = Concrete<String>;
11741177
type BPolicy = Concrete<bitcoin::PublicKey>;
@@ -1554,6 +1557,17 @@ mod tests {
15541557
))
15551558
);
15561559
}
1560+
1561+
#[test]
1562+
fn compile_tr_thresh() {
1563+
for k in 1..4 {
1564+
let small_thresh: Concrete<String> =
1565+
policy_str!("{}", &format!("thresh({},pk(B),pk(C),pk(D))", k));
1566+
let small_thresh_ms: Miniscript<String, Tap> = small_thresh.compile().unwrap();
1567+
let small_thresh_ms_expected: Miniscript<String, Tap> = ms_str!("multi_a({},B,C,D)", k);
1568+
assert_eq!(small_thresh_ms, small_thresh_ms_expected);
1569+
}
1570+
}
15571571
}
15581572

15591573
#[cfg(all(test, feature = "unstable"))]

src/policy/concrete.rs

+36
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@
1818
use bitcoin::hashes::hex::FromHex;
1919
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d};
2020
use std::collections::HashSet;
21+
#[cfg(feature = "compiler")]
22+
use std::sync::Arc;
2123
use std::{error, fmt, str};
2224

2325
use super::ENTAILMENT_MAX_TERMINALS;
26+
#[cfg(feature = "compiler")]
27+
use descriptor::TapTree;
2428
use errstr;
2529
use expression::{self, FromTree};
2630
use miniscript::limits::{HEIGHT_TIME_THRESHOLD, SEQUENCE_LOCKTIME_TYPE_FLAG};
@@ -32,8 +36,13 @@ use policy::compiler;
3236
#[cfg(feature = "compiler")]
3337
use policy::compiler::CompilerError;
3438
#[cfg(feature = "compiler")]
39+
use Descriptor;
40+
#[cfg(feature = "compiler")]
3541
use Miniscript;
42+
#[cfg(feature = "compiler")]
43+
use Tap;
3644
use {Error, ForEach, ForEachKey, MiniscriptKey};
45+
3746
/// Concrete policy which corresponds directly to a Miniscript structure,
3847
/// and whose disjunctions are annotated with satisfaction probabilities
3948
/// to assist the compiler
@@ -128,6 +137,33 @@ impl fmt::Display for PolicyError {
128137
}
129138

130139
impl<Pk: MiniscriptKey> Policy<Pk> {
140+
/// Single-Node compilation
141+
#[cfg(feature = "compiler")]
142+
fn compile_huffman_taptree(policy: &Self) -> Result<TapTree<Pk>, Error> {
143+
let compilation = policy.compile::<Tap>().unwrap();
144+
Ok(TapTree::Leaf(Arc::new(compilation)))
145+
}
146+
/// Extract the Taproot internal_key from policy tree.
147+
#[cfg(feature = "compiler")]
148+
fn extract_key(policy: &Self, unspendable_key: Option<Pk>) -> Result<(Pk, &Policy<Pk>), Error> {
149+
match unspendable_key {
150+
Some(key) => Ok((key, policy)),
151+
None => Err(errstr("No internal key found")),
152+
}
153+
}
154+
155+
/// Compile the [`Tr`] descriptor into optimized [`TapTree`] implementation
156+
#[cfg(feature = "compiler")]
157+
pub fn compile_tr(&self, unspendable_key: Option<Pk>) -> Result<Descriptor<Pk>, Error> {
158+
let (internal_key, policy) = Self::extract_key(self, unspendable_key).unwrap();
159+
let tree = Descriptor::new_tr(
160+
internal_key,
161+
Some(Self::compile_huffman_taptree(policy).unwrap()),
162+
)
163+
.unwrap();
164+
Ok(tree)
165+
}
166+
131167
/// Compile the descriptor into an optimized `Miniscript` representation
132168
#[cfg(feature = "compiler")]
133169
pub fn compile<Ctx: ScriptContext>(&self) -> Result<Miniscript<Pk, Ctx>, CompilerError> {

src/policy/mod.rs

+22
Original file line numberDiff line numberDiff line change
@@ -233,8 +233,14 @@ mod tests {
233233
Concrete, Liftable, Semantic,
234234
};
235235
use bitcoin;
236+
#[cfg(feature = "compiler")]
237+
use descriptor::TapTree;
236238
use std::str::FromStr;
239+
#[cfg(feature = "compiler")]
240+
use std::sync::Arc;
237241
use DummyKey;
242+
#[cfg(feature = "compiler")]
243+
use {Descriptor, Tap};
238244

239245
type ConcretePol = Concrete<DummyKey>;
240246
type SemanticPol = Semantic<DummyKey>;
@@ -364,4 +370,20 @@ mod tests {
364370
ms_str.lift().unwrap()
365371
);
366372
}
373+
374+
#[test]
375+
#[cfg(feature = "compiler")]
376+
fn single_leaf_tr_compile() {
377+
for k in 1..5 {
378+
let unspendable_key: String = "z".to_string();
379+
let policy: Concrete<String> = policy_str!("thresh({},pk(A),pk(B),pk(C),pk(D))", k);
380+
let descriptor = policy.compile_tr(Some(unspendable_key.clone())).unwrap();
381+
382+
let ms_compilation: Miniscript<String, Tap> = ms_str!("multi_a({},A,B,C,D)", k);
383+
let tree: TapTree<String> = TapTree::Leaf(Arc::new(ms_compilation));
384+
let expected_descriptor = Descriptor::new_tr(unspendable_key, Some(tree)).unwrap();
385+
386+
assert_eq!(descriptor, expected_descriptor);
387+
}
388+
}
367389
}

0 commit comments

Comments
 (0)