Skip to content

Commit 26fc574

Browse files
Policy to single-leaf TapTree compilation done
A new method `compile_tr` is introduced in policy for creating a Tr descriptor with TapTree containing single script child-node. An internal-key extraction method from the policy has also been implemented for the same.
1 parent 8062016 commit 26fc574

File tree

3 files changed

+67
-18
lines changed

3 files changed

+67
-18
lines changed

src/policy/compiler.rs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use std::marker::PhantomData;
2424
use std::sync::Arc;
2525
use std::{cmp, error, f64, fmt, hash, mem};
2626

27+
use crate::miniscript::context::SigType;
2728
use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG;
2829
use crate::miniscript::types::{self, ErrorKind, ExtData, Property, Type};
2930
use crate::miniscript::ScriptContext;
@@ -987,18 +988,23 @@ where
987988
})
988989
.collect();
989990

990-
if key_vec.len() == subs.len() && subs.len() <= MAX_PUBKEYS_PER_MULTISIG {
991-
insert_wrap!(AstElemExt::terminal(Terminal::Multi(k, key_vec)));
992-
}
993-
// Not a threshold, it's always more optimal to translate it to and()s as we save the
994-
// resulting threshold check (N EQUAL) in any case.
995-
else if k == subs.len() {
996-
let mut policy = subs.first().expect("No sub policy in thresh() ?").clone();
997-
for sub in &subs[1..] {
998-
policy = Concrete::And(vec![sub.clone(), policy]);
991+
match Ctx::sig_type() {
992+
SigType::Schnorr if key_vec.len() == subs.len() => {
993+
insert_wrap!(AstElemExt::terminal(Terminal::MultiA(k, key_vec)))
994+
}
995+
SigType::Ecdsa
996+
if key_vec.len() == subs.len() && subs.len() <= MAX_PUBKEYS_PER_MULTISIG =>
997+
{
998+
insert_wrap!(AstElemExt::terminal(Terminal::Multi(k, key_vec)))
999999
}
1000+
_ if k == subs.len() => {
1001+
let mut it = subs.iter();
1002+
let mut policy = it.next().expect("No sub policy in thresh() ?").clone();
1003+
policy = it.fold(policy, |acc, pol| Concrete::And(vec![acc, pol.clone()]));
10001004

1001-
ret = best_compilations(policy_cache, &policy, sat_prob, dissat_prob)?;
1005+
ret = best_compilations(policy_cache, &policy, sat_prob, dissat_prob)?;
1006+
}
1007+
_ => {}
10021008
}
10031009

10041010
// FIXME: Should we also optimize thresh(1, subs) ?
@@ -1549,6 +1555,17 @@ mod tests {
15491555
))
15501556
);
15511557
}
1558+
1559+
#[test]
1560+
fn compile_tr_thresh() {
1561+
for k in 1..4 {
1562+
let small_thresh: Concrete<String> =
1563+
policy_str!("{}", &format!("thresh({},pk(B),pk(C),pk(D))", k));
1564+
let small_thresh_ms: Miniscript<String, Tap> = small_thresh.compile().unwrap();
1565+
let small_thresh_ms_expected: Miniscript<String, Tap> = ms_str!("multi_a({},B,C,D)", k);
1566+
assert_eq!(small_thresh_ms, small_thresh_ms_expected);
1567+
}
1568+
}
15521569
}
15531570

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

src/policy/concrete.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,19 @@ use std::{error, fmt, str};
2020

2121
use bitcoin::hashes::hex::FromHex;
2222
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d};
23+
#[cfg(feature = "compiler")]
24+
use {
25+
crate::descriptor::TapTree, crate::miniscript::ScriptContext, crate::policy::compiler,
26+
crate::policy::compiler::CompilerError, crate::Descriptor, crate::Miniscript, crate::Tap,
27+
std::sync::Arc,
28+
};
2329

