bitcoin_script_analyzer/
analyzer.rs

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    // TODO does not run on multiple threads yet
181    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                        // TODO swap_remove is O(1) but then exprs is not sorted anymore
301                        exprs.remove(j);
302                        continue 'j;
303                    } else {
304                        // TODO expr1.error
305                        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                        // TODO no clone needed here
310                        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                        // (a && a) == a
325                        exprs.remove(k);
326                        continue 'i;
327                    }
328                    if let Expr::Op(op) = expr1 {
329                        // have to write multiple nested if blocks for now https://github.com/rust-lang/rust/issues/53667
330                        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                                    // (a && !a) == 0
334
335                                    // TODO expr{1,2}.error
336                                    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                                        // (!a && f(a)) -> f(false)
342
343                                        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                            // (a == b && f(a)) -> f(b)
354
355                            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                            // (a && f(a)) -> f(true)
363
364                            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; // 'j
377                }
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                        // TODO save some allocations
781
782                        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            // TODO insert error?
882            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}