1use 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 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 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 _ => {
361 if let Some((ch, sub)) = self.wrap_char() {
362 if ch == 'c' {
363 if let Terminal::PkK(ref pk) = sub.node {
364 return write!(f, "pk({})", pk);
366 } else if let Terminal::RawPkH(ref pkh) = sub.node {
367 return write!(f, "expr_raw_pkh({})", pkh);
374 } else if let Terminal::PkH(ref pk) = sub.node {
375 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 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 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 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 let ms = Miniscript::from_ast(unwrapped)?;
588 Ctx::check_global_validity(&ms)?;
589 Ok(ms.node)
590 }
591);
592
593trait 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 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 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 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) + 1 + subs.iter().map(|s| s.node.script_size()).sum::<usize>()
798 + subs.len() - 1 }
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 + pks.iter().map(|pk| Ctx::pk_len(pk)).sum::<usize>() + pks.len() }
813 }
814 }
815}