2430
use super::ENTAILMENT_MAX_TERMINALS;
2531
use crate::expression::{self, FromTree};
2632
use crate::miniscript::limits::{HEIGHT_TIME_THRESHOLD, SEQUENCE_LOCKTIME_TYPE_FLAG};
2733
use crate::miniscript::types::extra_props::TimeLockInfo;
28-
#[cfg(feature = "compiler")]
29-
use crate::miniscript::ScriptContext;
30-
#[cfg(feature = "compiler")]
31-
use crate::policy::compiler;
32-
#[cfg(feature = "compiler")]
33-
use crate::policy::compiler::CompilerError;
34-
#[cfg(feature = "compiler")]
35-
use crate::Miniscript;
3634
use crate::{errstr, Error, ForEach, ForEachKey, MiniscriptKey};
35+
3736
/// Concrete policy which corresponds directly to a Miniscript structure,
3837
/// and whose disjunctions are annotated with satisfaction probabilities
3938
/// to assist the compiler
@@ -128,6 +127,21 @@ impl fmt::Display for PolicyError {
128127
}
129128

130129
impl<Pk: MiniscriptKey> Policy<Pk> {
130+
/// Single-Node compilation
131+
#[cfg(feature = "compiler")]
132+
fn compile_leaf_taptree(&self) -> Result<TapTree<Pk>, Error> {
133+
let compilation = self.compile::<Tap>().unwrap();
134+
Ok(TapTree::Leaf(Arc::new(compilation)))
135+
}
136+
137+
/// Compile a [`Policy`] into a single-leaf [`TapTree`]
138+
#[cfg(feature = "compiler")]
139+
pub fn compile_tr(&self, unspendable_key: Option<Pk>) -> Result<Descriptor<Pk>, Error> {
140+
let internal_key = unspendable_key.ok_or(errstr("No internal key found"))?;
141+
let tree = Descriptor::new_tr(internal_key, Some(self.compile_leaf_taptree()?))?;
142+
Ok(tree)
143+
}
144+
131145
/// Compile the descriptor into an optimized `Miniscript` representation
132146
#[cfg(feature = "compiler")]
133147
pub fn compile<Ctx: ScriptContext>(&self) -> Result<Miniscript<Pk, Ctx>, CompilerError> {

src/policy/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,13 +225,17 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Concrete<Pk> {
225225
#[cfg(test)]
226226
mod tests {
227227
use std::str::FromStr;
228+
#[cfg(feature = "compiler")]
229+
use std::sync::Arc;
228230

229231
use bitcoin;
230232

231233
use super::super::miniscript::context::Segwitv0;
232234
use super::super::miniscript::Miniscript;
233235
use super::{Concrete, Liftable, Semantic};
234236
use crate::DummyKey;
237+
#[cfg(feature = "compiler")]
238+
use crate::{descriptor::TapTree, Descriptor, Tap};
235239

236240
type ConcretePol = Concrete<DummyKey>;
237241
type SemanticPol = Semantic<DummyKey>;
@@ -361,4 +365,18 @@ mod tests {
361365
ms_str.lift().unwrap()
362366
);
363367
}
368+
369+
#[test]
370+
#[cfg(feature = "compiler")]
371+
fn single_leaf_tr_compile() {
372+
let unspendable_key: String = "z".to_string();
373+
let policy: Concrete<String> = policy_str!("thresh(2,pk(A),pk(B),pk(C),pk(D))");
374+
let descriptor = policy.compile_tr(Some(unspendable_key.clone())).unwrap();
375+
376+
let ms_compilation: Miniscript<String, Tap> = ms_str!("multi_a(2,A,B,C,D)");
377+
let tree: TapTree<String> = TapTree::Leaf(Arc::new(ms_compilation));
378+
let expected_descriptor = Descriptor::new_tr(unspendable_key, Some(tree)).unwrap();
379+
380+
assert_eq!(descriptor, expected_descriptor);
381+
}
364382
}

0 commit comments

Comments
 (0)