1use crate::{
2 condition_stack::ConditionStack,
3 context::{ScriptContext, ScriptRules, ScriptVersion},
4 expr::{Expr, MultisigArgs, OpExprArgs, Opcode1, Opcode2, Opcode3},
5 opcode::opcodes,
6 script::{
7 convert::{decode_bool, decode_int, encode_int, FALSE, TRUE},
8 stack::Stack,
9 ScriptElem, ScriptSlice,
10 },
11 script_error::ScriptError,
12 util::locktime::{
13 locktime_to_string, locktime_type_equals, LocktimeType, SEQUENCE_LOCKTIME_MASK,
14 SEQUENCE_LOCKTIME_TYPE_FLAG,
15 },
16};
17use core::fmt;
18
19struct LocktimeRequirement {
20 exprs: Vec<Expr>,
21 req: Option<u32>,
22}
23
24impl LocktimeRequirement {
25 fn new() -> Self {
26 Self {
27 exprs: Vec::new(),
28 req: None,
29 }
30 }
31
32 fn locktime_requirement_to_string(&self, relative: bool) -> Option<String> {
33 if self.exprs.is_empty() && self.req.is_none() {
34 return None;
35 }
36
37 let type_ = match self.req.map(|req| LocktimeType::new(req, relative)) {
38 Some(LocktimeType::Height) => "height",
39 Some(LocktimeType::Time) => "time",
40 None => "unknown",
41 };
42
43 let tmp;
44 let min_value = match self.req {
45 Some(req) => {
46 tmp = locktime_to_string(req, relative);
47 &tmp
48 }
49 None => "unknown",
50 };
51
52 Some(format!(
53 "type: {}, minValue: {}{}",
54 type_,
55 min_value,
56 if !self.exprs.is_empty() {
57 format!(
58 ", stack elements: {:?}",
59 self.exprs
60 .iter()
61 .map(|s| s.to_string())
62 .collect::<Vec<_>>()
63 .join("\n")
64 )
65 } else {
66 "".to_string()
67 }
68 ))
69 }
70}
71
72struct AnalyzerResult {
73 stack_size: u32,
74 spending_conditions: Vec<Expr>,
75 locktime_req: LocktimeRequirement,
76 sequence_req: LocktimeRequirement,
77}
78
79impl fmt::Display for AnalyzerResult {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 let tmp;
82 let stack_items_str = if !self.spending_conditions.is_empty() {
83 tmp = format!(
84 "\n{}",
85 self.spending_conditions
86 .iter()
87 .map(|s| s.to_string())
88 .collect::<Vec<_>>()
89 .join("\n")
90 );
91 &tmp
92 } else {
93 " none"
94 };
95
96 let locktime = self.locktime_req.locktime_requirement_to_string(false);
97 let sequence = self.sequence_req.locktime_requirement_to_string(true);
98
99 let locktime_str = match &locktime {
100 Some(s) => s,
101 None => "none",
102 };
103 let sequence_str = match (&sequence, &locktime) {
104 (Some(s), _) => s,
105 (None, Some(_)) => "non-final (not 0xffffffff)",
106 (None, None) => "none",
107 };
108
109 write!(
110 f,
111 "Stack size: {}\n\
112 Stack item requirements:\
113 {stack_items_str}\n\
114 Locktime requirement: {locktime_str}\n\
115 Sequence requirement: {sequence_str}",
116 self.stack_size,
117 )
118 }
119}
120
121type Results<'a> = Vec<ScriptAnalyzer<'a>>;
122
123#[cfg(feature = "threads")]
124type ResultsMut<'a, 'b, 'f> = &'b std::sync::Mutex<Results<'a>>;
125
126#[cfg(not(feature = "threads"))]
127type ResultsMut<'a, 'b, 'f> = &'f mut Results<'a>;
128
129#[cfg(feature = "threads")]
130type ThreadPool<'a, 'f> = &'f crate::threadpool::ThreadPool<'a>;
131
132#[cfg(not(feature = "threads"))]
133type ThreadPool<'a, 'f> = ();
134
135pub fn analyze_script(
136 script: ScriptSlice<'_>,
137 ctx: ScriptContext,
138 worker_threads: usize,
139) -> Result<String, String> {
140 #[cfg(not(feature = "threads"))]
141 assert_eq!(
142 worker_threads, 0,
143 "Feature \"threads\" disabled, set `worker_threads` to 0 or enable the feature"
144 );
145
146 for op in script {
147 if let ScriptElem::Op(op) = op {
148 if op.is_disabled() {
149 return Err(format!(
150 "Script error: {}",
151 ScriptError::SCRIPT_ERR_DISABLED_OPCODE
152 ));
153 }
154 }
155 }
156
157 let analyzer = ScriptAnalyzer::from_script(script);
158
159 #[cfg(feature = "threads")]
160 let results = {
161 let results = std::sync::Mutex::new(Vec::new());
162
163 std::thread::scope(|scope| {
164 let pool = crate::threadpool::ThreadPool::new(scope, worker_threads);
165 analyzer.analyze(&results, ctx, &pool);
166 });
167
168 results.into_inner().unwrap()
169 };
170
171 #[cfg(not(feature = "threads"))]
172 let results = {
173 let mut results = Vec::new();
174
175 analyzer.analyze(&mut results, ctx, ());
176
177 results
178 };
179
180 let results: Vec<_> = results
182 .into_iter()
183 .filter_map(|mut a| {
184 a.calculate_locktime_requirements()
185 .ok()
186 .map(|(locktime_req, sequence_req)| AnalyzerResult {
187 locktime_req,
188 sequence_req,
189 stack_size: a.stack.items_used(),
190 spending_conditions: a.spending_conditions,
191 })
192 })
193 .collect();
194
195 if results.is_empty() {
196 return Err("Script is unspendable".to_string());
197 }
198
199 Ok(format!(
200 "Spending paths:\n\n{}",
201 results
202 .into_iter()
203 .map(|res| res.to_string())
204 .collect::<Vec<_>>()
205 .join("\n\n")
206 ))
207}
208
209#[derive(Clone)]
210pub struct ScriptAnalyzer<'a> {
211 stack: Stack,
212 altstack: Vec<Expr>,
213 spending_conditions: Vec<Expr>,
214 script: ScriptSlice<'a>,
215 script_offset: usize,
216 cs: ConditionStack,
217}
218
219impl<'a> ScriptAnalyzer<'a> {
220 fn from_script(script: ScriptSlice<'a>) -> Self {
221 Self {
222 stack: Stack::new(),
223 altstack: Vec::new(),
224 spending_conditions: Vec::new(),
225 script,
226 script_offset: 0,
227 cs: ConditionStack::new(),
228 }
229 }
230
231 fn calculate_locktime_requirements(
232 &mut self,
233 ) -> Result<(LocktimeRequirement, LocktimeRequirement), ScriptError> {
234 let mut locktime_requirement = LocktimeRequirement::new();
235 let mut sequence_requirement = LocktimeRequirement::new();
236
237 let mut i = 0;
238 while i < self.spending_conditions.len() {
239 let expr = &self.spending_conditions[i];
240 if let Expr::Op(expr) = expr {
241 if let OpExprArgs::Args1(op, arg) = &expr.args {
242 let arg = &arg[0];
243
244 if matches!(
245 op,
246 Opcode1::OP_CHECKLOCKTIMEVERIFY | Opcode1::OP_CHECKSEQUENCEVERIFY
247 ) {
248 let relative = expr.opcode() == opcodes::OP_CHECKSEQUENCEVERIFY;
249 let r = if relative {
250 &mut sequence_requirement
251 } else {
252 &mut locktime_requirement
253 };
254 if let Expr::Bytes(arg) = arg {
255 let min_value = decode_int(arg, 5)?;
256 if min_value < 0 {
257 return Err(ScriptError::SCRIPT_ERR_NEGATIVE_LOCKTIME);
258 } else if !relative && min_value > u32::MAX as i64 {
259 return Err(ScriptError::SCRIPT_ERR_UNSATISFIED_LOCKTIME);
260 }
261 let mut min_value = min_value as u32;
262 if relative {
263 min_value &= SEQUENCE_LOCKTIME_TYPE_FLAG | SEQUENCE_LOCKTIME_MASK;
264 }
265 if let Some(ref mut req) = r.req {
266 if !locktime_type_equals(*req, min_value, relative) {
267 return Err(ScriptError::SCRIPT_ERR_UNSATISFIED_LOCKTIME);
268 }
269 if *req < min_value {
270 *req = min_value;
271 }
272 } else {
273 r.req = Some(min_value);
274 }
275 } else {
276 r.exprs.push(arg.clone());
277 }
278
279 self.spending_conditions.remove(i);
280 continue;
281 }
282 }
283 }
284
285 i += 1;
286 }
287
288 Ok((locktime_requirement, sequence_requirement))
289 }
290
291 fn eval_conditions(&mut self, ctx: ScriptContext) -> Result<(), ScriptError> {
292 let exprs = &mut self.spending_conditions;
293 'i: loop {
294 Expr::sort_recursive(exprs);
295 let mut j = 0;
296 'j: while j < exprs.len() {
297 let expr1 = &exprs[j];
298 if let Expr::Bytes(bytes) = expr1 {
299 if decode_bool(bytes) {
300 exprs.remove(j);
302 continue 'j;
303 } else {
304 return Err(ScriptError::SCRIPT_ERR_UNKNOWN_ERROR);
306 }
307 } else if let Expr::Op(op) = expr1 {
308 if let OpExprArgs::Args2(Opcode2::OP_BOOLAND, args) = &op.args {
309 let args = args.clone();
311 exprs.remove(j);
312 exprs.extend(args.into_iter());
313 continue 'i;
314 }
315 }
316 let mut k = 0;
317 'k: while k < exprs.len() {
318 if j == k {
319 k += 1;
320 continue 'k;
321 }
322 let expr2 = &exprs[k];
323 if expr1 == expr2 {
324 exprs.remove(k);
326 continue 'i;
327 }
328 if let Expr::Op(op) = expr1 {
329 if let OpExprArgs::Args1(op, args) = &op.args {
331 if *op == Opcode1::OP_NOT || *op == Opcode1::OP_INTERNAL_NOT {
332 if &args[0] == expr2 {
333 return Err(ScriptError::SCRIPT_ERR_UNKNOWN_ERROR);
337 }
338
339 if let Expr::Op(expr_args_0) = &args[0] {
340 if expr_args_0.opcode().returns_boolean() {
341 let mut res = expr2.clone();
344 if res.replace_all(&args[0], &Expr::bytes(FALSE)) {
345 exprs[k] = res;
346 continue 'i;
347 }
348 }
349 }
350 }
351 }
352 if let OpExprArgs::Args2(Opcode2::OP_EQUAL, args) = &op.args {
353 let mut res = expr2.clone();
356 if res.replace_all(&args[0], &args[1]) {
357 exprs[k] = res;
358 continue 'i;
359 }
360 }
361 if op.opcode().returns_boolean() {
362 let mut res = expr2.clone();
365 if res.replace_all(expr1, &Expr::bytes(TRUE)) {
366 exprs[k] = res;
367 continue 'i;
368 }
369 }
370 }
371
372 k += 1;
373 }
374
375 if exprs[j].eval(ctx)? {
376 continue 'i; }
378
379 j += 1;
380 }
381
382 break Ok(());
383 }
384 }
385
386 fn analyze<'b>(
387 mut self,
388 results: ResultsMut<'a, 'b, '_>,
389 ctx: ScriptContext,
390 pool: ThreadPool<'b, '_>,
391 ) {
392 if self.analyze_path(results, ctx, pool).is_err() {
393 return;
394 }
395
396 if self.eval_conditions(ctx).is_err() {
397 return;
398 }
399
400 #[cfg(feature = "threads")]
401 let mut results = results.lock().unwrap();
402
403 results.push(self);
404 }
405
406 fn analyze_path<'b>(
407 &mut self,
408 results: ResultsMut<'a, 'b, '_>,
409 ctx: ScriptContext,
410 pool: ThreadPool<'b, '_>,
411 ) -> Result<(), ScriptError> {
412 while self.script_offset < self.script.len() {
413 let f_exec = self.cs.all_true();
414 let op = self.script[self.script_offset];
415 self.script_offset += 1;
416
417 if !f_exec {
418 match op {
419 ScriptElem::Bytes(_) => {
420 continue;
421 }
422 ScriptElem::Op(opcode) => {
423 if opcode < opcodes::OP_IF || opcode > opcodes::OP_ENDIF {
424 continue;
425 }
426 }
427 }
428 }
429
430 match op {
431 ScriptElem::Bytes(b) => self.stack.push(Expr::bytes(b)),
432 ScriptElem::Op(op) => match op {
433 opcodes::OP_0 => self.stack.push(Expr::bytes(&[])),
434
435 opcodes::OP_1NEGATE => self.stack.push(Expr::bytes(&[0x81])),
436
437 opcodes::OP_1
438 | opcodes::OP_2
439 | opcodes::OP_3
440 | opcodes::OP_4
441 | opcodes::OP_5
442 | opcodes::OP_6
443 | opcodes::OP_7
444 | opcodes::OP_8
445 | opcodes::OP_9
446 | opcodes::OP_10
447 | opcodes::OP_11
448 | opcodes::OP_12
449 | opcodes::OP_13
450 | opcodes::OP_14
451 | opcodes::OP_15
452 | opcodes::OP_16 => self.stack.push(Expr::bytes(&[op.opcode - 0x50])),
453
454 opcodes::OP_NOP => {}
455
456 opcodes::OP_IF | opcodes::OP_NOTIF => {
457 if f_exec {
458 let minimal_if = ctx.version == ScriptVersion::SegwitV1
459 || (ctx.version == ScriptVersion::SegwitV0
460 && ctx.rules == ScriptRules::All);
461 let [elem] = self.stack.pop();
462 let mut fork = self.clone();
463 self.cs.push_back(op == opcodes::OP_IF);
464 fork.cs.push_back(op != opcodes::OP_IF);
465 if minimal_if {
466 let error = if ctx.version == ScriptVersion::SegwitV1 {
467 ScriptError::SCRIPT_ERR_TAPSCRIPT_MINIMALIF
468 } else {
469 ScriptError::SCRIPT_ERR_MINIMALIF
470 };
471 self.spending_conditions
472 .push(Opcode2::OP_EQUAL.expr_with_error(
473 Box::new([elem.clone(), Expr::bytes(TRUE)]),
474 error,
475 ));
476 fork.spending_conditions.push(
477 Opcode2::OP_EQUAL.expr_with_error(
478 Box::new([elem, Expr::bytes(FALSE)]),
479 error,
480 ),
481 );
482 } else {
483 self.spending_conditions.push(elem.clone());
484 fork.spending_conditions
485 .push(Opcode1::OP_INTERNAL_NOT.expr(Box::new([elem])));
486 }
487
488 #[cfg(feature = "threads")]
489 {
490 let pool_ = pool.clone();
491 pool.submit_job(move || {
492 fork.analyze(results, ctx, &pool_);
493 });
494 }
495
496 #[cfg(not(feature = "threads"))]
497 fork.analyze(results, ctx, pool);
498 } else {
499 self.cs.push_back(false);
500 }
501 }
502
503 opcodes::OP_ELSE => {
504 if self.cs.empty() {
505 return Err(ScriptError::SCRIPT_ERR_UNBALANCED_CONDITIONAL);
506 }
507 self.cs.toggle_top();
508 }
509
510 opcodes::OP_ENDIF => {
511 if self.cs.empty() {
512 return Err(ScriptError::SCRIPT_ERR_UNBALANCED_CONDITIONAL);
513 }
514 self.cs.pop_back();
515 }
516
517 opcodes::OP_VERIFY => {
518 self.verify(ScriptError::SCRIPT_ERR_VERIFY)?;
519 }
520
521 opcodes::OP_RETURN => {
522 return Err(ScriptError::SCRIPT_ERR_OP_RETURN);
523 }
524
525 opcodes::OP_TOALTSTACK => {
526 let [elem] = self.stack.pop();
527 self.altstack.push(elem);
528 }
529
530 opcodes::OP_FROMALTSTACK => {
531 self.stack.push(
532 self.altstack
533 .pop()
534 .ok_or(ScriptError::SCRIPT_ERR_INVALID_ALTSTACK_OPERATION)?,
535 );
536 }
537
538 opcodes::OP_2DROP => {
539 self.stack.pop::<2>();
540 }
541
542 opcodes::OP_2DUP => {
543 self.stack.extend_from_within_back(2, 0);
544 }
545
546 opcodes::OP_3DUP => {
547 self.stack.extend_from_within_back(3, 0);
548 }
549
550 opcodes::OP_2OVER => {
551 self.stack.extend_from_within_back(2, 2);
552 }
553
554 opcodes::OP_2ROT => {
555 self.stack.swap_back(0, 2);
556 self.stack.swap_back(1, 3);
557 self.stack.swap_back(2, 4);
558 self.stack.swap_back(3, 5);
559 }
560
561 opcodes::OP_2SWAP => {
562 self.stack.swap_back(0, 2);
563 self.stack.swap_back(1, 3);
564 }
565
566 opcodes::OP_IFDUP => {
567 let elem = self.stack.get_back(0).clone();
568
569 let mut fork = self.clone();
570 fork.spending_conditions
571 .push(Opcode1::OP_INTERNAL_NOT.expr(Box::new([elem.clone()])));
572
573 #[cfg(feature = "threads")]
574 {
575 let pool_ = pool.clone();
576 pool.submit_job(move || {
577 fork.analyze(results, ctx, &pool_);
578 });
579 }
580
581 #[cfg(not(feature = "threads"))]
582 fork.analyze(results, ctx, pool);
583
584 self.spending_conditions.push(elem.clone());
585 self.stack.push(elem);
586 }
587
588 opcodes::OP_DEPTH => {
589 self.stack
590 .push(Expr::bytes_owned(encode_int(self.stack.len() as i64)));
591 }
592
593 opcodes::OP_DROP => {
594 self.stack.pop::<1>();
595 }
596
597 opcodes::OP_DUP => {
598 self.stack.extend_from_within_back(1, 0);
599 }
600
601 opcodes::OP_NIP => {
602 self.stack.remove_back(1);
603 }
604
605 opcodes::OP_OVER => {
606 self.stack.extend_from_within_back(1, 1);
607 }
608
609 opcodes::OP_PICK | opcodes::OP_ROLL => {
610 let index = self.num_from_stack()?;
611 if index < 0 {
612 return Err(ScriptError::SCRIPT_ERR_INVALID_STACK_OPERATION);
613 }
614 let index = index as usize;
615 let elem = match op {
616 opcodes::OP_PICK => self.stack.get_back(index).clone(),
617 opcodes::OP_ROLL => self.stack.remove_back(index),
618 _ => unreachable!(),
619 };
620 self.stack.push(elem);
621 }
622
623 opcodes::OP_ROT => {
624 self.stack.swap_back(2, 1);
625 self.stack.swap_back(1, 0);
626 }
627
628 opcodes::OP_SWAP => {
629 self.stack.swap_back(0, 1);
630 }
631
632 opcodes::OP_TUCK => {
633 self.stack.swap_back(0, 1);
634 self.stack.extend_from_within_back(1, 1);
635 }
636
637 opcodes::OP_SIZE => {
638 let size = match self.stack.get_back(0) {
639 Expr::Bytes(b) => Expr::bytes_owned(encode_int(b.len() as i64)),
640 elem => Opcode1::OP_SIZE.expr(Box::new([elem.clone()])),
641 };
642
643 self.stack.push(size);
644 }
645
646 opcodes::OP_EQUAL | opcodes::OP_EQUALVERIFY => {
647 let elems = self.stack.pop::<2>();
648 self.stack.push(Opcode2::OP_EQUAL.expr(Box::new(elems)));
649 if op == opcodes::OP_EQUALVERIFY {
650 self.verify(ScriptError::SCRIPT_ERR_EQUALVERIFY)?;
651 }
652 }
653
654 opcodes::OP_1ADD | opcodes::OP_1SUB => {
655 let [elem] = self.stack.pop();
656 self.stack.push(
657 match op {
658 opcodes::OP_1ADD => Opcode2::OP_ADD,
659 opcodes::OP_1SUB => Opcode2::OP_SUB,
660 _ => unreachable!(),
661 }
662 .expr(Box::new([elem, Expr::bytes(&[1])])),
663 );
664 }
665
666 opcodes::OP_NEGATE => {
667 let [elem] = self.stack.pop();
668 self.stack
669 .push(Opcode2::OP_SUB.expr(Box::new([Expr::bytes(&[]), elem])));
670 }
671
672 opcodes::OP_ABS | opcodes::OP_NOT | opcodes::OP_0NOTEQUAL => {
673 let [elem] = self.stack.pop();
674 self.stack.push(
675 match op {
676 opcodes::OP_ABS => Opcode1::OP_ABS,
677 opcodes::OP_NOT => Opcode1::OP_NOT,
678 opcodes::OP_0NOTEQUAL => Opcode1::OP_0NOTEQUAL,
679 _ => unreachable!(),
680 }
681 .expr(Box::new([elem])),
682 );
683 }
684
685 opcodes::OP_ADD
686 | opcodes::OP_SUB
687 | opcodes::OP_BOOLAND
688 | opcodes::OP_BOOLOR
689 | opcodes::OP_NUMEQUAL
690 | opcodes::OP_NUMEQUALVERIFY
691 | opcodes::OP_NUMNOTEQUAL
692 | opcodes::OP_LESSTHAN
693 | opcodes::OP_GREATERTHAN
694 | opcodes::OP_LESSTHANOREQUAL
695 | opcodes::OP_GREATERTHANOREQUAL
696 | opcodes::OP_MIN
697 | opcodes::OP_MAX => {
698 let mut elems = self.stack.pop::<2>();
699 self.stack.push(
700 match op {
701 opcodes::OP_ADD => Opcode2::OP_ADD,
702 opcodes::OP_SUB => Opcode2::OP_SUB,
703 opcodes::OP_BOOLAND => Opcode2::OP_BOOLAND,
704 opcodes::OP_BOOLOR => Opcode2::OP_BOOLOR,
705 opcodes::OP_NUMEQUAL | opcodes::OP_NUMEQUALVERIFY => {
706 Opcode2::OP_NUMEQUAL
707 }
708 opcodes::OP_NUMNOTEQUAL => Opcode2::OP_NUMNOTEQUAL,
709 opcodes::OP_LESSTHAN => Opcode2::OP_LESSTHAN,
710 opcodes::OP_GREATERTHAN => {
711 elems.swap(0, 1);
712 Opcode2::OP_LESSTHAN
713 }
714 opcodes::OP_LESSTHANOREQUAL => Opcode2::OP_LESSTHANOREQUAL,
715 opcodes::OP_GREATERTHANOREQUAL => {
716 elems.swap(0, 1);
717 Opcode2::OP_LESSTHANOREQUAL
718 }
719 opcodes::OP_MIN => Opcode2::OP_MIN,
720 opcodes::OP_MAX => Opcode2::OP_MAX,
721 _ => unreachable!(),
722 }
723 .expr(Box::new(elems)),
724 );
725 if op == opcodes::OP_NUMEQUALVERIFY {
726 self.verify(ScriptError::SCRIPT_ERR_NUMEQUALVERIFY)?;
727 }
728 }
729
730 opcodes::OP_WITHIN => {
731 let elems = self.stack.pop::<3>();
732 self.stack.push(Opcode3::OP_WITHIN.expr(Box::new(elems)));
733 }
734
735 opcodes::OP_RIPEMD160 | opcodes::OP_SHA1 | opcodes::OP_SHA256 => {
736 let [elem] = self.stack.pop();
737 self.stack.push(
738 match op {
739 opcodes::OP_RIPEMD160 => Opcode1::OP_RIPEMD160,
740 opcodes::OP_SHA1 => Opcode1::OP_SHA1,
741 opcodes::OP_SHA256 => Opcode1::OP_SHA256,
742 _ => unreachable!(),
743 }
744 .expr(Box::new([elem])),
745 );
746 }
747
748 opcodes::OP_HASH160 | opcodes::OP_HASH256 => {
749 let [elem] = self.stack.pop();
750 self.stack.push(
751 match op {
752 opcodes::OP_HASH160 => Opcode1::OP_RIPEMD160,
753 opcodes::OP_HASH256 => Opcode1::OP_SHA256,
754 _ => unreachable!(),
755 }
756 .expr(Box::new([Opcode1::OP_SHA256.expr(Box::new([elem]))])),
757 );
758 }
759
760 opcodes::OP_CODESEPARATOR => {}
761
762 opcodes::OP_CHECKSIG | opcodes::OP_CHECKSIGVERIFY => {
763 let elems = self.stack.pop::<2>();
764 self.stack.push(Opcode2::OP_CHECKSIG.expr(Box::new(elems)));
765 if op == opcodes::OP_CHECKSIGVERIFY {
766 self.verify(ScriptError::SCRIPT_ERR_CHECKSIGVERIFY)?;
767 }
768 }
769
770 opcodes::OP_CHECKMULTISIG | opcodes::OP_CHECKMULTISIGVERIFY => {
771 if ctx.version == ScriptVersion::SegwitV1 {
772 return Err(ScriptError::SCRIPT_ERR_TAPSCRIPT_CHECKMULTISIG);
773 }
774
775 let kcount = self.num_from_stack()?;
776 if !(0..=20).contains(&kcount) {
777 return Err(ScriptError::SCRIPT_ERR_PUBKEY_COUNT);
778 }
779
780 let pks = self.stack.pop_to_box(kcount as usize);
783
784 let scount = self.num_from_stack()?;
785 if !(0..=kcount).contains(&scount) {
786 return Err(ScriptError::SCRIPT_ERR_SIG_COUNT);
787 }
788
789 let kcount = kcount as usize;
790 let scount = scount as usize;
791
792 let sigs = self.stack.pop_to_box(scount);
793
794 let [dummy] = self.stack.pop();
795
796 if ctx.rules == ScriptRules::All {
797 self.spending_conditions
798 .push(Opcode2::OP_EQUAL.expr_with_error(
799 Box::new([dummy, Expr::bytes(FALSE)]),
800 ScriptError::SCRIPT_ERR_SIG_NULLDUMMY,
801 ));
802 }
803
804 let mut args = Vec::with_capacity(scount + kcount);
805 args.extend(sigs.into_vec());
806 args.extend(pks.into_vec());
807
808 self.stack
809 .push(MultisigArgs::expr(args.into_boxed_slice(), scount));
810
811 if op == opcodes::OP_CHECKMULTISIGVERIFY {
812 self.verify(ScriptError::SCRIPT_ERR_CHECKMULTISIGVERIFY)?;
813 }
814 }
815
816 opcodes::OP_CHECKLOCKTIMEVERIFY | opcodes::OP_CHECKSEQUENCEVERIFY => {
817 let elem = self.stack.get_back(0).clone();
818 self.spending_conditions.push(
819 match op {
820 opcodes::OP_CHECKLOCKTIMEVERIFY => Opcode1::OP_CHECKLOCKTIMEVERIFY,
821 opcodes::OP_CHECKSEQUENCEVERIFY => Opcode1::OP_CHECKSEQUENCEVERIFY,
822 _ => unreachable!(),
823 }
824 .expr(Box::new([elem])),
825 );
826 }
827
828 opcodes::OP_NOP1
829 | opcodes::OP_NOP4
830 | opcodes::OP_NOP5
831 | opcodes::OP_NOP6
832 | opcodes::OP_NOP7
833 | opcodes::OP_NOP8
834 | opcodes::OP_NOP9
835 | opcodes::OP_NOP10 => {}
836
837 opcodes::OP_CHECKSIGADD => {
838 if ctx.version != ScriptVersion::SegwitV1 {
839 return Err(ScriptError::SCRIPT_ERR_BAD_OPCODE);
840 }
841 let [sig, n, pk] = self.stack.pop();
842 self.stack.push(Opcode2::OP_ADD.expr(Box::new([
843 n,
844 Opcode2::OP_CHECKSIG.expr(Box::new([sig, pk])),
845 ])));
846 }
847
848 _ => {
849 return Err(ScriptError::SCRIPT_ERR_BAD_OPCODE);
850 }
851 },
852 }
853
854 if self.stack.len() + self.altstack.len() > 1000 {
855 return Err(ScriptError::SCRIPT_ERR_STACK_SIZE);
856 }
857 }
858
859 if !self.cs.empty() {
860 return Err(ScriptError::SCRIPT_ERR_UNBALANCED_CONDITIONAL);
861 }
862
863 if self.stack.len() > 1
864 && !(ctx.version == ScriptVersion::Legacy && ctx.rules == ScriptRules::ConsensusOnly)
865 {
866 return Err(ScriptError::SCRIPT_ERR_CLEANSTACK);
867 }
868
869 self.verify(ScriptError::SCRIPT_ERR_EVAL_FALSE)?;
870
871 Ok(())
872 }
873
874 fn verify(&mut self, error: ScriptError) -> Result<(), ScriptError> {
875 let [elem] = self.stack.pop();
876 if let Expr::Bytes(elem) = elem {
877 if !decode_bool(&elem) {
878 return Err(error);
879 }
880 } else {
881 self.spending_conditions.push(elem);
883 }
884 Ok(())
885 }
886
887 fn num_from_stack(&mut self) -> Result<i64, ScriptError> {
888 if let [Expr::Bytes(top)] = self.stack.pop() {
889 decode_int(&top, 4)
890 } else {
891 Err(ScriptError::SCRIPT_ERR_UNKNOWN_DEPTH)
892 }
893 }
894}