1use elements::Sequence;
14
15use crate::{error, fmt};
16
17#[cfg(feature = "compiler")]
18pub mod compiler;
19pub mod concrete;
20pub mod semantic;
21
22pub use self::concrete::Policy as Concrete;
23pub use self::semantic::Policy as Semantic;
26use crate::descriptor::{CovError, Descriptor};
27use crate::miniscript::{Miniscript, ScriptContext};
28use crate::{AbsLockTime, BtcPolicy, Error, Extension, MiniscriptKey, Terminal};
29
30const ENTAILMENT_MAX_TERMINALS: usize = 20;
32pub trait Liftable<Pk: MiniscriptKey> {
46 fn lift(&self) -> Result<Semantic<Pk>, Error>;
48}
49
50#[derive(Copy, Clone, PartialEq, Eq, Debug)]
52pub enum LiftError {
53 HeightTimelockCombination,
56 BranchExceedResourceLimits,
58 RawDescriptorLift,
60}
61
62impl fmt::Display for LiftError {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 match *self {
65 LiftError::HeightTimelockCombination => {
66 f.write_str("Cannot lift policies that have a heightlock and timelock combination")
67 }
68 LiftError::BranchExceedResourceLimits => f.write_str(
69 "Cannot lift policies containing one branch that exceeds resource limits",
70 ),
71 LiftError::RawDescriptorLift => f.write_str("Cannot lift raw descriptors"),
72 }
73 }
74}
75
76impl error::Error for LiftError {
77 fn cause(&self) -> Option<&dyn error::Error> {
78 use self::LiftError::*;
79
80 match self {
81 HeightTimelockCombination | BranchExceedResourceLimits | RawDescriptorLift => None,
82 }
83 }
84}
85
86impl<Pk: MiniscriptKey, Ctx: ScriptContext, Ext: Extension> Miniscript<Pk, Ctx, Ext> {
87 pub fn lift_check(&self) -> Result<(), LiftError> {
96 if !self.within_resource_limits() {
97 Err(LiftError::BranchExceedResourceLimits)
98 } else if self.has_mixed_timelocks() {
99 Err(LiftError::HeightTimelockCombination)
100 } else {
101 Ok(())
102 }
103 }
104}
105
106impl<Pk: MiniscriptKey, Ctx: ScriptContext, Ext: Extension> Liftable<Pk>
107 for Miniscript<Pk, Ctx, Ext>
108{
109 fn lift(&self) -> Result<Semantic<Pk>, Error> {
110 self.lift_check()?;
113 self.as_inner().lift()
114 }
115}
116
117impl<Pk, Ctx, Ext> Liftable<Pk> for Terminal<Pk, Ctx, Ext>
118where
119 Pk: MiniscriptKey,
120 Ctx: ScriptContext,
121 Ext: Extension,
122{
123 fn lift(&self) -> Result<Semantic<Pk>, Error> {
124 let ret = match *self {
125 Terminal::PkK(ref pk) | Terminal::PkH(ref pk) => Semantic::Key(pk.clone()),
126 Terminal::RawPkH(ref _pkh) => {
127 return Err(Error::LiftError(LiftError::RawDescriptorLift))
128 }
129 Terminal::After(t) => Semantic::After(t),
130 Terminal::Older(t) => Semantic::Older(t),
131 Terminal::Sha256(ref h) => Semantic::Sha256(h.clone()),
132 Terminal::Hash256(ref h) => Semantic::Hash256(h.clone()),
133 Terminal::Ripemd160(ref h) => Semantic::Ripemd160(h.clone()),
134 Terminal::Hash160(ref h) => Semantic::Hash160(h.clone()),
135 Terminal::False => Semantic::Unsatisfiable,
136 Terminal::True => Semantic::Trivial,
137 Terminal::Alt(ref sub)
138 | Terminal::Swap(ref sub)
139 | Terminal::Check(ref sub)
140 | Terminal::DupIf(ref sub)
141 | Terminal::Verify(ref sub)
142 | Terminal::NonZero(ref sub)
143 | Terminal::ZeroNotEqual(ref sub) => sub.node.lift()?,
144 Terminal::AndV(ref left, ref right) | Terminal::AndB(ref left, ref right) => {
145 Semantic::Threshold(2, vec![left.node.lift()?, right.node.lift()?])
146 }
147 Terminal::AndOr(ref a, ref b, ref c) => Semantic::Threshold(
148 1,
149 vec![
150 Semantic::Threshold(2, vec![a.node.lift()?, b.node.lift()?]),
151 c.node.lift()?,
152 ],
153 ),
154 Terminal::OrB(ref left, ref right)
155 | Terminal::OrD(ref left, ref right)
156 | Terminal::OrC(ref left, ref right)
157 | Terminal::OrI(ref left, ref right) => {
158 Semantic::Threshold(1, vec![left.node.lift()?, right.node.lift()?])
159 }
160 Terminal::Thresh(k, ref subs) => {
161 let semantic_subs: Result<_, Error> = subs.iter().map(|s| s.node.lift()).collect();
162 Semantic::Threshold(k, semantic_subs?)
163 }
164 Terminal::Multi(k, ref keys) | Terminal::MultiA(k, ref keys) => {
165 Semantic::Threshold(k, keys.iter().map(|k| Semantic::Key(k.clone())).collect())
166 }
167 Terminal::Ext(ref _e) => Err(Error::CovError(CovError::CovenantLift))?,
168 }
169 .normalized();
170 Ok(ret)
171 }
172}
173
174impl<Pk: MiniscriptKey, T: Extension> Liftable<Pk> for Descriptor<Pk, T> {
175 fn lift(&self) -> Result<Semantic<Pk>, Error> {
176 match *self {
177 Descriptor::Bare(ref bare) => bare.lift(),
178 Descriptor::Pkh(ref pkh) => pkh.lift(),
179 Descriptor::Wpkh(ref wpkh) => wpkh.lift(),
180 Descriptor::Wsh(ref wsh) => wsh.lift(),
181 Descriptor::Sh(ref sh) => sh.lift(),
182 Descriptor::LegacyCSFSCov(ref _cov) => Err(Error::CovError(CovError::CovenantLift)),
183 Descriptor::Tr(ref tr) => tr.lift(),
184 Descriptor::TrExt(ref tr) => tr.lift(),
185 }
186 }
187}
188
189impl<Pk: MiniscriptKey> Liftable<Pk> for Semantic<Pk> {
190 fn lift(&self) -> Result<Semantic<Pk>, Error> {
191 Ok(self.clone())
192 }
193}
194
195impl<Pk: MiniscriptKey> Liftable<Pk> for Concrete<Pk> {
196 fn lift(&self) -> Result<Semantic<Pk>, Error> {
197 self.check_timelocks()?;
200 let ret = match *self {
201 Concrete::Unsatisfiable => Semantic::Unsatisfiable,
202 Concrete::Trivial => Semantic::Trivial,
203 Concrete::Key(ref pk) => Semantic::Key(pk.clone()),
204 Concrete::After(t) => Semantic::After(t),
205 Concrete::Older(t) => Semantic::Older(t),
206 Concrete::Sha256(ref h) => Semantic::Sha256(h.clone()),
207 Concrete::Hash256(ref h) => Semantic::Hash256(h.clone()),
208 Concrete::Ripemd160(ref h) => Semantic::Ripemd160(h.clone()),
209 Concrete::Hash160(ref h) => Semantic::Hash160(h.clone()),
210 Concrete::And(ref subs) => {
211 let semantic_subs: Result<_, Error> = subs.iter().map(Liftable::lift).collect();
212 Semantic::Threshold(2, semantic_subs?)
213 }
214 Concrete::Or(ref subs) => {
215 let semantic_subs: Result<_, Error> =
216 subs.iter().map(|(_p, sub)| sub.lift()).collect();
217 Semantic::Threshold(1, semantic_subs?)
218 }
219 Concrete::Threshold(k, ref subs) => {
220 let semantic_subs: Result<_, Error> = subs.iter().map(Liftable::lift).collect();
221 Semantic::Threshold(k, semantic_subs?)
222 }
223 }
224 .normalized();
225 Ok(ret)
226 }
227}
228
229impl<Pk: MiniscriptKey> Liftable<Pk> for BtcPolicy<Pk> {
231 fn lift(&self) -> Result<Semantic<Pk>, Error> {
232 match self {
233 BtcPolicy::Unsatisfiable => Ok(Semantic::Unsatisfiable),
234 BtcPolicy::Trivial => Ok(Semantic::Trivial),
235 BtcPolicy::Key(ref pkh) => Ok(Semantic::Key(pkh.clone())),
236 BtcPolicy::Sha256(ref h) => Ok(Semantic::Sha256(h.clone())),
237 BtcPolicy::Hash256(ref h) => Ok(Semantic::Hash256(h.clone())),
238 BtcPolicy::Ripemd160(ref h) => Ok(Semantic::Ripemd160(h.clone())),
239 BtcPolicy::Hash160(ref h) => Ok(Semantic::Hash160(h.clone())),
240 BtcPolicy::After(n) => Ok(Semantic::After(AbsLockTime::from_consensus(
241 n.to_consensus_u32(),
242 ))),
243 BtcPolicy::Older(n) => Ok(Semantic::Older(Sequence(n.to_consensus_u32()))),
244 BtcPolicy::Thresh(t) => {
245 let new_subs: Result<Vec<Semantic<Pk>>, _> = t
246 .data()
247 .iter()
248 .map(|sub| Liftable::lift(sub.as_ref()))
249 .collect();
250 Ok(Semantic::Threshold(t.k(), new_subs?))
251 }
252 }
253 }
254}
255
256#[cfg(test)]
257mod tests {
258 use std::str::FromStr;
259 #[cfg(feature = "compiler")]
260 use std::sync::Arc;
261
262 use bitcoin;
263 use elements::Sequence;
264
265 use super::super::miniscript::context::Segwitv0;
266 use super::super::miniscript::Miniscript;
267 use super::{Concrete, Liftable, Semantic};
268 #[cfg(feature = "compiler")]
269 use crate::descriptor::Tr;
270 #[cfg(feature = "compiler")]
271 use crate::{descriptor::TapTree, Descriptor, Tap};
272
273 type ConcretePol = Concrete<String>;
274 type SemanticPol = Semantic<String>;
275
276 fn concrete_policy_rtt(s: &str) {
277 let conc = ConcretePol::from_str(s).unwrap();
278 let output = conc.to_string();
279 assert_eq!(s.to_lowercase(), output.to_lowercase());
280 }
281
282 fn semantic_policy_rtt(s: &str) {
283 let sem = SemanticPol::from_str(s).unwrap();
284 let output = sem.normalized().to_string();
285 assert_eq!(s.to_lowercase(), output.to_lowercase());
286 }
287
288 #[test]
289 fn test_timelock_validity() {
290 assert!(ConcretePol::from_str("after(100)").is_ok());
292 assert!(ConcretePol::from_str("after(1000000000)").is_ok());
294 assert!(ConcretePol::from_str("or(after(1000000000),after(100))").is_ok());
296 assert!(ConcretePol::from_str("and(after(1000000000),after(100))").is_err());
298 assert!(ConcretePol::from_str("thresh(1,pk(),after(1000000000),after(100))").is_ok());
300 assert!(ConcretePol::from_str("thresh(2,after(1000000000),after(100),pk())").is_err());
302 }
303 #[test]
304 fn policy_rtt_tests() {
305 concrete_policy_rtt("pk()");
306 concrete_policy_rtt("or(1@pk(),1@pk())");
307 concrete_policy_rtt("or(99@pk(),1@pk())");
308 concrete_policy_rtt("and(pk(),or(99@pk(),1@older(12960)))");
309
310 semantic_policy_rtt("pk()");
311 semantic_policy_rtt("or(pk(),pk())");
312 semantic_policy_rtt("and(pk(),pk())");
313
314 assert!(ConcretePol::from_str("thresh()").is_err());
316 assert!(SemanticPol::from_str("thresh(0)").is_err());
317 assert!(SemanticPol::from_str("thresh()").is_err());
318 concrete_policy_rtt("ripemd160()");
319 }
320
321 #[test]
322 fn compile_invalid() {
323 assert_eq!(
326 ConcretePol::from_str("thresh(2,pk(),thresh(0))")
327 .unwrap_err()
328 .to_string(),
329 "Threshold k must be greater than 0 and less than or equal to n 0<k<=n"
330 );
331 assert_eq!(
332 ConcretePol::from_str("thresh(2,pk(),thresh(0,pk()))")
333 .unwrap_err()
334 .to_string(),
335 "Threshold k must be greater than 0 and less than or equal to n 0<k<=n"
336 );
337 assert_eq!(
338 ConcretePol::from_str("and(pk())").unwrap_err().to_string(),
339 "And policy fragment must take 2 arguments"
340 );
341 assert_eq!(
342 ConcretePol::from_str("or(pk())").unwrap_err().to_string(),
343 "Or policy fragment must take 2 arguments"
344 );
345 assert_eq!(
346 ConcretePol::from_str("thresh(3,after(0),pk(),pk())")
347 .unwrap_err()
348 .to_string(),
349 "Time must be greater than 0; n > 0"
350 );
351
352 assert_eq!(
353 ConcretePol::from_str("thresh(2,older(2147483650),pk(),pk())")
354 .unwrap_err()
355 .to_string(),
356 "Relative/Absolute time must be less than 2^31; n < 2^31"
357 );
358 }
359
360 #[test]
362 fn heavy_nest() {
363 let policy_string = "thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk(),thresh(1,pk(),pk(),pk()))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))";
364 ConcretePol::from_str(policy_string).unwrap_err();
365 }
366
367 #[test]
368 fn lift_andor() {
369 let key_a: bitcoin::PublicKey =
370 "02d7924d4f7d43ea965a465ae3095ff41131e5946f3c85f79e44adbcf8e27e080e"
371 .parse()
372 .unwrap();
373 let key_b: bitcoin::PublicKey =
374 "03b506a1dbe57b4bf48c95e0c7d417b87dd3b4349d290d2e7e9ba72c912652d80a"
375 .parse()
376 .unwrap();
377
378 let ms_str: Miniscript<bitcoin::PublicKey, Segwitv0> = format!(
379 "andor(multi(1,{}),older(42),c:pk_k({}))",
380 key_a.inner, key_b.inner
381 )
382 .parse()
383 .unwrap();
384 assert_eq!(
385 Semantic::Threshold(
386 1,
387 vec![
388 Semantic::Threshold(
389 2,
390 vec![
391 Semantic::Key(key_a),
392 Semantic::Older(Sequence::from_height(42))
393 ]
394 ),
395 Semantic::Key(key_b)
396 ]
397 ),
398 ms_str.lift().unwrap()
399 );
400 }
401
402 #[test]
403 #[cfg(feature = "compiler")]
404 fn taproot_compile() {
405 let unspendable_key: String = "UNSPENDABLE".to_string();
407 {
408 let policy: Concrete<String> = policy_str!("thresh(2,pk(A),pk(B),pk(C),pk(D))");
409 let descriptor = policy.compile_tr(Some(unspendable_key.clone())).unwrap();
410
411 let ms_compilation: Miniscript<String, Tap> = ms_str!("multi_a(2,A,B,C,D)");
412 let tree: TapTree<String> = TapTree::Leaf(Arc::new(ms_compilation));
413 let expected_descriptor =
414 Descriptor::new_tr(unspendable_key.clone(), Some(tree)).unwrap();
415 assert_eq!(descriptor, expected_descriptor);
416 }
417
418 {
420 let policy: Concrete<String> = policy_str!("or(and(pk(A),pk(B)),and(pk(C),pk(D)))");
421 let descriptor = policy.compile_tr(Some(unspendable_key.clone())).unwrap();
422
423 let left_ms_compilation: Arc<Miniscript<String, Tap>> =
424 Arc::new(ms_str!("and_v(v:pk(C),pk(D))"));
425 let right_ms_compilation: Arc<Miniscript<String, Tap>> =
426 Arc::new(ms_str!("and_v(v:pk(A),pk(B))"));
427 let left_node: Arc<TapTree<String>> = Arc::from(TapTree::Leaf(left_ms_compilation));
428 let right_node: Arc<TapTree<String>> = Arc::from(TapTree::Leaf(right_ms_compilation));
429 let tree: TapTree<String> = TapTree::Tree(left_node, right_node);
430 let expected_descriptor =
431 Descriptor::new_tr(unspendable_key.clone(), Some(tree)).unwrap();
432 assert_eq!(descriptor, expected_descriptor);
433 }
434
435 {
436 let policy: Concrete<String> = policy_str!("or(and(pk(A),pk(B)),and(pk(A),pk(D)))");
438 let descriptor = policy.compile_tr(Some(unspendable_key.clone()));
439
440 assert_eq!(
441 descriptor.unwrap_err().to_string(),
442 "Policy contains duplicate keys"
443 );
444 }
445
446 {
448 let node_policies = [
449 "and(pk(A),pk(B))",
450 "and(pk(C),older(12960))",
451 "pk(D)",
452 "pk(E)",
453 "thresh(3,pk(F),pk(G),pk(H))",
454 "and(and(or(2@pk(I),1@pk(J)),or(1@pk(K),20@pk(L))),pk(M))",
455 "pk(N)",
456 ];
457
458 let node_probabilities: [f64; 7] =
460 [0.12000002, 0.28, 0.08, 0.12, 0.19, 0.18999998, 0.02];
461
462 let policy: Concrete<String> = policy_str!(
463 "{}",
464 &format!(
465 "or(4@or(3@{},7@{}),6@thresh(1,or(4@{},6@{}),{},or(9@{},1@{})))",
466 node_policies[0],
467 node_policies[1],
468 node_policies[2],
469 node_policies[3],
470 node_policies[4],
471 node_policies[5],
472 node_policies[6]
473 )
474 );
475 let descriptor = policy.compile_tr(Some(unspendable_key)).unwrap();
476
477 let mut sorted_policy_prob = node_policies
478 .iter()
479 .zip(node_probabilities.iter())
480 .collect::<Vec<_>>();
481 sorted_policy_prob.sort_by(|a, b| (a.1).partial_cmp(b.1).unwrap());
482 let sorted_policies = sorted_policy_prob
483 .into_iter()
484 .map(|(x, _prob)| x)
485 .collect::<Vec<_>>();
486
487 let node_compilations = sorted_policies
489 .into_iter()
490 .map(|x| {
491 let leaf_policy: Concrete<String> = policy_str!("{}", x);
492 TapTree::Leaf(Arc::from(leaf_policy.compile::<Tap>().unwrap()))
493 })
494 .collect::<Vec<_>>();
495
496 let tree = TapTree::Tree(
498 Arc::from(TapTree::Tree(
499 Arc::from(node_compilations[4].clone()),
500 Arc::from(node_compilations[5].clone()),
501 )),
502 Arc::from(TapTree::Tree(
503 Arc::from(TapTree::Tree(
504 Arc::from(TapTree::Tree(
505 Arc::from(node_compilations[0].clone()),
506 Arc::from(node_compilations[1].clone()),
507 )),
508 Arc::from(node_compilations[3].clone()),
509 )),
510 Arc::from(node_compilations[6].clone()),
511 )),
512 );
513
514 let expected_descriptor = Descriptor::new_tr("E".to_string(), Some(tree)).unwrap();
515 assert_eq!(descriptor, expected_descriptor);
516 }
517 }
518
519 #[test]
520 #[cfg(feature = "compiler")]
521 fn experimental_taproot_compile() {
522 let unspendable_key = "UNSPEND".to_string();
523
524 {
525 let pol = Concrete::<String>::from_str(
526 "thresh(7,pk(A),pk(B),pk(C),pk(D),pk(E),pk(F),pk(G),pk(H))",
527 )
528 .unwrap();
529 let desc = pol
530 .compile_tr_private_experimental(Some(unspendable_key.clone()))
531 .unwrap();
532 let expected_desc = Descriptor::Tr(
533 Tr::<String>::from_str(
534 "eltr(UNSPEND ,{
535 {
536 {multi_a(7,B,C,D,E,F,G,H),multi_a(7,A,C,D,E,F,G,H)},
537 {multi_a(7,A,B,D,E,F,G,H),multi_a(7,A,B,C,E,F,G,H)}
538 },
539 {
540 {multi_a(7,A,B,C,D,F,G,H),multi_a(7,A,B,C,D,E,G,H)}
541 ,{multi_a(7,A,B,C,D,E,F,H),multi_a(7,A,B,C,D,E,F,G)}
542 }})"
543 .replace(&['\t', ' ', '\n'][..], "")
544 .as_str(),
545 )
546 .unwrap(),
547 );
548 assert_eq!(desc, expected_desc);
549 }
550
551 {
552 let pol =
553 Concrete::<String>::from_str("thresh(3,pk(A),pk(B),pk(C),pk(D),pk(E))").unwrap();
554 let desc = pol
555 .compile_tr_private_experimental(Some(unspendable_key))
556 .unwrap();
557 let expected_desc = Descriptor::Tr(
558 Tr::<String>::from_str(
559 "eltr(UNSPEND,
560 {{
561 {multi_a(3,A,D,E),multi_a(3,A,C,E)},
562 {multi_a(3,A,C,D),multi_a(3,A,B,E)}\
563 },
564 {
565 {multi_a(3,A,B,D),multi_a(3,A,B,C)},
566 {
567 {multi_a(3,C,D,E),multi_a(3,B,D,E)},
568 {multi_a(3,B,C,E),multi_a(3,B,C,D)}
569 }}})"
570 .replace(&['\t', ' ', '\n'][..], "")
571 .as_str(),
572 )
573 .unwrap(),
574 );
575 assert_eq!(desc, expected_desc);
576 }
577 }
578}
579
580#[cfg(all(miniscript_bench, feature = "compiler"))]
581mod benches {
582 use core::str::FromStr;
583
584 use test::{black_box, Bencher};
585
586 use super::{Concrete, Error};
587 use crate::descriptor::Descriptor;
588 type TapDesc = Result<Descriptor<String>, Error>;
589
590 #[bench]
591 pub fn compile_large_tap(bh: &mut Bencher) {
592 let pol = Concrete::<String>::from_str(
593 "thresh(20,pk(A),pk(B),pk(C),pk(D),pk(E),pk(F),pk(G),pk(H),pk(I),pk(J),pk(K),pk(L),pk(M),pk(N),pk(O),pk(P),pk(Q),pk(R),pk(S),pk(T),pk(U),pk(V),pk(W),pk(X),pk(Y),pk(Z))",
594 )
595 .expect("parsing");
596 bh.iter(|| {
597 let pt: TapDesc = pol.compile_tr_private_experimental(Some("UNSPEND".to_string()));
598 black_box(pt).unwrap();
599 });
600 }
601}