miniscript_debug/miniscript/
astelem.rs

1// Miniscript
2// Written in 2019 by
3//     Andrew Poelstra <apoelstra@wpsoftware.net>
4//
5// To the extent possible under law, the author(s) have dedicated all
6// copyright and related and neighboring rights to this software to
7// the public domain worldwide. This software is distributed without
8// any warranty.
9//
10// You should have received a copy of the CC0 Public Domain Dedication
11// along with this software.
12// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13//
14
15//! AST Elements
16//!
17//! Datatype describing a Miniscript "script fragment", which are the
18//! building blocks of all Miniscripts. Each fragment has a unique
19//! encoding in Bitcoin script, as well as a datatype. Full details
20//! are given on the Miniscript website.
21
22use core::fmt;
23use core::str::FromStr;
24
25use bitcoin::blockdata::{opcodes, script};
26use bitcoin::hashes::hash160;
27use bitcoin::{LockTime, Sequence};
28use sync::Arc;
29
30use crate::miniscript::context::SigType;
31use crate::miniscript::types::{self, Property};
32use crate::miniscript::ScriptContext;
33use crate::prelude::*;
34use crate::util::MsKeyBuilder;
35use crate::{
36    errstr, expression, script_num_size, Error, ForEachKey, Miniscript, MiniscriptKey, Terminal,
37    ToPublicKey, TranslatePk, Translator,
38};
39
40impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
41    /// Internal helper function for displaying wrapper types; returns
42    /// a character to display before the `:` as well as a reference
43    /// to the wrapped type to allow easy recursion
44    fn wrap_char(&self) -> Option<(char, &Arc<Miniscript<Pk, Ctx>>)> {
45        match *self {
46            Terminal::Alt(ref sub) => Some(('a', sub)),
47            Terminal::Swap(ref sub) => Some(('s', sub)),
48            Terminal::Check(ref sub) => Some(('c', sub)),
49            Terminal::DupIf(ref sub) => Some(('d', sub)),
50            Terminal::Verify(ref sub) => Some(('v', sub)),
51            Terminal::NonZero(ref sub) => Some(('j', sub)),
52            Terminal::ZeroNotEqual(ref sub) => Some(('n', sub)),
53            Terminal::AndV(ref sub, ref r) if r.node == Terminal::True => Some(('t', sub)),
54            Terminal::OrI(ref sub, ref r) if r.node == Terminal::False => Some(('u', sub)),
55            Terminal::OrI(ref l, ref sub) if l.node == Terminal::False => Some(('l', sub)),
56            _ => None,
57        }
58    }
59}
60
61impl<Pk, Q, Ctx> TranslatePk<Pk, Q> for Terminal<Pk, Ctx>
62where
63    Pk: MiniscriptKey,
64    Q: MiniscriptKey,
65    Ctx: ScriptContext,
66{
67    type Output = Terminal<Q, Ctx>;
68
69    /// Converts an AST element with one public key type to one of another public key type.
70    fn translate_pk<T, E>(&self, translate: &mut T) -> Result<Self::Output, E>
71    where
72        T: Translator<Pk, Q, E>,
73    {
74        self.real_translate_pk(translate)
75    }
76}
77
78impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
79    pub(super) fn real_for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: &mut F) -> bool
80    where
81        Pk: 'a,
82    {
83        match *self {
84            Terminal::PkK(ref p) => pred(p),
85            Terminal::PkH(ref p) => pred(p),
86            Terminal::RawPkH(..)
87            | Terminal::After(..)
88            | Terminal::Older(..)
89            | Terminal::Sha256(..)
90            | Terminal::Hash256(..)
91            | Terminal::Ripemd160(..)
92            | Terminal::Hash160(..)
93            | Terminal::True
94            | Terminal::False => true,
95            Terminal::Alt(ref sub)
96            | Terminal::Swap(ref sub)
97            | Terminal::Check(ref sub)
98            | Terminal::DupIf(ref sub)
99            | Terminal::Verify(ref sub)
100            | Terminal::NonZero(ref sub)
101            | Terminal::ZeroNotEqual(ref sub) => sub.real_for_each_key(pred),
102            Terminal::AndV(ref left, ref right)
103            | Terminal::AndB(ref left, ref right)
104            | Terminal::OrB(ref left, ref right)
105            | Terminal::OrD(ref left, ref right)
106            | Terminal::OrC(ref left, ref right)
107            | Terminal::OrI(ref left, ref right) => {
108                left.real_for_each_key(&mut *pred) && right.real_for_each_key(pred)
109            }
110            Terminal::AndOr(ref a, ref b, ref c) => {
111                a.real_for_each_key(&mut *pred)
112                    && b.real_for_each_key(&mut *pred)
113                    && c.real_for_each_key(pred)
114            }
115            Terminal::Thresh(_, ref subs) => subs.iter().all(|sub| sub.real_for_each_key(pred)),
116            Terminal::Multi(_, ref keys) | Terminal::MultiA(_, ref keys) => {
117                keys.iter().all(|key| pred(key))
118            }
119        }
120    }
121
122    pub(super) fn real_translate_pk<Q, CtxQ, T, E>(&self, t: &mut T) -> Result<Terminal<Q, CtxQ>, E>
123    where
124        Q: MiniscriptKey,
125        CtxQ: ScriptContext,
126        T: Translator<Pk, Q, E>,
127    {
128        let frag: Terminal<Q, CtxQ> = match *self {
129            Terminal::PkK(ref p) => Terminal::PkK(t.pk(p)?),
130            Terminal::PkH(ref p) => Terminal::PkH(t.pk(p)?),
131            Terminal::RawPkH(ref p) => Terminal::RawPkH(*p),
132            Terminal::After(n) => Terminal::After(n),
133            Terminal::Older(n) => Terminal::Older(n),
134            Terminal::Sha256(ref x) => Terminal::Sha256(t.sha256(&x)?),
135            Terminal::Hash256(ref x) => Terminal::Hash256(t.hash256(&x)?),
136            Terminal::Ripemd160(ref x) => Terminal::Ripemd160(t.ripemd160(&x)?),
137            Terminal::Hash160(ref x) => Terminal::Hash160(t.hash160(&x)?),
138            Terminal::True => Terminal::True,
139            Terminal::False => Terminal::False,
140            Terminal::Alt(ref sub) => Terminal::Alt(Arc::new(sub.real_translate_pk(t)?)),
141            Terminal::Swap(ref sub) => Terminal::Swap(Arc::new(sub.real_translate_pk(t)?)),
142            Terminal::Check(ref sub) => Terminal::Check(Arc::new(sub.real_translate_pk(t)?)),
143            Terminal::DupIf(ref sub) => Terminal::DupIf(Arc::new(sub.real_translate_pk(t)?)),
144            Terminal::Verify(ref sub) => Terminal::Verify(Arc::new(sub.real_translate_pk(t)?)),
145            Terminal::NonZero(ref sub) => Terminal::NonZero(Arc::new(sub.real_translate_pk(t)?)),
146            Terminal::ZeroNotEqual(ref sub) => {
147                Terminal::ZeroNotEqual(Arc::new(sub.real_translate_pk(t)?))
148            }
149            Terminal::AndV(ref left, ref right) => Terminal::AndV(
150                Arc::new(left.real_translate_pk(t)?),
151                Arc::new(right.real_translate_pk(t)?),
152            ),
153            Terminal::AndB(ref left, ref right) => Terminal::AndB(
154                Arc::new(left.real_translate_pk(t)?),
155                Arc::new(right.real_translate_pk(t)?),
156            ),
157            Terminal::AndOr(ref a, ref b, ref c) => Terminal::AndOr(
158                Arc::new(a.real_translate_pk(t)?),
159                Arc::new(b.real_translate_pk(t)?),
160                Arc::new(c.real_translate_pk(t)?),
161            ),
162            Terminal::OrB(ref left, ref right) => Terminal::OrB(
163                Arc::new(left.real_translate_pk(t)?),
164                Arc::new(right.real_translate_pk(t)?),
165            ),
166            Terminal::OrD(ref left, ref right) => Terminal::OrD(
167                Arc::new(left.real_translate_pk(t)?),
168                Arc::new(right.real_translate_pk(t)?),
169            ),
170            Terminal::OrC(ref left, ref right) => Terminal::OrC(
171                Arc::new(left.real_translate_pk(t)?),
172                Arc::new(right.real_translate_pk(t)?),
173            ),
174            Terminal::OrI(ref left, ref right) => Terminal::OrI(
175                Arc::new(left.real_translate_pk(t)?),
176                Arc::new(right.real_translate_pk(t)?),
177            ),
178            Terminal::Thresh(k, ref subs) => {
179                let subs: Result<Vec<Arc<Miniscript<Q, _>>>, _> = subs
180                    .iter()
181                    .map(|s| s.real_translate_pk(t).map(Arc::new))
182                    .collect();
183                Terminal::Thresh(k, subs?)
184            }
185            Terminal::Multi(k, ref keys) => {
186                let keys: Result<Vec<Q>, _> = keys.iter().map(|k| t.pk(k)).collect();
187                Terminal::Multi(k, keys?)
188            }
189            Terminal::MultiA(k, ref keys) => {
190                let keys: Result<Vec<Q>, _> = keys.iter().map(|k| t.pk(k)).collect();
191                Terminal::MultiA(k, keys?)
192            }
193        };
194        Ok(frag)
195    }
196}
197
198impl<Pk: MiniscriptKey, Ctx: ScriptContext> ForEachKey<Pk> for Terminal<Pk, Ctx> {
199    fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool
200    where
201        Pk: 'a,
202    {
203        self.real_for_each_key(&mut pred)
204    }
205}
206
207impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Debug for Terminal<Pk, Ctx> {
208    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209        f.write_str("[")?;
210        if let Ok(type_map) = types::Type::type_check(self, |_| None) {
211            f.write_str(match type_map.corr.base {
212                types::Base::B => "B",
213                types::Base::K => "K",
214                types::Base::V => "V",
215                types::Base::W => "W",
216            })?;
217            fmt::Write::write_char(f, '/')?;
218            f.write_str(match type_map.corr.input {
219                types::Input::Zero => "z",
220                types::Input::One => "o",
221                types::Input::OneNonZero => "on",
222                types::Input::Any => "",
223                types::Input::AnyNonZero => "n",
224            })?;
225            if type_map.corr.dissatisfiable {
226                fmt::Write::write_char(f, 'd')?;
227            }
228            if type_map.corr.unit {
229                fmt::Write::write_char(f, 'u')?;
230            }
231            f.write_str(match type_map.mall.dissat {
232                types::Dissat::None => "f",
233                types::Dissat::Unique => "e",
234                types::Dissat::Unknown => "",
235            })?;
236            if type_map.mall.safe {
237                fmt::Write::write_char(f, 's')?;
238            }
239            if type_map.mall.non_malleable {
240                fmt::Write::write_char(f, 'm')?;
241            }
242        } else {
243            f.write_str("TYPECHECK FAILED")?;
244        }
245        f.write_str("]")?;
246        if let Some((ch, sub)) = self.wrap_char() {
247            fmt::Write::write_char(f, ch)?;
248            if sub.node.wrap_char().is_none() {
249                fmt::Write::write_char(f, ':')?;
250            }
251            write!(f, "{:?}", sub)
252        } else {
253            match *self {
254                Terminal::PkK(ref pk) => write!(f, "pk_k({:?})", pk),
255                Terminal::PkH(ref pk) => write!(f, "pk_h({:?})", pk),
256                Terminal::RawPkH(ref pkh) => write!(f, "expr_raw_pk_h({:?})", pkh),
257                Terminal::After(t) => write!(f, "after({})", t),
258                Terminal::Older(t) => write!(f, "older({})", t),
259                Terminal::Sha256(ref h) => write!(f, "sha256({})", h),
260                Terminal::Hash256(ref h) => write!(f, "hash256({})", h),
261                Terminal::Ripemd160(ref h) => write!(f, "ripemd160({})", h),
262                Terminal::Hash160(ref h) => write!(f, "hash160({})", h),
263                Terminal::True => f.write_str("1"),
264                Terminal::False => f.write_str("0"),
265                Terminal::AndV(ref l, ref r) => write!(f, "and_v({:?},{:?})", l, r),
266                Terminal::AndB(ref l, ref r) => write!(f, "and_b({:?},{:?})", l, r),
267                Terminal::AndOr(ref a, ref b, ref c) => {
268                    if c.node == Terminal::False {
269                        write!(f, "and_n({:?},{:?})", a, b)
270                    } else {
271                        write!(f, "andor({:?},{:?},{:?})", a, b, c)
272                    }
273                }
274                Terminal::OrB(ref l, ref r) => write!(f, "or_b({:?},{:?})", l, r),
275                Terminal::OrD(ref l, ref r) => write!(f, "or_d({:?},{:?})", l, r),
276                Terminal::OrC(ref l, ref r) => write!(f, "or_c({:?},{:?})", l, r),
277                Terminal::OrI(ref l, ref r) => write!(f, "or_i({:?},{:?})", l, r),
278                Terminal::Thresh(k, ref subs) => {
279                    write!(f, "thresh({}", k)?;
280                    for s in subs {
281                        write!(f, ",{:?}", s)?;
282                    }
283                    f.write_str(")")
284                }
285                Terminal::Multi(k, ref keys) => {
286                    write!(f, "multi({}", k)?;
287                    for k in keys {
288                        write!(f, ",{:?}", k)?;
289                    }
290                    f.write_str(")")
291                }
292                Terminal::MultiA(k, ref keys) => {
293                    write!(f, "multi_a({}", k)?;
294                    for k in keys {
295                        write!(f, ",{}", k)?;
296                    }
297                    f.write_str(")")
298                }
299                _ => unreachable!(),
300            }
301        }
302    }
303}
304
305impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Display for Terminal<Pk, Ctx> {
306    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
307        match *self {
308            Terminal::PkK(ref pk) => write!(f, "pk_k({})", pk),
309            Terminal::PkH(ref pk) => write!(f, "pk_h({})", pk),
310            Terminal::RawPkH(ref pkh) => write!(f, "expr_raw_pk_h({})", pkh),
311            Terminal::After(t) => write!(f, "after({})", t),
312            Terminal::Older(t) => write!(f, "older({})", t),
313            Terminal::Sha256(ref h) => write!(f, "sha256({})", h),
314            Terminal::Hash256(ref h) => write!(f, "hash256({})", h),
315            Terminal::Ripemd160(ref h) => write!(f, "ripemd160({})", h),
316            Terminal::Hash160(ref h) => write!(f, "hash160({})", h),
317            Terminal::True => f.write_str("1"),
318            Terminal::False => f.write_str("0"),
319            Terminal::AndV(ref l, ref r) if r.node != Terminal::True => {
320                write!(f, "and_v({},{})", l, r)
321            }
322            Terminal::AndB(ref l, ref r) => write!(f, "and_b({},{})", l, r),
323            Terminal::AndOr(ref a, ref b, ref c) => {
324                if c.node == Terminal::False {
325                    write!(f, "and_n({},{})", a, b)
326                } else {
327                    write!(f, "andor({},{},{})", a, b, c)
328                }
329            }
330            Terminal::OrB(ref l, ref r) => write!(f, "or_b({},{})", l, r),
331            Terminal::OrD(ref l, ref r) => write!(f, "or_d({},{})", l, r),
332            Terminal::OrC(ref l, ref r) => write!(f, "or_c({},{})", l, r),
333            Terminal::OrI(ref l, ref r)
334                if l.node != Terminal::False && r.node != Terminal::False =>
335            {
336                write!(f, "or_i({},{})", l, r)
337            }
338            Terminal::Thresh(k, ref subs) => {
339                write!(f, "thresh({}", k)?;
340                for s in subs {
341                    write!(f, ",{}", s)?;
342                }
343                f.write_str(")")
344            }
345            Terminal::Multi(k, ref keys) => {
346                write!(f, "multi({}", k)?;
347                for k in keys {
348                    write!(f, ",{}", k)?;
349                }
350                f.write_str(")")
351            }
352            Terminal::MultiA(k, ref keys) => {
353                write!(f, "multi_a({}", k)?;
354                for k in keys {
355                    write!(f, ",{}", k)?;
356                }
357                f.write_str(")")
358            }
359            // wrappers
360            _ => {
361                if let Some((ch, sub)) = self.wrap_char() {
362                    if ch == 'c' {
363                        if let Terminal::PkK(ref pk) = sub.node {
364                            // alias: pk(K) = c:pk_k(K)
365                            return write!(f, "pk({})", pk);
366                        } else if let Terminal::RawPkH(ref pkh) = sub.node {
367                            // `RawPkH` is currently unsupported in the descriptor spec
368                            // alias: pkh(K) = c:pk_h(K)
369                            // We temporarily display there using raw_pkh, but these descriptors
370                            // are not defined in the spec yet. These are prefixed with `expr`
371                            // in the descriptor string.
372                            // We do not support parsing these descriptors yet.
373                            return write!(f, "expr_raw_pkh({})", pkh);
374                        } else if let Terminal::PkH(ref pk) = sub.node {
375                            // alias: pkh(K) = c:pk_h(K)
376                            return write!(f, "pkh({})", pk);
377                        }
378                    }
379
380                    fmt::Write::write_char(f, ch)?;
381                    match sub.node.wrap_char() {
382                        None => {
383                            fmt::Write::write_char(f, ':')?;
384                        }
385                        // Add a ':' wrapper if there are other wrappers apart from c:pk_k()
386                        // tvc:pk_k() -> tv:pk()
387                        Some(('c', ms)) => match ms.node {
388                            Terminal::PkK(_) | Terminal::PkH(_) | Terminal::RawPkH(_) => {
389                                fmt::Write::write_char(f, ':')?
390                            }
391                            _ => {}
392                        },
393                        _ => {}
394                    };
395                    write!(f, "{}", sub)
396                } else {
397                    unreachable!();
398                }
399            }
400        }
401    }
402}
403
404impl_from_tree!(
405    ;Ctx; ScriptContext,
406    Arc<Terminal<Pk, Ctx>>,
407    fn from_tree(top: &expression::Tree) -> Result<Arc<Terminal<Pk, Ctx>>, Error> {
408        Ok(Arc::new(expression::FromTree::from_tree(top)?))
409    }
410);
411
412impl_from_tree!(
413    ;Ctx; ScriptContext,
414    Terminal<Pk, Ctx>,
415    fn from_tree(top: &expression::Tree) -> Result<Terminal<Pk, Ctx>, Error> {
416        let mut aliased_wrap;
417        let frag_name;
418        let frag_wrap;
419        let mut name_split = top.name.split(':');
420        match (name_split.next(), name_split.next(), name_split.next()) {
421            (None, _, _) => {
422                frag_name = "";
423                frag_wrap = "";
424            }
425            (Some(name), None, _) => {
426                if name == "pk" {
427                    frag_name = "pk_k";
428                    frag_wrap = "c";
429                } else if name == "pkh" {
430                    frag_name = "pk_h";
431                    frag_wrap = "c";
432                } else {
433                    frag_name = name;
434                    frag_wrap = "";
435                }
436            }
437            (Some(wrap), Some(name), None) => {
438                if wrap.is_empty() {
439                    return Err(Error::Unexpected(top.name.to_owned()));
440                }
441                if name == "pk" {
442                    frag_name = "pk_k";
443                    aliased_wrap = wrap.to_owned();
444                    aliased_wrap.push('c');
445                    frag_wrap = &aliased_wrap;
446                } else if name == "pkh" {
447                    frag_name = "pk_h";
448                    aliased_wrap = wrap.to_owned();
449                    aliased_wrap.push('c');
450                    frag_wrap = &aliased_wrap;
451                } else {
452                    frag_name = name;
453                    frag_wrap = wrap;
454                }
455            }
456            (Some(_), Some(_), Some(_)) => {
457                return Err(Error::MultiColon(top.name.to_owned()));
458            }
459        }
460        let mut unwrapped = match (frag_name, top.args.len()) {
461            ("expr_raw_pkh", 1) => expression::terminal(&top.args[0], |x| {
462                hash160::Hash::from_str(x).map(Terminal::RawPkH)
463            }),
464            ("pk_k", 1) => {
465                expression::terminal(&top.args[0], |x| Pk::from_str(x).map(Terminal::PkK))
466            }
467            ("pk_h", 1) => expression::terminal(&top.args[0], |x| Pk::from_str(x).map(Terminal::PkH)),
468            ("after", 1) => expression::terminal(&top.args[0], |x| {
469                expression::parse_num(x).map(|x| Terminal::After(LockTime::from_consensus(x).into()))
470            }),
471            ("older", 1) => expression::terminal(&top.args[0], |x| {
472                expression::parse_num(x).map(|x| Terminal::Older(Sequence::from_consensus(x)))
473            }),
474            ("sha256", 1) => expression::terminal(&top.args[0], |x| {
475                Pk::Sha256::from_str(x).map(Terminal::Sha256)
476            }),
477            ("hash256", 1) => expression::terminal(&top.args[0], |x| {
478                Pk::Hash256::from_str(x).map(Terminal::Hash256)
479            }),
480            ("ripemd160", 1) => expression::terminal(&top.args[0], |x| {
481                Pk::Ripemd160::from_str(x).map(Terminal::Ripemd160)
482            }),
483            ("hash160", 1) => expression::terminal(&top.args[0], |x| {
484                Pk::Hash160::from_str(x).map(Terminal::Hash160)
485            }),
486            ("1", 0) => Ok(Terminal::True),
487            ("0", 0) => Ok(Terminal::False),
488            ("and_v", 2) => expression::binary(top, Terminal::AndV),
489            ("and_b", 2) => expression::binary(top, Terminal::AndB),
490            ("and_n", 2) => Ok(Terminal::AndOr(
491                expression::FromTree::from_tree(&top.args[0])?,
492                expression::FromTree::from_tree(&top.args[1])?,
493                Arc::new(Miniscript::from_ast(Terminal::False)?),
494            )),
495            ("andor", 3) => Ok(Terminal::AndOr(
496                expression::FromTree::from_tree(&top.args[0])?,
497                expression::FromTree::from_tree(&top.args[1])?,
498                expression::FromTree::from_tree(&top.args[2])?,
499            )),
500            ("or_b", 2) => expression::binary(top, Terminal::OrB),
501            ("or_d", 2) => expression::binary(top, Terminal::OrD),
502            ("or_c", 2) => expression::binary(top, Terminal::OrC),
503            ("or_i", 2) => expression::binary(top, Terminal::OrI),
504            ("thresh", n) => {
505                if n == 0 {
506                    return Err(errstr("no arguments given"));
507                }
508                let k = expression::terminal(&top.args[0], expression::parse_num)? as usize;
509                if k > n - 1 {
510                    return Err(errstr("higher threshold than there are subexpressions"));
511                }
512                if n == 1 {
513                    return Err(errstr("empty thresholds not allowed in descriptors"));
514                }
515
516                let subs: Result<Vec<Arc<Miniscript<Pk, Ctx>>>, _> = top.args[1..]
517                    .iter()
518                    .map(expression::FromTree::from_tree)
519                    .collect();
520
521                Ok(Terminal::Thresh(k, subs?))
522            }
523            ("multi", n) | ("multi_a", n) => {
524                if n == 0 {
525                    return Err(errstr("no arguments given"));
526                }
527                let k = expression::terminal(&top.args[0], expression::parse_num)? as usize;
528                if k > n - 1 {
529                    return Err(errstr("higher threshold than there were keys in multi"));
530                }
531
532                let pks: Result<Vec<Pk>, _> = top.args[1..]
533                    .iter()
534                    .map(|sub| expression::terminal(sub, Pk::from_str))
535                    .collect();
536
537                if frag_name == "multi" {
538                    pks.map(|pks| Terminal::Multi(k, pks))
539                } else {
540                    // must be multi_a
541                    pks.map(|pks| Terminal::MultiA(k, pks))
542                }
543            }
544            _ => Err(Error::Unexpected(format!(
545                "{}({} args) while parsing Miniscript",
546                top.name,
547                top.args.len(),
548            ))),
549        }?;
550        for ch in frag_wrap.chars().rev() {
551            // Check whether the wrapper is valid under the current context
552            let ms = Miniscript::from_ast(unwrapped)?;
553            Ctx::check_global_validity(&ms)?;
554            match ch {
555                'a' => unwrapped = Terminal::Alt(Arc::new(ms)),
556                's' => unwrapped = Terminal::Swap(Arc::new(ms)),
557                'c' => unwrapped = Terminal::Check(Arc::new(ms)),
558                'd' => unwrapped = Terminal::DupIf(Arc::new(ms)),
559                'v' => unwrapped = Terminal::Verify(Arc::new(ms)),
560                'j' => unwrapped = Terminal::NonZero(Arc::new(ms)),
561                'n' => unwrapped = Terminal::ZeroNotEqual(Arc::new(ms)),
562                't' => {
563                    unwrapped = Terminal::AndV(
564                        Arc::new(ms),
565                        Arc::new(Miniscript::from_ast(Terminal::True)?),
566                    )
567                }
568                'u' => {
569                    unwrapped = Terminal::OrI(
570                        Arc::new(ms),
571                        Arc::new(Miniscript::from_ast(Terminal::False)?),
572                    )
573                }
574                'l' => {
575                    if ms.node == Terminal::False {
576                        return Err(Error::LikelyFalse);
577                    }
578                    unwrapped = Terminal::OrI(
579                        Arc::new(Miniscript::from_ast(Terminal::False)?),
580                        Arc::new(ms),
581                    )
582                }
583                x => return Err(Error::UnknownWrapper(x)),
584            }
585        }
586        // Check whether the unwrapped miniscript is valid under the current context
587        let ms = Miniscript::from_ast(unwrapped)?;
588        Ctx::check_global_validity(&ms)?;
589        Ok(ms.node)
590    }
591);
592
593/// Helper trait to add a `push_astelem` method to `script::Builder`
594trait PushAstElem<Pk: MiniscriptKey, Ctx: ScriptContext> {
595    fn push_astelem(self, ast: &Miniscript<Pk, Ctx>) -> Self
596    where
597        Pk: ToPublicKey;
598}
599
600impl<Pk: MiniscriptKey, Ctx: ScriptContext> PushAstElem<Pk, Ctx> for script::Builder {
601    fn push_astelem(self, ast: &Miniscript<Pk, Ctx>) -> Self
602    where
603        Pk: ToPublicKey,
604    {
605        ast.node.encode(self)
606    }
607}
608
609impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
610    /// Encode the element as a fragment of Bitcoin Script. The inverse
611    /// function, from Script to an AST element, is implemented in the
612    /// `parse` module.
613    pub fn encode(&self, mut builder: script::Builder) -> script::Builder
614    where
615        Pk: ToPublicKey,
616    {
617        match *self {
618            Terminal::PkK(ref pk) => builder.push_ms_key::<_, Ctx>(pk),
619            Terminal::PkH(ref pk) => builder
620                .push_opcode(opcodes::all::OP_DUP)
621                .push_opcode(opcodes::all::OP_HASH160)
622                .push_ms_key_hash::<_, Ctx>(pk)
623                .push_opcode(opcodes::all::OP_EQUALVERIFY),
624            Terminal::RawPkH(ref hash) => builder
625                .push_opcode(opcodes::all::OP_DUP)
626                .push_opcode(opcodes::all::OP_HASH160)
627                .push_slice(&hash)
628                .push_opcode(opcodes::all::OP_EQUALVERIFY),
629            Terminal::After(t) => builder
630                .push_int(t.to_u32().into())
631                .push_opcode(opcodes::all::OP_CLTV),
632            Terminal::Older(t) => builder
633                .push_int(t.to_consensus_u32().into())
634                .push_opcode(opcodes::all::OP_CSV),
635            Terminal::Sha256(ref h) => builder
636                .push_opcode(opcodes::all::OP_SIZE)
637                .push_int(32)
638                .push_opcode(opcodes::all::OP_EQUALVERIFY)
639                .push_opcode(opcodes::all::OP_SHA256)
640                .push_slice(&Pk::to_sha256(&h))
641                .push_opcode(opcodes::all::OP_EQUAL),
642            Terminal::Hash256(ref h) => builder
643                .push_opcode(opcodes::all::OP_SIZE)
644                .push_int(32)
645                .push_opcode(opcodes::all::OP_EQUALVERIFY)
646                .push_opcode(opcodes::all::OP_HASH256)
647                .push_slice(&Pk::to_hash256(&h))
648                .push_opcode(opcodes::all::OP_EQUAL),
649            Terminal::Ripemd160(ref h) => builder
650                .push_opcode(opcodes::all::OP_SIZE)
651                .push_int(32)
652                .push_opcode(opcodes::all::OP_EQUALVERIFY)
653                .push_opcode(opcodes::all::OP_RIPEMD160)
654                .push_slice(&Pk::to_ripemd160(&h))
655                .push_opcode(opcodes::all::OP_EQUAL),
656            Terminal::Hash160(ref h) => builder
657                .push_opcode(opcodes::all::OP_SIZE)
658                .push_int(32)
659                .push_opcode(opcodes::all::OP_EQUALVERIFY)
660                .push_opcode(opcodes::all::OP_HASH160)
661                .push_slice(&Pk::to_hash160(&h))
662                .push_opcode(opcodes::all::OP_EQUAL),
663            Terminal::True => builder.push_opcode(opcodes::OP_TRUE),
664            Terminal::False => builder.push_opcode(opcodes::OP_FALSE),
665            Terminal::Alt(ref sub) => builder
666                .push_opcode(opcodes::all::OP_TOALTSTACK)
667                .push_astelem(sub)
668                .push_opcode(opcodes::all::OP_FROMALTSTACK),
669            Terminal::Swap(ref sub) => builder.push_opcode(opcodes::all::OP_SWAP).push_astelem(sub),
670            Terminal::Check(ref sub) => builder
671                .push_astelem(sub)
672                .push_opcode(opcodes::all::OP_CHECKSIG),
673            Terminal::DupIf(ref sub) => builder
674                .push_opcode(opcodes::all::OP_DUP)
675                .push_opcode(opcodes::all::OP_IF)
676                .push_astelem(sub)
677                .push_opcode(opcodes::all::OP_ENDIF),
678            Terminal::Verify(ref sub) => builder.push_astelem(sub).push_verify(),
679            Terminal::NonZero(ref sub) => builder
680                .push_opcode(opcodes::all::OP_SIZE)
681                .push_opcode(opcodes::all::OP_0NOTEQUAL)
682                .push_opcode(opcodes::all::OP_IF)
683                .push_astelem(sub)
684                .push_opcode(opcodes::all::OP_ENDIF),
685            Terminal::ZeroNotEqual(ref sub) => builder
686                .push_astelem(sub)
687                .push_opcode(opcodes::all::OP_0NOTEQUAL),
688            Terminal::AndV(ref left, ref right) => builder.push_astelem(left).push_astelem(right),
689            Terminal::AndB(ref left, ref right) => builder
690                .push_astelem(left)
691                .push_astelem(right)
692                .push_opcode(opcodes::all::OP_BOOLAND),
693            Terminal::AndOr(ref a, ref b, ref c) => builder
694                .push_astelem(a)
695                .push_opcode(opcodes::all::OP_NOTIF)
696                .push_astelem(c)
697                .push_opcode(opcodes::all::OP_ELSE)
698                .push_astelem(b)
699                .push_opcode(opcodes::all::OP_ENDIF),
700            Terminal::OrB(ref left, ref right) => builder
701                .push_astelem(left)
702                .push_astelem(right)
703                .push_opcode(opcodes::all::OP_BOOLOR),
704            Terminal::OrD(ref left, ref right) => builder
705                .push_astelem(left)
706                .push_opcode(opcodes::all::OP_IFDUP)
707                .push_opcode(opcodes::all::OP_NOTIF)
708                .push_astelem(right)
709                .push_opcode(opcodes::all::OP_ENDIF),
710            Terminal::OrC(ref left, ref right) => builder
711                .push_astelem(left)
712                .push_opcode(opcodes::all::OP_NOTIF)
713                .push_astelem(right)
714                .push_opcode(opcodes::all::OP_ENDIF),
715            Terminal::OrI(ref left, ref right) => builder
716                .push_opcode(opcodes::all::OP_IF)
717                .push_astelem(left)
718                .push_opcode(opcodes::all::OP_ELSE)
719                .push_astelem(right)
720                .push_opcode(opcodes::all::OP_ENDIF),
721            Terminal::Thresh(k, ref subs) => {
722                builder = builder.push_astelem(&subs[0]);
723                for sub in &subs[1..] {
724                    builder = builder.push_astelem(sub).push_opcode(opcodes::all::OP_ADD);
725                }
726                builder
727                    .push_int(k as i64)
728                    .push_opcode(opcodes::all::OP_EQUAL)
729            }
730            Terminal::Multi(k, ref keys) => {
731                debug_assert!(Ctx::sig_type() == SigType::Ecdsa);
732                builder = builder.push_int(k as i64);
733                for pk in keys {
734                    builder = builder.push_key(&pk.to_public_key());
735                }
736                builder
737                    .push_int(keys.len() as i64)
738                    .push_opcode(opcodes::all::OP_CHECKMULTISIG)
739            }
740            Terminal::MultiA(k, ref keys) => {
741                debug_assert!(Ctx::sig_type() == SigType::Schnorr);
742                // keys must be atleast len 1 here, guaranteed by typing rules
743                builder = builder.push_ms_key::<_, Ctx>(&keys[0]);
744                builder = builder.push_opcode(opcodes::all::OP_CHECKSIG);
745                for pk in keys.iter().skip(1) {
746                    builder = builder.push_ms_key::<_, Ctx>(pk);
747                    builder = builder.push_opcode(opcodes::all::OP_CHECKSIGADD);
748                }
749                builder
750                    .push_int(k as i64)
751                    .push_opcode(opcodes::all::OP_NUMEQUAL)
752            }
753        }
754    }
755
756    /// Size, in bytes of the script-pubkey. If this Miniscript is used outside
757    /// of segwit (e.g. in a bare or P2SH descriptor), this quantity should be
758    /// multiplied by 4 to compute the weight.
759    ///
760    /// In general, it is not recommended to use this function directly, but
761    /// to instead call the corresponding function on a `Descriptor`, which
762    /// will handle the segwit/non-segwit technicalities for you.
763    pub fn script_size(&self) -> usize {
764        match *self {
765            Terminal::PkK(ref pk) => Ctx::pk_len(pk),
766            Terminal::PkH(..) | Terminal::RawPkH(..) => 24,
767            Terminal::After(n) => script_num_size(n.to_u32() as usize) + 1,
768            Terminal::Older(n) => script_num_size(n.to_consensus_u32() as usize) + 1,
769            Terminal::Sha256(..) => 33 + 6,
770            Terminal::Hash256(..) => 33 + 6,
771            Terminal::Ripemd160(..) => 21 + 6,
772            Terminal::Hash160(..) => 21 + 6,
773            Terminal::True => 1,
774            Terminal::False => 1,
775            Terminal::Alt(ref sub) => sub.node.script_size() + 2,
776            Terminal::Swap(ref sub) => sub.node.script_size() + 1,
777            Terminal::Check(ref sub) => sub.node.script_size() + 1,
778            Terminal::DupIf(ref sub) => sub.node.script_size() + 3,
779            Terminal::Verify(ref sub) => {
780                sub.node.script_size() + if sub.ext.has_free_verify { 0 } else { 1 }
781            }
782            Terminal::NonZero(ref sub) => sub.node.script_size() + 4,
783            Terminal::ZeroNotEqual(ref sub) => sub.node.script_size() + 1,
784            Terminal::AndV(ref l, ref r) => l.node.script_size() + r.node.script_size(),
785            Terminal::AndB(ref l, ref r) => l.node.script_size() + r.node.script_size() + 1,
786            Terminal::AndOr(ref a, ref b, ref c) => {
787                a.node.script_size() + b.node.script_size() + c.node.script_size() + 3
788            }
789            Terminal::OrB(ref l, ref r) => l.node.script_size() + r.node.script_size() + 1,
790            Terminal::OrD(ref l, ref r) => l.node.script_size() + r.node.script_size() + 3,
791            Terminal::OrC(ref l, ref r) => l.node.script_size() + r.node.script_size() + 2,
792            Terminal::OrI(ref l, ref r) => l.node.script_size() + r.node.script_size() + 3,
793            Terminal::Thresh(k, ref subs) => {
794                assert!(!subs.is_empty(), "threshold must be nonempty");
795                script_num_size(k) // k
796                    + 1 // EQUAL
797                    + subs.iter().map(|s| s.node.script_size()).sum::<usize>()
798                    + subs.len() // ADD
799                    - 1 // no ADD on first element
800            }
801            Terminal::Multi(k, ref pks) => {
802                script_num_size(k)
803                    + 1
804                    + script_num_size(pks.len())
805                    + pks.iter().map(|pk| Ctx::pk_len(pk)).sum::<usize>()
806            }
807            Terminal::MultiA(k, ref pks) => {
808                script_num_size(k)
809                    + 1 // NUMEQUAL
810                    + pks.iter().map(|pk| Ctx::pk_len(pk)).sum::<usize>() // n keys
811                    + pks.len() // n times CHECKSIGADD
812            }
813        }
814    }
815}