Skip to main content

tidecoin_consensus_core/
interpreter.rs

1//! Script interpreter.
2
3use alloc::vec;
4#[cfg(not(feature = "std"))]
5use alloc::vec::Vec;
6#[cfg(feature = "std")]
7use std::vec::Vec;
8
9use core::{cell::RefCell, mem};
10
11use crate::{
12    PqPublicKey, PqSignature, PrecomputedTransactionData, ScriptError, SegwitV0Sighash, Sighash512,
13    SighashCache, SpentOutputs, TidecoinValidationError, TransactionContext, TxSighashType,
14    WitnessExecutionPlan, WitnessProgram, WitnessSigVersion, WitnessSigops,
15    VERIFY_CHECKLOCKTIMEVERIFY, VERIFY_CHECKSEQUENCEVERIFY, VERIFY_CLEANSTACK,
16    VERIFY_CONST_SCRIPTCODE, VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
17    VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, VERIFY_MINIMALDATA, VERIFY_MINIMALIF,
18    VERIFY_NULLDUMMY, VERIFY_NULLFAIL, VERIFY_P2SH, VERIFY_PQ_STRICT, VERIFY_SHA512,
19    VERIFY_SIGPUSHONLY, VERIFY_WITNESS, VERIFY_WITNESS_V1_512,
20};
21use hashes::{hash160, ripemd160, sha1, sha256, sha256d, sha512};
22use primitives::{
23    absolute::LOCK_TIME_THRESHOLD,
24    opcodes::{all, Opcode},
25    script::{
26        encode_scriptnum, read_scriptbool, read_scriptnum, Builder as ScriptBuilderT, Instruction,
27        PushBytesBuf, Script as ScriptT, ScriptBuf as ScriptBufT, ScriptIntError,
28    },
29    Amount, Sequence, Transaction, Witness,
30};
31
32type Builder = ScriptBuilderT<()>;
33type RawScript = ScriptT<()>;
34type RawScriptBuf = ScriptBufT<()>;
35type Error = TidecoinValidationError;
36
37fn script_unknown() -> TidecoinValidationError {
38    TidecoinValidationError::Script(ScriptError::Unknown)
39}
40
41const SUPPORTED_FLAGS: u32 = VERIFY_P2SH
42    | VERIFY_NULLDUMMY
43    | VERIFY_SIGPUSHONLY
44    | VERIFY_CHECKLOCKTIMEVERIFY
45    | VERIFY_CHECKSEQUENCEVERIFY
46    | VERIFY_WITNESS
47    | VERIFY_MINIMALDATA
48    | VERIFY_DISCOURAGE_UPGRADABLE_NOPS
49    | VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM
50    | VERIFY_CLEANSTACK
51    | VERIFY_MINIMALIF
52    | VERIFY_NULLFAIL
53    | VERIFY_PQ_STRICT
54    | VERIFY_WITNESS_V1_512
55    | VERIFY_SHA512
56    | VERIFY_CONST_SCRIPTCODE;
57
58const MAX_STACK_SIZE: usize = 1000;
59const MAX_SCRIPT_SIZE: usize = 65_536;
60const MAX_SCRIPT_ELEMENT_SIZE: usize = 8192;
61const MAX_OPS_PER_SCRIPT: usize = 201;
62const SCRIPTNUM_MAX_LEN: usize = 4;
63const SCRIPTNUM_MAX_LEN_EXTENDED: usize = 5;
64const MAX_PUBKEYS_PER_MULTISIG: usize = 20;
65const SEQUENCE_LOCKTIME_DISABLE_FLAG: u32 = 1 << 31;
66const SEQUENCE_LOCKTIME_TYPE_FLAG: u32 = 1 << 22;
67const SEQUENCE_LOCKTIME_MASK: u32 = 0x0000ffff;
68/// Wrapper for script verification flags.
69#[derive(Debug, Clone, Copy)]
70pub struct ScriptFlags(u32);
71
72impl ScriptFlags {
73    /// Validates raw verification bits against the supported Tidecoin flag set.
74    pub fn from_bits(bits: u32) -> Result<Self, TidecoinValidationError> {
75        if bits & !SUPPORTED_FLAGS != 0 {
76            return Err(TidecoinValidationError::InvalidFlags);
77        }
78        Ok(Self(bits))
79    }
80
81    /// Returns the raw verification bits.
82    pub fn bits(self) -> u32 {
83        self.0
84    }
85}
86
87#[derive(Copy, Clone, Debug, Eq, PartialEq)]
88enum SigVersion {
89    Base,
90    WitnessV0,
91    WitnessV1_512,
92}
93
94#[derive(Default)]
95struct ScriptCodeCache {
96    identity: ScriptIdentity,
97    code_separator: usize,
98    strip_codeseparators: bool,
99    script: RawScriptBuf,
100}
101
102#[derive(Copy, Clone, Default, PartialEq, Eq)]
103struct ScriptIdentity {
104    digest: [u8; 32],
105    len: usize,
106}
107
108impl ScriptIdentity {
109    fn new(script: &RawScript) -> Self {
110        let digest = sha256::Hash::hash(script.as_bytes()).to_byte_array();
111        Self { digest, len: script.as_bytes().len() }
112    }
113}
114
115impl ScriptCodeCache {
116    fn matches(
117        &self,
118        identity: ScriptIdentity,
119        code_separator: usize,
120        strip_codeseparators: bool,
121    ) -> bool {
122        self.identity == identity
123            && self.code_separator == code_separator
124            && self.strip_codeseparators == strip_codeseparators
125    }
126}
127
128/// Minimal stack abstraction used by the interpreter.
129#[derive(Debug, Default, Clone)]
130pub struct ScriptStack {
131    items: Vec<Vec<u8>>,
132}
133
134impl ScriptStack {
135    /// Creates an empty script stack.
136    pub fn new() -> Self {
137        Self { items: Vec::new() }
138    }
139
140    /// Builds a stack from raw items after enforcing script-element limits.
141    pub fn from_items(items: Vec<Vec<u8>>) -> Result<Self, ScriptError> {
142        if items.len() > MAX_STACK_SIZE {
143            return Err(ScriptError::StackSize);
144        }
145        for item in &items {
146            if item.len() > MAX_SCRIPT_ELEMENT_SIZE {
147                return Err(ScriptError::PushSize);
148            }
149        }
150        Ok(Self { items })
151    }
152
153    /// Pushes a raw stack element after enforcing the script-element limit.
154    pub fn push(&mut self, data: Vec<u8>) -> Result<(), ScriptError> {
155        if data.len() > MAX_SCRIPT_ELEMENT_SIZE {
156            return Err(ScriptError::PushSize);
157        }
158        self.items.push(data);
159        Ok(())
160    }
161
162    /// Pushes the canonical boolean stack encoding.
163    pub fn push_bool(&mut self, value: bool) -> Result<(), ScriptError> {
164        if value {
165            self.push(vec![1])
166        } else {
167            self.push(Vec::new())
168        }
169    }
170
171    /// Pops the top element as raw bytes.
172    pub fn pop_bytes(&mut self) -> Result<Vec<u8>, Error> {
173        self.items.pop().ok_or(script_unknown())
174    }
175
176    /// Borrows the top stack element.
177    pub fn last(&self) -> Option<&Vec<u8>> {
178        self.items.last()
179    }
180
181    /// Returns the number of stack elements.
182    pub fn len(&self) -> usize {
183        self.items.len()
184    }
185
186    /// Returns whether the stack is empty.
187    pub fn is_empty(&self) -> bool {
188        self.items.is_empty()
189    }
190}
191
192/// Input-specific data required to run the interpreter.
193pub struct SpendContext<'script> {
194    /// Serialized script pubkey being spent.
195    pub script_pubkey: &'script [u8],
196    /// Typed prevout set used for witness-aware sighash and flag handling.
197    pub spent_outputs: Option<SpentOutputs>,
198    /// Amount of the spent output in satoshis.
199    pub amount: u64,
200    /// Whether the amount is known at this boundary.
201    pub has_amount: bool,
202}
203
204impl<'script> SpendContext<'script> {
205    /// Creates a spend context for a single input verification.
206    pub fn new(
207        script_pubkey: &'script [u8],
208        spent_outputs: Option<SpentOutputs>,
209        amount: u64,
210        has_amount: bool,
211    ) -> Self {
212        Self { script_pubkey, spent_outputs, amount, has_amount }
213    }
214}
215
216/// High-level script verification context.
217pub struct Interpreter<'tx, 'script> {
218    flags: ScriptFlags,
219    amount: u64,
220    has_amount: bool,
221    spent_output_script: &'script [u8],
222    spent_outputs: Option<SpentOutputs>,
223    tx_ctx: &'tx TransactionContext<'tx>,
224    precomputed: Option<PrecomputedTransactionData>,
225    input_index: usize,
226    script_code_cache: Option<ScriptCodeCache>,
227    sighash_cache: RefCell<SighashCache<&'tx Transaction>>,
228    stack: ScriptStack,
229    exec_stack: Vec<bool>,
230    last_error: ScriptError,
231    op_count: usize,
232    sigops: u32,
233    had_witness: bool,
234}
235
236impl<'tx, 'script> Interpreter<'tx, 'script> {
237    /// Creates an interpreter for one transaction input.
238    pub fn new(
239        tx_ctx: &'tx TransactionContext<'tx>,
240        input_index: usize,
241        spend: SpendContext<'script>,
242        flags: ScriptFlags,
243    ) -> Result<Self, TidecoinValidationError> {
244        let SpendContext { script_pubkey, spent_outputs, amount, has_amount } = spend;
245
246        Ok(Self {
247            flags,
248            amount,
249            has_amount,
250            spent_output_script: script_pubkey,
251            spent_outputs,
252            tx_ctx,
253            precomputed: None,
254            input_index,
255            script_code_cache: None,
256            sighash_cache: RefCell::new(SighashCache::new(tx_ctx.tx())),
257            stack: ScriptStack::new(),
258            exec_stack: Vec::new(),
259            last_error: ScriptError::Ok,
260            op_count: 0,
261            sigops: 0,
262            had_witness: false,
263        })
264    }
265
266    /// Executes script verification for the configured input.
267    pub fn verify(&mut self) -> Result<(), TidecoinValidationError> {
268        self.last_error = ScriptError::Ok;
269        self.had_witness = false;
270        self.script_code_cache = None;
271        let txin = &self.tx_ctx.tx().inputs[self.input_index];
272        let witness_enabled = self.flags.bits() & VERIFY_WITNESS != 0;
273        let p2sh_enabled = self.flags.bits() & VERIFY_P2SH != 0;
274        let spent_is_p2sh = is_p2sh(self.spent_output_script);
275        if self.flags.bits() & VERIFY_SIGPUSHONLY != 0 && !is_push_only(txin.script_sig.as_bytes())
276        {
277            return Err(self.fail(ScriptError::SigPushOnly));
278        }
279        self.initialize_sigops(txin.script_sig.as_bytes())?;
280        if witness_enabled && !txin.witness.is_empty() && !self.has_amount {
281            return Err(TidecoinValidationError::AmountRequired);
282        }
283
284        let sig_script_res = self.run_on_main_stack(txin.script_sig.as_bytes(), SigVersion::Base);
285        self.track_script_error(sig_script_res)?;
286        let mut p2sh_stack =
287            if p2sh_enabled && spent_is_p2sh { Some(self.stack.clone()) } else { None };
288        let spent_script_res = self.run_on_main_stack(self.spent_output_script, SigVersion::Base);
289        self.track_script_error(spent_script_res)?;
290        if self.stack.is_empty() || !read_scriptbool(self.stack.last().unwrap()) {
291            return Err(self.fail(ScriptError::EvalFalse));
292        }
293        if witness_enabled {
294            if let Some(witness_program) = WitnessProgram::parse(self.spent_output_script) {
295                self.had_witness = true;
296                if !txin.script_sig.is_empty() {
297                    return Err(self.fail(ScriptError::WitnessMalleated));
298                }
299                let witness_res = self.execute_witness_program(
300                    witness_program.version(),
301                    witness_program.program(),
302                    &txin.witness,
303                    false,
304                );
305                self.track_script_error(witness_res)?;
306                let mut stack = ScriptStack::new();
307                self.push_bool_element(&mut stack, true)?;
308                self.stack = stack;
309            }
310        }
311
312        if p2sh_enabled && spent_is_p2sh {
313            if !is_push_only(txin.script_sig.as_bytes()) {
314                return Err(self.fail(ScriptError::SigPushOnly));
315            }
316
317            let mut stack_copy =
318                p2sh_stack.take().expect("P2SH spend requires preserved stack state");
319            if stack_copy.is_empty() {
320                return Err(self.fail(ScriptError::EvalFalse));
321            }
322
323            let redeem_script = stack_copy.pop_bytes()?;
324            self.run_script(&mut stack_copy, &redeem_script, SigVersion::Base)?;
325            if stack_copy.is_empty() || !read_scriptbool(stack_copy.last().unwrap()) {
326                return Err(self.fail(ScriptError::EvalFalse));
327            }
328
329            if witness_enabled {
330                if let Some(witness_program) = WitnessProgram::parse(&redeem_script) {
331                    self.had_witness = true;
332                    let expected = single_push_script(&redeem_script)
333                        .map_err(|_| self.fail(ScriptError::SigPushOnly))?;
334                    if txin.script_sig.as_bytes() != expected.as_bytes() {
335                        return Err(self.fail(ScriptError::WitnessMalleatedP2SH));
336                    }
337                    let witness_res = self.execute_witness_program(
338                        witness_program.version(),
339                        witness_program.program(),
340                        &txin.witness,
341                        true,
342                    );
343                    self.track_script_error(witness_res)?;
344                    stack_copy = ScriptStack::new();
345                    self.push_element(&mut stack_copy, vec![1])?;
346                }
347            }
348
349            self.add_sigops_from_script(&redeem_script, true)?;
350            self.stack = stack_copy;
351        }
352
353        if self.stack.is_empty() || !read_scriptbool(self.stack.last().unwrap()) {
354            return Err(self.fail(ScriptError::EvalFalse));
355        }
356
357        if self.flags.bits() & VERIFY_CLEANSTACK != 0 {
358            self.require_clean_stack(&self.stack).map_err(|err| self.fail(err))?;
359        }
360
361        if witness_enabled && !self.had_witness && !txin.witness.is_empty() {
362            return Err(self.fail(ScriptError::WitnessUnexpected));
363        }
364
365        Ok(())
366    }
367
368    /// Returns the most recent script error recorded by the interpreter.
369    #[inline]
370    pub fn last_script_error(&self) -> ScriptError {
371        self.last_error
372    }
373
374    fn fail(&mut self, error: ScriptError) -> Error {
375        self.last_error = error;
376        script_unknown()
377    }
378
379    fn map_failure<T>(
380        &mut self,
381        result: Result<T, TidecoinValidationError>,
382        error: ScriptError,
383    ) -> Result<T, TidecoinValidationError> {
384        result.map_err(|_| self.fail(error))
385    }
386
387    fn track_script_error<T>(
388        &mut self,
389        result: Result<T, TidecoinValidationError>,
390    ) -> Result<T, TidecoinValidationError> {
391        match result {
392            Err(err) if err == script_unknown() => {
393                if matches!(self.last_error, ScriptError::Ok) {
394                    self.last_error = ScriptError::Unknown;
395                }
396                Err(err)
397            }
398            other => other,
399        }
400    }
401
402    fn initialize_sigops(&mut self, script_sig: &[u8]) -> Result<(), TidecoinValidationError> {
403        let sigops_sig = count_sigops_bytes(script_sig, false)?;
404        let sigops_spent = count_sigops_bytes(self.spent_output_script, true)?;
405        self.sigops = sigops_sig.checked_add(sigops_spent).ok_or(script_unknown())?;
406        Ok(())
407    }
408
409    fn add_sigops_from_script(
410        &mut self,
411        script_bytes: &[u8],
412        accurate: bool,
413    ) -> Result<(), TidecoinValidationError> {
414        let count = count_sigops_bytes(script_bytes, accurate)?;
415        self.add_sigops(count)
416    }
417
418    fn add_sigops(&mut self, count: u32) -> Result<(), TidecoinValidationError> {
419        self.sigops = self.sigops.checked_add(count).ok_or(script_unknown())?;
420        Ok(())
421    }
422
423    fn push_element(
424        &mut self,
425        stack: &mut ScriptStack,
426        data: Vec<u8>,
427    ) -> Result<(), TidecoinValidationError> {
428        stack.push(data).map_err(|err| self.fail(err))
429    }
430
431    fn push_bool_element(
432        &mut self,
433        stack: &mut ScriptStack,
434        value: bool,
435    ) -> Result<(), TidecoinValidationError> {
436        stack.push_bool(value).map_err(|err| self.fail(err))
437    }
438
439    fn add_ops(&mut self, count: usize) -> Result<(), TidecoinValidationError> {
440        self.op_count += count;
441        if self.op_count > MAX_OPS_PER_SCRIPT {
442            Err(self.fail(ScriptError::OpCount))
443        } else {
444            Ok(())
445        }
446    }
447
448    fn run_script(
449        &mut self,
450        stack: &mut ScriptStack,
451        script_bytes: &[u8],
452        sigversion: SigVersion,
453    ) -> Result<(), TidecoinValidationError> {
454        if script_bytes.is_empty() {
455            return Ok(());
456        }
457        if script_bytes.len() > MAX_SCRIPT_SIZE {
458            return Err(self.fail(ScriptError::ScriptSize));
459        }
460
461        self.exec_stack.clear();
462        self.op_count = 0;
463        let script = RawScript::from_bytes(script_bytes);
464        let bytes = script.as_bytes();
465        let mut altstack: Vec<Vec<u8>> = Vec::new();
466        let mut code_separator = 0usize;
467        let mut cursor = 0usize;
468        let mut opcode_pos: u32 = 0;
469        let script_len = bytes.len();
470
471        while cursor < script_len {
472            let opcode = bytes[cursor];
473            cursor += 1;
474            let should_execute = self.exec_stack.iter().all(|&cond| cond);
475
476            if (0x01..=0x4b).contains(&opcode) {
477                let push_len = opcode as usize;
478                if cursor + push_len > script_len {
479                    return Err(self.fail(ScriptError::BadOpcode));
480                }
481                if push_len > MAX_SCRIPT_ELEMENT_SIZE {
482                    return Err(self.fail(ScriptError::PushSize));
483                }
484                if should_execute
485                    && self.flags.bits() & VERIFY_MINIMALDATA != 0
486                    && !is_minimal_push(opcode, &bytes[cursor..cursor + push_len])
487                {
488                    return Err(self.fail(ScriptError::MinimalData));
489                }
490                if should_execute {
491                    self.push_element(stack, bytes[cursor..cursor + push_len].to_vec())?;
492                }
493                cursor += push_len;
494            } else if opcode == all::OP_PUSHDATA1.to_u8()
495                || opcode == all::OP_PUSHDATA2.to_u8()
496                || opcode == all::OP_PUSHDATA4.to_u8()
497            {
498                let width = match opcode {
499                    x if x == all::OP_PUSHDATA1.to_u8() => 1,
500                    x if x == all::OP_PUSHDATA2.to_u8() => 2,
501                    _ => 4,
502                };
503                let mut len_cursor = cursor;
504                let push_len = read_push_length(bytes, &mut len_cursor, width)
505                    .map_err(|err| self.fail(err))?;
506                if len_cursor + push_len > script_len {
507                    return Err(self.fail(ScriptError::BadOpcode));
508                }
509                if push_len > MAX_SCRIPT_ELEMENT_SIZE {
510                    return Err(self.fail(ScriptError::PushSize));
511                }
512                if should_execute
513                    && self.flags.bits() & VERIFY_MINIMALDATA != 0
514                    && !is_minimal_push(opcode, &bytes[len_cursor..len_cursor + push_len])
515                {
516                    return Err(self.fail(ScriptError::MinimalData));
517                }
518                if should_execute {
519                    self.push_element(stack, bytes[len_cursor..len_cursor + push_len].to_vec())?;
520                }
521                cursor = len_cursor + push_len;
522            } else {
523                let op = Opcode::from(opcode);
524
525                if matches!(op, all::OP_VERIF | all::OP_VERNOTIF) {
526                    return Err(self.fail(ScriptError::BadOpcode));
527                }
528                if matches!(
529                    op,
530                    all::OP_CAT
531                        | all::OP_SUBSTR
532                        | all::OP_LEFT
533                        | all::OP_RIGHT
534                        | all::OP_INVERT
535                        | all::OP_AND
536                        | all::OP_OR
537                        | all::OP_XOR
538                        | all::OP_2MUL
539                        | all::OP_2DIV
540                        | all::OP_MUL
541                        | all::OP_DIV
542                        | all::OP_MOD
543                        | all::OP_LSHIFT
544                        | all::OP_RSHIFT
545                ) {
546                    return Err(self.fail(ScriptError::DisabledOpcode));
547                }
548                if opcode > all::OP_PUSHNUM_16.to_u8() {
549                    self.add_ops(1)?;
550                }
551                if op == all::OP_CODESEPARATOR
552                    && sigversion == SigVersion::Base
553                    && self.flags.bits() & VERIFY_CONST_SCRIPTCODE != 0
554                {
555                    return Err(self.fail(ScriptError::OpCodeSeparator));
556                }
557
558                if is_control_flow(op) {
559                    let control_res =
560                        self.handle_control_flow(stack, op, should_execute, sigversion);
561                    self.track_script_error(control_res)?;
562                } else if should_execute {
563                    if op == all::OP_CODESEPARATOR {
564                        code_separator = cursor;
565                    } else {
566                        let opcode_res = self.execute_opcode(
567                            stack,
568                            &mut altstack,
569                            op,
570                            script,
571                            code_separator,
572                            sigversion,
573                        );
574                        self.track_script_error(opcode_res)?;
575                    }
576                }
577            }
578
579            let limit_res = self.ensure_stack_limit(stack.len(), altstack.len());
580            self.track_script_error(limit_res)?;
581            opcode_pos = opcode_pos.wrapping_add(1);
582        }
583
584        if !self.exec_stack.is_empty() {
585            return Err(self.fail(ScriptError::UnbalancedConditional));
586        }
587
588        Ok(())
589    }
590
591    fn run_on_main_stack(
592        &mut self,
593        script_bytes: &[u8],
594        sigversion: SigVersion,
595    ) -> Result<(), TidecoinValidationError> {
596        let mut stack = mem::take(&mut self.stack);
597        let run_res = self.run_script(&mut stack, script_bytes, sigversion);
598        let result = self.track_script_error(run_res);
599        self.stack = stack;
600        result
601    }
602
603    fn execute_opcode(
604        &mut self,
605        stack: &mut ScriptStack,
606        altstack: &mut Vec<Vec<u8>>,
607        op: Opcode,
608        script: &RawScript,
609        code_separator: usize,
610        sigversion: SigVersion,
611    ) -> Result<(), TidecoinValidationError> {
612        use all::*;
613
614        let opcode = op.to_u8();
615        let require_minimal = self.flags.bits() & VERIFY_MINIMALDATA != 0;
616
617        if matches!(op, OP_RESERVED | OP_RESERVED1 | OP_RESERVED2 | OP_VER | OP_INVALIDOPCODE) {
618            return Err(self.fail(ScriptError::BadOpcode));
619        }
620
621        if matches!(
622            op,
623            OP_CAT
624                | OP_SUBSTR
625                | OP_LEFT
626                | OP_RIGHT
627                | OP_INVERT
628                | OP_AND
629                | OP_OR
630                | OP_XOR
631                | OP_2MUL
632                | OP_2DIV
633                | OP_MUL
634                | OP_DIV
635                | OP_MOD
636                | OP_LSHIFT
637                | OP_RSHIFT
638        ) {
639            return Err(self.fail(ScriptError::DisabledOpcode));
640        }
641
642        if opcode == OP_PUSHBYTES_0.to_u8() {
643            return self.push_element(stack, Vec::new());
644        }
645        if opcode >= OP_PUSHNUM_1.to_u8() && opcode <= OP_PUSHNUM_16.to_u8() {
646            let value = (opcode - OP_PUSHNUM_1.to_u8() + 1) as i32;
647            return self.push_element(stack, encode_scriptnum(value as i64));
648        }
649
650        match op {
651            OP_TOALTSTACK => {
652                let value =
653                    self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
654                altstack.push(value);
655            }
656            OP_FROMALTSTACK => {
657                let value = altstack
658                    .pop()
659                    .ok_or_else(|| self.fail(ScriptError::InvalidAltstackOperation))?;
660                self.push_element(stack, value)?;
661            }
662            OP_IFDUP => {
663                let value = stack
664                    .last()
665                    .ok_or_else(|| self.fail(ScriptError::InvalidStackOperation))?
666                    .clone();
667                if read_scriptbool(&value) {
668                    self.push_element(stack, value)?;
669                }
670            }
671            OP_DEPTH => {
672                let depth = encode_scriptnum(stack.len() as i64);
673                self.push_element(stack, depth)?;
674            }
675            OP_PUSHNUM_NEG1 => {
676                self.push_element(stack, encode_scriptnum(-1))?;
677            }
678            OP_NOP => {}
679            OP_NOP1 | OP_NOP5 | OP_NOP6 | OP_NOP7 | OP_NOP8 | OP_NOP9 | OP_NOP10 => {
680                if self.flags.bits() & VERIFY_DISCOURAGE_UPGRADABLE_NOPS != 0 {
681                    return Err(self.fail(ScriptError::DiscourageUpgradableNops));
682                }
683            }
684            OP_DUP => {
685                let value = stack
686                    .last()
687                    .ok_or_else(|| self.fail(ScriptError::InvalidStackOperation))?
688                    .clone();
689                self.push_element(stack, value)?;
690            }
691            OP_DROP => {
692                self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
693            }
694            OP_NIP => {
695                if stack.len() < 2 {
696                    return Err(self.fail(ScriptError::InvalidStackOperation));
697                }
698                let idx = stack.len() - 2;
699                stack.items.remove(idx);
700            }
701            OP_OVER => {
702                if stack.len() < 2 {
703                    return Err(self.fail(ScriptError::InvalidStackOperation));
704                }
705                let value = stack.items[stack.len() - 2].clone();
706                self.push_element(stack, value)?;
707            }
708            OP_ROT => {
709                if stack.len() < 3 {
710                    return Err(self.fail(ScriptError::InvalidStackOperation));
711                }
712                let len = stack.len();
713                stack.items.swap(len - 3, len - 2);
714                stack.items.swap(len - 2, len - 1);
715            }
716            OP_SWAP => {
717                if stack.len() < 2 {
718                    return Err(self.fail(ScriptError::InvalidStackOperation));
719                }
720                let len = stack.len();
721                stack.items.swap(len - 2, len - 1);
722            }
723            OP_TUCK => {
724                if stack.len() < 2 {
725                    return Err(self.fail(ScriptError::InvalidStackOperation));
726                }
727                let len = stack.len();
728                let value = stack.items[len - 1].clone();
729                stack.items.insert(len - 2, value);
730            }
731            OP_2DROP => {
732                if stack.len() < 2 {
733                    return Err(self.fail(ScriptError::InvalidStackOperation));
734                }
735                self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
736                self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
737            }
738            OP_2DUP => {
739                if stack.len() < 2 {
740                    return Err(self.fail(ScriptError::InvalidStackOperation));
741                }
742                let len = stack.len();
743                let first = stack.items[len - 2].clone();
744                let second = stack.items[len - 1].clone();
745                self.push_element(stack, first)?;
746                self.push_element(stack, second)?;
747            }
748            OP_PICK => {
749                let depth = self.pop_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN)?;
750                if depth < 0 {
751                    return Err(self.fail(ScriptError::InvalidStackOperation));
752                }
753                let depth = depth as usize;
754                if depth >= stack.len() {
755                    return Err(self.fail(ScriptError::InvalidStackOperation));
756                }
757                let idx = stack.len() - 1 - depth;
758                let value = stack.items[idx].clone();
759                self.push_element(stack, value)?;
760            }
761            OP_ROLL => {
762                let depth = self.pop_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN)?;
763                if depth < 0 {
764                    return Err(self.fail(ScriptError::InvalidStackOperation));
765                }
766                let depth = depth as usize;
767                if depth >= stack.len() {
768                    return Err(self.fail(ScriptError::InvalidStackOperation));
769                }
770                let idx = stack.len() - 1 - depth;
771                let value = stack.items.remove(idx);
772                self.push_element(stack, value)?;
773            }
774            OP_3DUP => {
775                if stack.len() < 3 {
776                    return Err(self.fail(ScriptError::InvalidStackOperation));
777                }
778                let len = stack.len();
779                let first = stack.items[len - 3].clone();
780                let second = stack.items[len - 2].clone();
781                let third = stack.items[len - 1].clone();
782                self.push_element(stack, first)?;
783                self.push_element(stack, second)?;
784                self.push_element(stack, third)?;
785            }
786            OP_2OVER => {
787                if stack.len() < 4 {
788                    return Err(self.fail(ScriptError::InvalidStackOperation));
789                }
790                let len = stack.len();
791                let first = stack.items[len - 4].clone();
792                let second = stack.items[len - 3].clone();
793                self.push_element(stack, first)?;
794                self.push_element(stack, second)?;
795            }
796            OP_2ROT => {
797                if stack.len() < 6 {
798                    return Err(self.fail(ScriptError::InvalidStackOperation));
799                }
800                let len = stack.len();
801                let first = stack.items[len - 6].clone();
802                let second = stack.items[len - 5].clone();
803                stack.items.drain(len - 6..len - 4);
804                self.push_element(stack, first)?;
805                self.push_element(stack, second)?;
806            }
807            OP_2SWAP => {
808                if stack.len() < 4 {
809                    return Err(self.fail(ScriptError::InvalidStackOperation));
810                }
811                let len = stack.len();
812                stack.items.swap(len - 4, len - 2);
813                stack.items.swap(len - 3, len - 1);
814            }
815            OP_SIZE => {
816                let value =
817                    stack.last().ok_or_else(|| self.fail(ScriptError::InvalidStackOperation))?;
818                let size = encode_scriptnum(value.len() as i64);
819                self.push_element(stack, size)?;
820            }
821            OP_1ADD | OP_1SUB | OP_NEGATE | OP_ABS | OP_NOT | OP_0NOTEQUAL => {
822                let mut num = self.pop_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN)?;
823                match op {
824                    OP_1ADD => num += 1,
825                    OP_1SUB => num -= 1,
826                    OP_NEGATE => num = -num,
827                    OP_ABS => {
828                        if num < 0 {
829                            num = -num;
830                        }
831                    }
832                    OP_NOT => num = if num == 0 { 1 } else { 0 },
833                    OP_0NOTEQUAL => num = if num != 0 { 1 } else { 0 },
834                    _ => {}
835                }
836                let encoded = encode_scriptnum(num);
837                self.push_element(stack, encoded)?;
838            }
839            OP_ADD
840            | OP_SUB
841            | OP_BOOLAND
842            | OP_BOOLOR
843            | OP_NUMEQUAL
844            | OP_NUMEQUALVERIFY
845            | OP_NUMNOTEQUAL
846            | OP_LESSTHAN
847            | OP_GREATERTHAN
848            | OP_LESSTHANOREQUAL
849            | OP_GREATERTHANOREQUAL
850            | OP_MIN
851            | OP_MAX => {
852                let b = self.pop_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN)?;
853                let a = self.pop_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN)?;
854                let result = match op {
855                    OP_ADD => a.checked_add(b).ok_or(script_unknown())?,
856                    OP_SUB => a.checked_sub(b).ok_or(script_unknown())?,
857                    OP_BOOLAND => {
858                        if a != 0 && b != 0 {
859                            1
860                        } else {
861                            0
862                        }
863                    }
864                    OP_BOOLOR => {
865                        if a != 0 || b != 0 {
866                            1
867                        } else {
868                            0
869                        }
870                    }
871                    OP_NUMEQUAL | OP_NUMEQUALVERIFY => {
872                        if a == b {
873                            1
874                        } else {
875                            0
876                        }
877                    }
878                    OP_NUMNOTEQUAL => {
879                        if a != b {
880                            1
881                        } else {
882                            0
883                        }
884                    }
885                    OP_LESSTHAN => {
886                        if a < b {
887                            1
888                        } else {
889                            0
890                        }
891                    }
892                    OP_GREATERTHAN => {
893                        if a > b {
894                            1
895                        } else {
896                            0
897                        }
898                    }
899                    OP_LESSTHANOREQUAL => {
900                        if a <= b {
901                            1
902                        } else {
903                            0
904                        }
905                    }
906                    OP_GREATERTHANOREQUAL => {
907                        if a >= b {
908                            1
909                        } else {
910                            0
911                        }
912                    }
913                    OP_MIN => {
914                        if a < b {
915                            a
916                        } else {
917                            b
918                        }
919                    }
920                    OP_MAX => {
921                        if a > b {
922                            a
923                        } else {
924                            b
925                        }
926                    }
927                    _ => 0,
928                };
929                self.push_element(stack, encode_scriptnum(result))?;
930                if op == OP_NUMEQUALVERIFY {
931                    self.op_verify_with_code(stack, ScriptError::NumEqualVerify)?;
932                }
933            }
934            OP_WITHIN => {
935                let max = self.pop_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN)?;
936                let min = self.pop_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN)?;
937                let value = self.pop_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN)?;
938                self.push_bool_element(stack, value >= min && value < max)?;
939            }
940            OP_CLTV => {
941                if self.flags.bits() & VERIFY_CHECKLOCKTIMEVERIFY != 0 {
942                    let locktime =
943                        self.peek_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN_EXTENDED)?;
944                    if locktime < 0 {
945                        return Err(self.fail(ScriptError::NegativeLockTime));
946                    }
947                    let check = self.check_lock_time(locktime as u64);
948                    if let Err(err) = check {
949                        return Err(self.fail(err));
950                    }
951                }
952            }
953            OP_CSV => {
954                if self.flags.bits() & VERIFY_CHECKSEQUENCEVERIFY != 0 {
955                    let sequence =
956                        self.peek_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN_EXTENDED)?;
957                    if sequence < 0 {
958                        return Err(self.fail(ScriptError::NegativeLockTime));
959                    }
960                    let check = self.check_sequence(sequence as u64);
961                    if let Err(err) = check {
962                        return Err(self.fail(err));
963                    }
964                }
965            }
966            OP_RIPEMD160 => self.op_ripemd160(stack)?,
967            OP_SHA1 => self.op_sha1(stack)?,
968            OP_SHA256 => self.op_sha256(stack)?,
969            OP_HASH160 => self.op_hash160(stack)?,
970            OP_HASH256 => self.op_hash256(stack)?,
971            _ if opcode == all::OP_NOP4.to_u8() => self.op_sha512(stack)?,
972            OP_EQUAL => self.op_equal(stack)?,
973            OP_EQUALVERIFY => {
974                self.op_equal(stack)?;
975                self.op_verify_with_code(stack, ScriptError::EqualVerify)?;
976            }
977            OP_VERIFY => self.op_verify(stack)?,
978            OP_RETURN => return Err(self.fail(ScriptError::OpReturn)),
979            OP_CHECKSIG => self.op_checksig(stack, script, code_separator, sigversion)?,
980            OP_CHECKSIGVERIFY => {
981                self.op_checksig(stack, script, code_separator, sigversion)?;
982                self.op_verify_with_code(stack, ScriptError::CheckSigVerify)?;
983            }
984            OP_CHECKSIGADD => {
985                self.op_checksigadd(stack, sigversion)?;
986            }
987            OP_CHECKMULTISIG => {
988                self.op_checkmultisig(stack, script, code_separator, sigversion)?;
989            }
990            OP_CHECKMULTISIGVERIFY => {
991                self.op_checkmultisig(stack, script, code_separator, sigversion)?;
992                self.op_verify_with_code(stack, ScriptError::CheckMultiSigVerify)?;
993            }
994            _ => return Err(self.fail(ScriptError::BadOpcode)),
995        }
996
997        Ok(())
998    }
999
1000    fn handle_control_flow(
1001        &mut self,
1002        stack: &mut ScriptStack,
1003        op: Opcode,
1004        should_execute: bool,
1005        sigversion: SigVersion,
1006    ) -> Result<(), TidecoinValidationError> {
1007        use all::*;
1008
1009        match op {
1010            OP_IF | OP_NOTIF => {
1011                let mut value = false;
1012                if should_execute {
1013                    let condition =
1014                        self.map_failure(stack.pop_bytes(), ScriptError::UnbalancedConditional)?;
1015                    let enforce_minimal_if = match sigversion {
1016                        SigVersion::WitnessV0 => self.flags.bits() & VERIFY_MINIMALIF != 0,
1017                        SigVersion::WitnessV1_512 => true,
1018                        SigVersion::Base => false,
1019                    };
1020                    let minimal_if_error = match sigversion {
1021                        SigVersion::WitnessV1_512 => ScriptError::MinimalIf,
1022                        _ => ScriptError::MinimalIf,
1023                    };
1024                    if enforce_minimal_if
1025                        && !condition.is_empty()
1026                        && !is_minimal_if_condition(&condition)
1027                    {
1028                        return Err(self.fail(minimal_if_error));
1029                    }
1030                    value = read_scriptbool(&condition);
1031                    if op == OP_NOTIF {
1032                        value = !value;
1033                    }
1034                }
1035                self.exec_stack.push(value);
1036            }
1037            OP_ELSE => {
1038                let Some(top) = self.exec_stack.last_mut() else {
1039                    return Err(self.fail(ScriptError::UnbalancedConditional));
1040                };
1041                *top = !*top;
1042            }
1043            OP_ENDIF => {
1044                if self.exec_stack.pop().is_none() {
1045                    return Err(self.fail(ScriptError::UnbalancedConditional));
1046                }
1047            }
1048            _ => {}
1049        }
1050
1051        Ok(())
1052    }
1053
1054    fn ensure_stack_limit(
1055        &mut self,
1056        stack_size: usize,
1057        altstack_size: usize,
1058    ) -> Result<(), TidecoinValidationError> {
1059        if stack_size + altstack_size > MAX_STACK_SIZE {
1060            Err(self.fail(ScriptError::StackSize))
1061        } else {
1062            Ok(())
1063        }
1064    }
1065
1066    fn op_hash160(&mut self, stack: &mut ScriptStack) -> Result<(), TidecoinValidationError> {
1067        let data = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1068        let hash = hash160::Hash::hash(&data);
1069        self.push_element(stack, hash.to_byte_array().to_vec())
1070    }
1071
1072    fn op_ripemd160(&mut self, stack: &mut ScriptStack) -> Result<(), TidecoinValidationError> {
1073        let data = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1074        let hash = ripemd160::Hash::hash(&data);
1075        self.push_element(stack, hash.to_byte_array().to_vec())
1076    }
1077
1078    fn op_sha1(&mut self, stack: &mut ScriptStack) -> Result<(), TidecoinValidationError> {
1079        let data = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1080        let hash = sha1::Hash::hash(&data);
1081        self.push_element(stack, hash.to_byte_array().to_vec())
1082    }
1083
1084    fn op_sha256(&mut self, stack: &mut ScriptStack) -> Result<(), TidecoinValidationError> {
1085        let data = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1086        let hash = sha256::Hash::hash(&data);
1087        self.push_element(stack, hash.to_byte_array().to_vec())
1088    }
1089
1090    fn op_hash256(&mut self, stack: &mut ScriptStack) -> Result<(), TidecoinValidationError> {
1091        let data = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1092        let hash = sha256d::Hash::hash(&data);
1093        self.push_element(stack, hash.to_byte_array().to_vec())
1094    }
1095
1096    fn op_sha512(&mut self, stack: &mut ScriptStack) -> Result<(), TidecoinValidationError> {
1097        if self.flags.bits() & VERIFY_SHA512 == 0 {
1098            if self.flags.bits() & VERIFY_DISCOURAGE_UPGRADABLE_NOPS != 0 {
1099                return Err(self.fail(ScriptError::DiscourageUpgradableNops));
1100            }
1101            return Ok(());
1102        }
1103
1104        let data = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1105        let hash = sha512::Hash::hash(&data);
1106        self.push_element(stack, hash.to_byte_array().to_vec())
1107    }
1108
1109    fn op_equal(&mut self, stack: &mut ScriptStack) -> Result<(), TidecoinValidationError> {
1110        let a = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1111        let b = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1112        self.push_bool_element(stack, a == b)
1113    }
1114
1115    fn op_verify(&mut self, stack: &mut ScriptStack) -> Result<(), TidecoinValidationError> {
1116        self.op_verify_with_code(stack, ScriptError::Verify)
1117    }
1118
1119    fn op_verify_with_code(
1120        &mut self,
1121        stack: &mut ScriptStack,
1122        error: ScriptError,
1123    ) -> Result<(), TidecoinValidationError> {
1124        let value = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1125        if !read_scriptbool(&value) {
1126            return Err(self.fail(error));
1127        }
1128        Ok(())
1129    }
1130
1131    fn op_checksig(
1132        &mut self,
1133        stack: &mut ScriptStack,
1134        script: &RawScript,
1135        code_separator: usize,
1136        sigversion: SigVersion,
1137    ) -> Result<(), TidecoinValidationError> {
1138        let pubkey = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1139        let sig = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1140        let script_code =
1141            self.build_signature_script_code(script, code_separator, sigversion, &[&sig])?;
1142        let result =
1143            self.verify_signature_against_code(&sig, &pubkey, script_code.as_script(), sigversion)?;
1144        if !result && self.flags.bits() & VERIFY_NULLFAIL != 0 && !sig.is_empty() {
1145            return Err(self.fail(ScriptError::NullFail));
1146        }
1147        self.push_bool_element(stack, result)
1148    }
1149
1150    fn op_checkmultisig(
1151        &mut self,
1152        stack: &mut ScriptStack,
1153        script: &RawScript,
1154        code_separator: usize,
1155        sigversion: SigVersion,
1156    ) -> Result<(), TidecoinValidationError> {
1157        let require_minimal = self.flags.bits() & VERIFY_MINIMALDATA != 0;
1158        let n_keys = self.pop_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN)?;
1159        if n_keys < 0 || n_keys as usize > MAX_PUBKEYS_PER_MULTISIG {
1160            return Err(self.fail(ScriptError::PubkeyCount));
1161        }
1162        let n_keys = n_keys as usize;
1163        self.add_ops(n_keys)?;
1164        if stack.len() < n_keys {
1165            return Err(self.fail(ScriptError::InvalidStackOperation));
1166        }
1167
1168        let mut pubkeys = Vec::with_capacity(n_keys);
1169        for _ in 0..n_keys {
1170            let key = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1171            pubkeys.push(key);
1172        }
1173
1174        let n_sigs = self.pop_scriptnum(stack, require_minimal, SCRIPTNUM_MAX_LEN)?;
1175        if n_sigs < 0 || n_sigs as usize > n_keys {
1176            return Err(self.fail(ScriptError::SigCount));
1177        }
1178        let n_sigs = n_sigs as usize;
1179        if stack.len() < n_sigs + 1 {
1180            return Err(self.fail(ScriptError::InvalidStackOperation));
1181        }
1182
1183        let mut sigs = Vec::with_capacity(n_sigs);
1184        for _ in 0..n_sigs {
1185            let sig = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1186            sigs.push(sig);
1187        }
1188
1189        let signatures = sigs.iter().map(Vec::as_slice).collect::<Vec<_>>();
1190        let script_code =
1191            self.build_signature_script_code(script, code_separator, sigversion, &signatures)?;
1192        let dummy = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1193        if self.flags.bits() & VERIFY_NULLDUMMY != 0 && !dummy.is_empty() {
1194            return Err(self.fail(ScriptError::SigNullDummy));
1195        }
1196
1197        let mut success = true;
1198        let mut sig_index = 0usize;
1199        let mut key_index = 0usize;
1200        let enforce_nullfail = self.flags.bits() & VERIFY_NULLFAIL != 0;
1201
1202        while success && sig_index < sigs.len() {
1203            if pubkeys.len() - key_index < sigs.len() - sig_index {
1204                success = false;
1205                break;
1206            }
1207
1208            let sig_valid = self.verify_signature_against_code(
1209                &sigs[sig_index],
1210                &pubkeys[key_index],
1211                script_code.as_script(),
1212                sigversion,
1213            )?;
1214            if sig_valid {
1215                sig_index += 1;
1216            }
1217            key_index += 1;
1218        }
1219
1220        if !success && enforce_nullfail {
1221            let has_non_empty = sigs.iter().any(|sig| !sig.is_empty());
1222            if has_non_empty {
1223                return Err(self.fail(ScriptError::NullFail));
1224            }
1225        }
1226
1227        let remaining_keys = pubkeys.len().saturating_sub(key_index);
1228        let remaining_sigs = sigs.len().saturating_sub(sig_index);
1229        if remaining_sigs > remaining_keys {
1230            success = false;
1231        }
1232
1233        self.push_bool_element(stack, success)
1234    }
1235
1236    fn op_checksigadd(
1237        &mut self,
1238        _stack: &mut ScriptStack,
1239        _sigversion: SigVersion,
1240    ) -> Result<(), TidecoinValidationError> {
1241        Err(self.fail(ScriptError::BadOpcode))
1242    }
1243
1244    fn pop_scriptnum(
1245        &mut self,
1246        stack: &mut ScriptStack,
1247        minimal: bool,
1248        max_len: usize,
1249    ) -> Result<i64, TidecoinValidationError> {
1250        let bytes = self.map_failure(stack.pop_bytes(), ScriptError::InvalidStackOperation)?;
1251        self.decode_scriptnum(&bytes, minimal, max_len)
1252    }
1253
1254    fn peek_scriptnum(
1255        &mut self,
1256        stack: &ScriptStack,
1257        minimal: bool,
1258        max_len: usize,
1259    ) -> Result<i64, TidecoinValidationError> {
1260        let bytes = stack.last().ok_or_else(|| self.fail(ScriptError::InvalidStackOperation))?;
1261        self.decode_scriptnum(bytes, minimal, max_len)
1262    }
1263
1264    fn decode_scriptnum(
1265        &mut self,
1266        bytes: &[u8],
1267        minimal: bool,
1268        max_len: usize,
1269    ) -> Result<i64, TidecoinValidationError> {
1270        parse_scriptnum(bytes, minimal, max_len).map_err(|err| self.fail(err))
1271    }
1272
1273    fn check_lock_time(&self, locktime: u64) -> Result<(), ScriptError> {
1274        if locktime > u32::MAX as u64 {
1275            return Err(ScriptError::UnsatisfiedLockTime);
1276        }
1277
1278        let tx = self.tx_ctx.tx();
1279        let tx_lock = tx.lock_time.to_consensus_u32();
1280        let locktime_u32 = locktime as u32;
1281        if tx_lock < locktime_u32 {
1282            return Err(ScriptError::UnsatisfiedLockTime);
1283        }
1284
1285        if (tx_lock < LOCK_TIME_THRESHOLD) != (locktime_u32 < LOCK_TIME_THRESHOLD) {
1286            return Err(ScriptError::UnsatisfiedLockTime);
1287        }
1288
1289        let sequence = tx.inputs[self.input_index].sequence.to_consensus_u32();
1290        if sequence == Sequence::MAX.to_consensus_u32() {
1291            return Err(ScriptError::UnsatisfiedLockTime);
1292        }
1293
1294        Ok(())
1295    }
1296
1297    fn check_sequence(&self, sequence: u64) -> Result<(), ScriptError> {
1298        if (sequence as u32) & SEQUENCE_LOCKTIME_DISABLE_FLAG != 0 {
1299            return Ok(());
1300        }
1301        // CSV version gating uses unsigned transaction-version semantics.
1302        // That means negative serialized values (e.g. 0xffffffff) are treated
1303        // as large versions and satisfy the version gate.
1304        if self.tx_ctx.tx().version.to_u32() < 2 {
1305            return Err(ScriptError::UnsatisfiedLockTime);
1306        }
1307
1308        let tx_sequence = self.tx_ctx.tx().inputs[self.input_index].sequence.to_consensus_u32();
1309        if tx_sequence & SEQUENCE_LOCKTIME_DISABLE_FLAG != 0 {
1310            return Err(ScriptError::UnsatisfiedLockTime);
1311        }
1312
1313        let locktime_mask = SEQUENCE_LOCKTIME_TYPE_FLAG | SEQUENCE_LOCKTIME_MASK;
1314        let tx_sequence_masked = tx_sequence & locktime_mask;
1315        let sequence_masked = (sequence as u32) & locktime_mask;
1316        let tx_is_time = tx_sequence_masked >= SEQUENCE_LOCKTIME_TYPE_FLAG;
1317        let sequence_is_time = sequence_masked >= SEQUENCE_LOCKTIME_TYPE_FLAG;
1318        if tx_is_time != sequence_is_time {
1319            return Err(ScriptError::UnsatisfiedLockTime);
1320        }
1321
1322        if sequence_masked > tx_sequence_masked {
1323            return Err(ScriptError::UnsatisfiedLockTime);
1324        }
1325
1326        Ok(())
1327    }
1328
1329    fn build_script_code(
1330        &mut self,
1331        script: &RawScript,
1332        code_separator: usize,
1333        sigversion: SigVersion,
1334    ) -> Result<RawScriptBuf, TidecoinValidationError> {
1335        let strip_codeseparators = matches!(sigversion, SigVersion::Base);
1336        let identity = ScriptIdentity::new(script);
1337        let needs_refresh = self
1338            .script_code_cache
1339            .as_ref()
1340            .map(|cache| !cache.matches(identity, code_separator, strip_codeseparators))
1341            .unwrap_or(true);
1342        if needs_refresh {
1343            let script_buf =
1344                Self::materialize_script_code(script, code_separator, strip_codeseparators)?;
1345            self.script_code_cache = Some(ScriptCodeCache {
1346                identity,
1347                code_separator,
1348                strip_codeseparators,
1349                script: script_buf,
1350            });
1351        }
1352        Ok(self
1353            .script_code_cache
1354            .as_ref()
1355            .expect("script code cache is initialized")
1356            .script
1357            .clone())
1358    }
1359
1360    fn materialize_script_code(
1361        script: &RawScript,
1362        code_separator: usize,
1363        strip_codeseparators: bool,
1364    ) -> Result<RawScriptBuf, TidecoinValidationError> {
1365        if code_separator > script.as_bytes().len() {
1366            return Err(script_unknown());
1367        }
1368        let tail = &script.as_bytes()[code_separator..];
1369        if strip_codeseparators {
1370            let stripped = strip_opcode(tail, all::OP_CODESEPARATOR)?;
1371            Ok(RawScriptBuf::from_bytes(stripped))
1372        } else {
1373            Ok(RawScriptBuf::from_bytes(tail.to_vec()))
1374        }
1375    }
1376
1377    fn execute_witness_program(
1378        &mut self,
1379        version: u8,
1380        program: &[u8],
1381        witness: &'tx Witness,
1382        is_p2sh: bool,
1383    ) -> Result<(), TidecoinValidationError> {
1384        let _ = is_p2sh;
1385        let plan = WitnessProgram::parse_program(version, program)
1386            .execution_plan(self.flags.bits(), witness)
1387            .map_err(|err| self.fail(map_core_script_error(err)))?;
1388        match plan {
1389            WitnessExecutionPlan::Upgradable => Ok(()),
1390            WitnessExecutionPlan::Execute { sigversion, script_bytes, stack_items, sigops } => {
1391                match sigops {
1392                    WitnessSigops::None => {}
1393                    WitnessSigops::Fixed(count) => self.add_sigops(count)?,
1394                    WitnessSigops::CountExecutedScript => {
1395                        self.add_sigops_from_script(&script_bytes, true)?
1396                    }
1397                }
1398
1399                let mut stack =
1400                    ScriptStack::from_items(stack_items).map_err(|err| self.fail(err))?;
1401                let sigversion = match sigversion {
1402                    WitnessSigVersion::V0 => SigVersion::WitnessV0,
1403                    WitnessSigVersion::V1_512 => SigVersion::WitnessV1_512,
1404                };
1405                self.run_script(&mut stack, &script_bytes, sigversion)?;
1406                self.ensure_witness_success(&stack)
1407            }
1408        }
1409    }
1410
1411    fn require_clean_stack(&self, stack: &ScriptStack) -> Result<(), ScriptError> {
1412        if stack.len() != 1 {
1413            return Err(ScriptError::CleanStack);
1414        }
1415        if !read_scriptbool(stack.last().expect("stack length checked")) {
1416            return Err(ScriptError::CleanStack);
1417        }
1418        Ok(())
1419    }
1420
1421    fn ensure_witness_success(
1422        &mut self,
1423        stack: &ScriptStack,
1424    ) -> Result<(), TidecoinValidationError> {
1425        if stack.len() != 1 {
1426            return Err(self.fail(ScriptError::CleanStack));
1427        }
1428        if !read_scriptbool(stack.last().expect("stack length checked")) {
1429            return Err(self.fail(ScriptError::EvalFalse));
1430        }
1431        Ok(())
1432    }
1433
1434    fn verify_signature_against_code(
1435        &mut self,
1436        sig_with_hash_type: &[u8],
1437        pubkey_bytes: &[u8],
1438        script_code: &RawScript,
1439        sigversion: SigVersion,
1440    ) -> Result<bool, TidecoinValidationError> {
1441        if let Ok(pubkey) = PqPublicKey::from_prefixed_slice(pubkey_bytes) {
1442            return self.verify_pq_signature_against_code(
1443                sig_with_hash_type,
1444                &pubkey,
1445                script_code,
1446                sigversion,
1447            );
1448        }
1449        Ok(false)
1450    }
1451
1452    fn verify_pq_signature_against_code(
1453        &mut self,
1454        sig_with_hash_type: &[u8],
1455        pubkey: &PqPublicKey,
1456        script_code: &RawScript,
1457        sigversion: SigVersion,
1458    ) -> Result<bool, TidecoinValidationError> {
1459        let (sig_bytes, hash_type) = split_signature_hash_type(sig_with_hash_type);
1460        if sig_bytes.is_empty() || (sigversion == SigVersion::WitnessV1_512 && hash_type == 0) {
1461            return Ok(false);
1462        }
1463        let sig = PqSignature::from_slice(sig_bytes);
1464        let verified = match sigversion {
1465            SigVersion::Base => {
1466                let sighash = self
1467                    .sighash_cache
1468                    .borrow()
1469                    .legacy_signature_hash(
1470                        self.input_index,
1471                        script_code.as_bytes(),
1472                        hash_type as u32,
1473                    )
1474                    .map_err(|_| script_unknown())?;
1475                let msg = *sighash.as_byte_array();
1476                if self.flags.bits() & VERIFY_PQ_STRICT != 0 {
1477                    sig.verify_msg32(&msg, pubkey).is_ok()
1478                } else {
1479                    sig.verify_msg32_allow_legacy(&msg, pubkey).is_ok()
1480                }
1481            }
1482            SigVersion::WitnessV0 => {
1483                let sighash = self.segwit_v0_signature_hash(script_code, hash_type as u32)?;
1484                let msg = *sighash.as_byte_array();
1485                if self.flags.bits() & VERIFY_PQ_STRICT != 0 {
1486                    sig.verify_msg32(&msg, pubkey).is_ok()
1487                } else {
1488                    sig.verify_msg32_allow_legacy(&msg, pubkey).is_ok()
1489                }
1490            }
1491            SigVersion::WitnessV1_512 => {
1492                let sighash = self.witness_v1_512_signature_hash(script_code, hash_type as u32)?;
1493                if self.flags.bits() & VERIFY_PQ_STRICT != 0 {
1494                    sig.verify_msg64(sighash.as_byte_array(), pubkey).is_ok()
1495                } else {
1496                    sig.verify_msg64_allow_legacy(sighash.as_byte_array(), pubkey).is_ok()
1497                }
1498            }
1499        };
1500        Ok(verified)
1501    }
1502
1503    fn build_signature_script_code(
1504        &mut self,
1505        script: &RawScript,
1506        code_separator: usize,
1507        sigversion: SigVersion,
1508        signatures: &[&[u8]],
1509    ) -> Result<RawScriptBuf, TidecoinValidationError> {
1510        let mut script_code = self.build_script_code(script, code_separator, sigversion)?;
1511        if sigversion == SigVersion::Base {
1512            script_code = self.apply_legacy_find_and_delete(script_code.as_script(), signatures)?;
1513        }
1514        Ok(script_code)
1515    }
1516
1517    fn apply_legacy_find_and_delete(
1518        &mut self,
1519        script_code: &RawScript,
1520        signatures: &[&[u8]],
1521    ) -> Result<RawScriptBuf, TidecoinValidationError> {
1522        let mut script_bytes = script_code.as_bytes().to_vec();
1523        for signature in signatures {
1524            let sig_push = single_push_script(signature).map_err(|_| script_unknown())?;
1525            let (filtered, removed) = find_and_delete(&script_bytes, sig_push.as_bytes());
1526            if removed > 0 && self.flags.bits() & VERIFY_CONST_SCRIPTCODE != 0 {
1527                return Err(self.fail(ScriptError::SigFindAndDelete));
1528            }
1529            script_bytes = filtered;
1530        }
1531        Ok(RawScriptBuf::from_bytes(script_bytes))
1532    }
1533
1534    fn segwit_v0_signature_hash(
1535        &mut self,
1536        script_code: &RawScript,
1537        raw_sighash_type: u32,
1538    ) -> Result<SegwitV0Sighash, TidecoinValidationError> {
1539        let _ = self.ensure_precomputed();
1540        let sighash_type = TxSighashType::from_consensus(raw_sighash_type);
1541        self.sighash_cache
1542            .borrow_mut()
1543            .p2wsh_signature_hash(
1544                self.input_index,
1545                script_code.as_bytes(),
1546                Amount::from_sat(self.amount)
1547                    .map_err(|_| TidecoinValidationError::AmountRequired)?,
1548                sighash_type,
1549            )
1550            .map_err(|_| script_unknown())
1551    }
1552
1553    fn witness_v1_512_signature_hash(
1554        &mut self,
1555        script_code: &RawScript,
1556        raw_sighash_type: u32,
1557    ) -> Result<Sighash512, TidecoinValidationError> {
1558        let _ = self.ensure_precomputed();
1559        let sighash_type = TxSighashType::from_consensus(raw_sighash_type);
1560        self.sighash_cache
1561            .borrow_mut()
1562            .p2wsh512_signature_hash(
1563                self.input_index,
1564                script_code.as_bytes(),
1565                Amount::from_sat(self.amount)
1566                    .map_err(|_| TidecoinValidationError::AmountRequired)?,
1567                sighash_type,
1568            )
1569            .map_err(|_| script_unknown())
1570    }
1571
1572    fn ensure_precomputed(&mut self) -> &PrecomputedTransactionData {
1573        if self.precomputed.is_none() {
1574            self.precomputed =
1575                Some(self.tx_ctx.build_precomputed(self.spent_outputs.as_ref(), false));
1576        }
1577        self.precomputed.as_ref().expect("precomputed data initialized")
1578    }
1579}
1580
1581fn parse_scriptnum(bytes: &[u8], minimal: bool, max_len: usize) -> Result<i64, ScriptError> {
1582    match read_scriptnum(bytes, minimal, max_len) {
1583        Ok(value) => Ok(value),
1584        Err(ScriptIntError::NumericOverflow | ScriptIntError::NonMinimal) => {
1585            Err(ScriptError::Unknown)
1586        }
1587        Err(_) => Err(ScriptError::Unknown),
1588    }
1589}
1590
1591fn is_push_only(script_bytes: &[u8]) -> bool {
1592    let mut offset = 0usize;
1593    while let Some((_, instruction)) = next_instruction(script_bytes, &mut offset, false) {
1594        match instruction {
1595            Ok(Instruction::PushBytes(_)) => {}
1596            Ok(Instruction::Op(op)) if op.to_u8() <= 0x60 => {}
1597            Ok(Instruction::Op(_)) | Err(_) => return false,
1598        }
1599    }
1600    true
1601}
1602
1603fn is_p2sh(script_bytes: &[u8]) -> bool {
1604    script_bytes.len() == 23
1605        && script_bytes[0] == all::OP_HASH160.to_u8()
1606        && script_bytes[1] == all::OP_PUSHBYTES_20.to_u8()
1607        && script_bytes[22] == all::OP_EQUAL.to_u8()
1608}
1609
1610fn single_push_script(data: &[u8]) -> Result<RawScriptBuf, primitives::script::PushBytesError> {
1611    let push = PushBytesBuf::try_from(data.to_vec())?;
1612    Ok(Builder::new().push_slice(push).into_script())
1613}
1614
1615fn map_core_script_error(error: ScriptError) -> ScriptError {
1616    error
1617}
1618
1619fn is_control_flow(op: Opcode) -> bool {
1620    use all::*;
1621
1622    matches!(op, OP_IF | OP_NOTIF | OP_ELSE | OP_ENDIF)
1623}
1624
1625fn is_minimal_if_condition(data: &[u8]) -> bool {
1626    data.len() == 1 && data[0] == 1
1627}
1628
1629fn split_signature_hash_type(sig: &[u8]) -> (&[u8], u8) {
1630    match sig.split_last() {
1631        Some((&hash_type, body)) => (body, hash_type),
1632        None => (&[], 0),
1633    }
1634}
1635
1636fn is_minimal_push(opcode: u8, data: &[u8]) -> bool {
1637    use all::*;
1638
1639    if data.is_empty() {
1640        return opcode == OP_PUSHBYTES_0.to_u8();
1641    }
1642
1643    if data.len() == 1 {
1644        let value = data[0];
1645        if value == 0x81 {
1646            return opcode == OP_PUSHNUM_NEG1.to_u8();
1647        }
1648        if (1..=16).contains(&value) {
1649            return opcode == OP_PUSHNUM_1.to_u8() + value - 1;
1650        }
1651    }
1652
1653    if data.len() <= 75 {
1654        return opcode as usize == data.len();
1655    }
1656    if data.len() <= 0xff {
1657        return opcode == OP_PUSHDATA1.to_u8();
1658    }
1659    if data.len() <= 0xffff {
1660        return opcode == OP_PUSHDATA2.to_u8();
1661    }
1662    opcode == OP_PUSHDATA4.to_u8()
1663}
1664
1665fn strip_opcode(script_bytes: &[u8], opcode: Opcode) -> Result<Vec<u8>, Error> {
1666    let instructions =
1667        collect_instruction_indices(script_bytes, false).map_err(|_| script_unknown())?;
1668    let mut stripped = Vec::with_capacity(script_bytes.len());
1669
1670    for (idx, (pos, instruction)) in instructions.iter().enumerate() {
1671        if matches!(instruction, Instruction::Op(op) if *op == opcode) {
1672            continue;
1673        }
1674        let next_pos =
1675            if idx + 1 < instructions.len() { instructions[idx + 1].0 } else { script_bytes.len() };
1676        stripped.extend_from_slice(&script_bytes[*pos..next_pos]);
1677    }
1678
1679    Ok(stripped)
1680}
1681
1682fn find_and_delete(script_bytes: &[u8], pattern: &[u8]) -> (Vec<u8>, usize) {
1683    if pattern.is_empty() {
1684        return (script_bytes.to_vec(), 0);
1685    }
1686    if script_bytes.len() < pattern.len() {
1687        return (script_bytes.to_vec(), 0);
1688    }
1689
1690    let mut removed = 0usize;
1691    let mut result = Vec::with_capacity(script_bytes.len());
1692    let mut pc = 0usize;
1693    let mut pc2 = 0usize;
1694    let end = script_bytes.len();
1695
1696    loop {
1697        result.extend_from_slice(&script_bytes[pc2..pc]);
1698        while pc + pattern.len() <= end && &script_bytes[pc..pc + pattern.len()] == pattern {
1699            pc += pattern.len();
1700            removed += 1;
1701        }
1702        pc2 = pc;
1703        let Some(next_pc) = next_instruction_offset(script_bytes, pc) else {
1704            break;
1705        };
1706        pc = next_pc;
1707    }
1708
1709    if removed > 0 {
1710        result.extend_from_slice(&script_bytes[pc2..end]);
1711        (result, removed)
1712    } else {
1713        (script_bytes.to_vec(), 0)
1714    }
1715}
1716
1717fn next_instruction_offset(script_bytes: &[u8], offset: usize) -> Option<usize> {
1718    if offset >= script_bytes.len() {
1719        return None;
1720    }
1721
1722    let opcode = script_bytes[offset];
1723    let mut cursor = offset + 1;
1724    match opcode {
1725        0x01..=0x4b => {
1726            let push_len = opcode as usize;
1727            cursor = cursor.checked_add(push_len)?;
1728            if cursor <= script_bytes.len() {
1729                Some(cursor)
1730            } else {
1731                None
1732            }
1733        }
1734        0x4c => {
1735            let len = *script_bytes.get(cursor)? as usize;
1736            cursor += 1;
1737            cursor = cursor.checked_add(len)?;
1738            (cursor <= script_bytes.len()).then_some(cursor)
1739        }
1740        0x4d => {
1741            let bytes = script_bytes.get(cursor..cursor + 2)?;
1742            let len = u16::from_le_bytes([bytes[0], bytes[1]]) as usize;
1743            cursor += 2;
1744            cursor = cursor.checked_add(len)?;
1745            (cursor <= script_bytes.len()).then_some(cursor)
1746        }
1747        0x4e => {
1748            let bytes = script_bytes.get(cursor..cursor + 4)?;
1749            let len = u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize;
1750            cursor += 4;
1751            cursor = cursor.checked_add(len)?;
1752            (cursor <= script_bytes.len()).then_some(cursor)
1753        }
1754        _ => Some(cursor),
1755    }
1756}
1757
1758fn read_push_length(bytes: &[u8], index: &mut usize, width: usize) -> Result<usize, ScriptError> {
1759    if bytes.len() < *index + width {
1760        return Err(ScriptError::BadOpcode);
1761    }
1762    let mut len: usize = 0;
1763    for i in 0..width {
1764        len |= (bytes[*index + i] as usize) << (8 * i);
1765    }
1766    *index += width;
1767    Ok(len)
1768}
1769
1770fn count_sigops_bytes(script_bytes: &[u8], accurate: bool) -> Result<u32, TidecoinValidationError> {
1771    count_sigops(script_bytes, accurate)
1772}
1773
1774fn count_sigops(script_bytes: &[u8], accurate: bool) -> Result<u32, TidecoinValidationError> {
1775    use all::*;
1776
1777    let mut total: u32 = 0;
1778    let mut last_op: Option<Opcode> = None;
1779    let mut offset = 0usize;
1780    while let Some((_, instruction)) = next_instruction(script_bytes, &mut offset, false) {
1781        let Ok(instruction) = instruction else {
1782            // Stop counting when decoding fails and return the count
1783            // accumulated so far.
1784            break;
1785        };
1786        match instruction {
1787            Instruction::Op(opcode) => {
1788                match opcode {
1789                    OP_CHECKSIG | OP_CHECKSIGVERIFY => {
1790                        total = total.checked_add(1).ok_or(script_unknown())?;
1791                    }
1792                    OP_CHECKMULTISIG | OP_CHECKMULTISIGVERIFY => {
1793                        let add = if accurate {
1794                            decode_op_n(last_op).unwrap_or(MAX_PUBKEYS_PER_MULTISIG as u32)
1795                        } else {
1796                            MAX_PUBKEYS_PER_MULTISIG as u32
1797                        };
1798                        total = total.checked_add(add).ok_or(script_unknown())?;
1799                    }
1800                    _ => {}
1801                }
1802                last_op = Some(opcode);
1803            }
1804            Instruction::PushBytes(_) => {
1805                last_op = None;
1806            }
1807        }
1808    }
1809
1810    Ok(total)
1811}
1812
1813fn collect_instruction_indices<'a>(
1814    script_bytes: &'a [u8],
1815    enforce_minimal: bool,
1816) -> Result<Vec<(usize, Instruction<'a>)>, ScriptError> {
1817    let mut offset = 0usize;
1818    let mut out = Vec::new();
1819    while let Some((pos, instruction)) =
1820        next_instruction(script_bytes, &mut offset, enforce_minimal)
1821    {
1822        out.push((pos, instruction?));
1823    }
1824    Ok(out)
1825}
1826
1827fn next_instruction<'a>(
1828    script_bytes: &'a [u8],
1829    offset: &mut usize,
1830    enforce_minimal: bool,
1831) -> Option<(usize, Result<Instruction<'a>, ScriptError>)> {
1832    if *offset >= script_bytes.len() {
1833        return None;
1834    }
1835
1836    let pos = *offset;
1837    let opcode = script_bytes[*offset];
1838    *offset += 1;
1839
1840    let push_len = match opcode {
1841        0x01..=0x4b => Some(opcode as usize),
1842        0x4c => match script_bytes.get(*offset) {
1843            Some(&len) => {
1844                *offset += 1;
1845                Some(len as usize)
1846            }
1847            None => return Some((pos, Err(ScriptError::BadOpcode))),
1848        },
1849        0x4d => match script_bytes.get(*offset..*offset + 2) {
1850            Some(bytes) => {
1851                *offset += 2;
1852                Some(u16::from_le_bytes([bytes[0], bytes[1]]) as usize)
1853            }
1854            None => return Some((pos, Err(ScriptError::BadOpcode))),
1855        },
1856        0x4e => match script_bytes.get(*offset..*offset + 4) {
1857            Some(bytes) => {
1858                *offset += 4;
1859                Some(u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]) as usize)
1860            }
1861            None => return Some((pos, Err(ScriptError::BadOpcode))),
1862        },
1863        _ => None,
1864    };
1865
1866    if let Some(push_len) = push_len {
1867        let data = match script_bytes.get(*offset..*offset + push_len) {
1868            Some(data) => data,
1869            None => return Some((pos, Err(ScriptError::BadOpcode))),
1870        };
1871        if enforce_minimal && !is_minimal_push(opcode, data) {
1872            return Some((pos, Err(ScriptError::BadOpcode)));
1873        }
1874        *offset += push_len;
1875        let push_bytes: &primitives::script::PushBytes =
1876            data.try_into().expect("push slice length came from script bytes");
1877        return Some((pos, Ok(Instruction::PushBytes(push_bytes))));
1878    }
1879
1880    Some((pos, Ok(Instruction::Op(Opcode::from(opcode)))))
1881}
1882
1883fn decode_op_n(opcode: Option<Opcode>) -> Option<u32> {
1884    use all::*;
1885
1886    let op = opcode?;
1887    let value = op.to_u8();
1888    if value >= OP_PUSHNUM_1.to_u8() && value <= OP_PUSHNUM_16.to_u8() {
1889        Some((value - OP_PUSHNUM_1.to_u8() + 1) as u32)
1890    } else {
1891        None
1892    }
1893}
1894
1895#[cfg(test)]
1896mod tests {
1897    use super::*;
1898    use crate::{VERIFY_P2SH, VERIFY_SIGPUSHONLY, VERIFY_WITNESS};
1899    use alloc::vec;
1900    use hashes::sha256;
1901    use primitives::{
1902        absolute::LockTime,
1903        opcodes::all,
1904        script::{
1905            Builder as BuilderT, PushBytesBuf, ScriptBuf as ScriptBufT, ScriptPubKeyBuf,
1906            ScriptSigBuf,
1907        },
1908        Amount, OutPoint, Sequence, Transaction, TransactionVersion, TxIn, TxOut, Txid, Witness,
1909    };
1910
1911    type Builder = BuilderT<()>;
1912    type ScriptBuf = ScriptBufT<()>;
1913
1914    fn hex_bytes(s: &str) -> Vec<u8> {
1915        assert!(s.len().is_multiple_of(2), "hex string must have an even length");
1916        s.as_bytes()
1917            .chunks_exact(2)
1918            .map(|chunk| {
1919                let hi = (chunk[0] as char).to_digit(16).expect("valid hex") as u8;
1920                let lo = (chunk[1] as char).to_digit(16).expect("valid hex") as u8;
1921                (hi << 4) | lo
1922            })
1923            .collect()
1924    }
1925
1926    fn dummy_outpoint() -> OutPoint {
1927        OutPoint { txid: Txid::from_byte_array([1u8; 32]), vout: 0 }
1928    }
1929
1930    #[test]
1931    fn rejects_unknown_flags() {
1932        let invalid_bit = 1 << 31;
1933        ScriptFlags::from_bits(invalid_bit).expect_err("invalid flag");
1934    }
1935
1936    #[test]
1937    fn flag_roundtrip_without_implied_bits_is_lossless() {
1938        let bits = VERIFY_P2SH | VERIFY_SIGPUSHONLY;
1939        let flags = ScriptFlags::from_bits(bits).unwrap();
1940        assert_eq!(flags.bits(), bits);
1941    }
1942
1943    #[test]
1944    fn witness_flag_does_not_imply_p2sh() {
1945        let flags = ScriptFlags::from_bits(VERIFY_WITNESS).unwrap();
1946        assert_eq!(flags.bits(), VERIFY_WITNESS);
1947    }
1948
1949    #[test]
1950    fn truncated_push_is_error() {
1951        let script: ScriptBuf = ScriptBuf::from_bytes(vec![0x4c, 0x01]);
1952        let instructions = collect_instruction_indices(script.as_bytes(), false);
1953        assert!(instructions.is_err());
1954    }
1955
1956    #[test]
1957    fn sigop_counter_counts_checksig_ops() {
1958        let script = Builder::new()
1959            .push_opcode(all::OP_DUP)
1960            .push_opcode(all::OP_CHECKSIG)
1961            .push_opcode(all::OP_CHECKSIGVERIFY)
1962            .into_script();
1963        assert_eq!(count_sigops_bytes(script.as_bytes(), true).unwrap(), 2);
1964        assert_eq!(count_sigops_bytes(script.as_bytes(), false).unwrap(), 2);
1965    }
1966
1967    #[test]
1968    fn sigop_counter_handles_multisig_precision() {
1969        let key1 = PushBytesBuf::try_from(vec![0x02; 33]).unwrap();
1970        let key2 = PushBytesBuf::try_from(vec![0x03; 33]).unwrap();
1971        let script = Builder::new()
1972            .push_opcode(all::OP_PUSHNUM_2)
1973            .push_slice(key1)
1974            .push_slice(key2)
1975            .push_opcode(all::OP_PUSHNUM_2)
1976            .push_opcode(all::OP_CHECKMULTISIG)
1977            .into_script();
1978        assert_eq!(count_sigops_bytes(script.as_bytes(), true).unwrap(), 2);
1979        assert_eq!(
1980            count_sigops_bytes(script.as_bytes(), false).unwrap(),
1981            MAX_PUBKEYS_PER_MULTISIG as u32
1982        );
1983    }
1984
1985    #[test]
1986    fn sigop_counter_ignores_checksigadd() {
1987        let script = Builder::new()
1988            .push_opcode(all::OP_CHECKSIG)
1989            .push_opcode(all::OP_CHECKSIGADD)
1990            .push_opcode(all::OP_CHECKSIGVERIFY)
1991            .into_script();
1992        assert_eq!(count_sigops_bytes(script.as_bytes(), true).unwrap(), 2);
1993    }
1994
1995    #[test]
1996    fn sigop_counter_stops_at_malformed_pushdata() {
1997        let malformed: ScriptBuf =
1998            ScriptBuf::from_bytes(vec![all::OP_CHECKSIG.to_u8(), all::OP_PUSHDATA1.to_u8(), 0x01]);
1999        assert_eq!(count_sigops_bytes(malformed.as_bytes(), true).unwrap(), 1);
2000    }
2001
2002    #[test]
2003    fn witness_v0_p2wpkh_path_charges_single_sigop() {
2004        let witness = Witness::from(vec![vec![], vec![0x02; 33]]);
2005        let tx = Transaction {
2006            version: TransactionVersion::TWO,
2007            lock_time: LockTime::ZERO,
2008            inputs: vec![TxIn {
2009                previous_output: dummy_outpoint(),
2010                script_sig: ScriptSigBuf::new(),
2011                sequence: Sequence::MAX,
2012                witness,
2013            }],
2014            outputs: vec![TxOut { amount: Amount::ZERO, script_pubkey: ScriptPubKeyBuf::new() }],
2015        };
2016        let tx_ctx = TransactionContext::new(&tx);
2017        let spent_script = Builder::new().push_opcode(all::OP_PUSHNUM_1).into_script();
2018        let spend_context = SpendContext::new(spent_script.as_bytes(), None, 0, true);
2019        let flags = ScriptFlags::from_bits(VERIFY_WITNESS | VERIFY_P2SH).expect("flags");
2020        let mut interpreter =
2021            Interpreter::new(&tx_ctx, 0, spend_context, flags).expect("interpreter");
2022
2023        let program = [0u8; 20];
2024        let _ =
2025            interpreter.execute_witness_program(0, &program, &tx_ctx.tx().inputs[0].witness, false);
2026        assert_eq!(interpreter.sigops, 1);
2027    }
2028
2029    #[test]
2030    fn witness_v0_p2wsh_path_charges_redeem_sigops() {
2031        let witness_script = Builder::new()
2032            .push_opcode(all::OP_CHECKSIG)
2033            .push_opcode(all::OP_CHECKSIGVERIFY)
2034            .into_script();
2035        let witness_script_bytes = witness_script.as_bytes().to_vec();
2036        let witness_program = sha256::Hash::hash(&witness_script_bytes);
2037        let witness = Witness::from(vec![vec![], vec![0x02; 33], witness_script_bytes]);
2038        let tx = Transaction {
2039            version: TransactionVersion::TWO,
2040            lock_time: LockTime::ZERO,
2041            inputs: vec![TxIn {
2042                previous_output: dummy_outpoint(),
2043                script_sig: ScriptSigBuf::new(),
2044                sequence: Sequence::MAX,
2045                witness,
2046            }],
2047            outputs: vec![TxOut { amount: Amount::ZERO, script_pubkey: ScriptPubKeyBuf::new() }],
2048        };
2049        let tx_ctx = TransactionContext::new(&tx);
2050        let spent_script = Builder::new().push_opcode(all::OP_PUSHNUM_1).into_script();
2051        let spend_context = SpendContext::new(spent_script.as_bytes(), None, 0, true);
2052        let flags = ScriptFlags::from_bits(VERIFY_WITNESS | VERIFY_P2SH).expect("flags");
2053        let mut interpreter =
2054            Interpreter::new(&tx_ctx, 0, spend_context, flags).expect("interpreter");
2055
2056        let _ = interpreter.execute_witness_program(
2057            0,
2058            &witness_program.to_byte_array(),
2059            &tx_ctx.tx().inputs[0].witness,
2060            false,
2061        );
2062        assert_eq!(interpreter.sigops, 2);
2063    }
2064
2065    #[test]
2066    fn p2sh_redeem_script_sigops_use_accurate_multisig_count() {
2067        let tx = Transaction {
2068            version: TransactionVersion::TWO,
2069            lock_time: LockTime::ZERO,
2070            inputs: vec![TxIn {
2071                previous_output: dummy_outpoint(),
2072                script_sig: ScriptSigBuf::new(),
2073                sequence: Sequence::MAX,
2074                witness: Witness::new(),
2075            }],
2076            outputs: vec![TxOut { amount: Amount::ZERO, script_pubkey: ScriptPubKeyBuf::new() }],
2077        };
2078        let tx_ctx = TransactionContext::new(&tx);
2079        let spent_script = Builder::new().push_opcode(all::OP_PUSHNUM_1).into_script();
2080        let spend_context = SpendContext::new(spent_script.as_bytes(), None, 0, true);
2081        let flags = ScriptFlags::from_bits(VERIFY_P2SH).expect("flags");
2082        let mut interpreter =
2083            Interpreter::new(&tx_ctx, 0, spend_context, flags).expect("interpreter");
2084
2085        let key1 = PushBytesBuf::try_from(vec![0x02; 33]).unwrap();
2086        let key2 = PushBytesBuf::try_from(vec![0x03; 33]).unwrap();
2087        let redeem_script = Builder::new()
2088            .push_opcode(all::OP_PUSHNUM_2)
2089            .push_slice(key1)
2090            .push_slice(key2)
2091            .push_opcode(all::OP_PUSHNUM_2)
2092            .push_opcode(all::OP_CHECKMULTISIG)
2093            .into_script();
2094        interpreter.add_sigops_from_script(redeem_script.as_bytes(), true).expect("sigop counting");
2095        assert_eq!(interpreter.sigops, 2);
2096    }
2097
2098    #[test]
2099    fn find_and_delete_matches_whole_pushes() {
2100        let pattern = single_push_script(&[0x02, 0x03]).unwrap();
2101        let script = Builder::new()
2102            .push_slice(PushBytesBuf::try_from(vec![0x02, 0x03]).unwrap())
2103            .push_opcode(all::OP_ADD)
2104            .push_slice(PushBytesBuf::try_from(vec![0x02, 0x03]).unwrap())
2105            .into_script();
2106        let (stripped, removed) = find_and_delete(script.as_bytes(), pattern.as_bytes());
2107        assert_eq!(removed, 2);
2108        assert_eq!(stripped, vec![all::OP_ADD.to_u8()]);
2109    }
2110
2111    #[test]
2112    fn find_and_delete_does_not_match_sub_slices() {
2113        let pattern = single_push_script(&[0xaa]).unwrap();
2114        let script = Builder::new()
2115            .push_slice(PushBytesBuf::try_from(vec![0xaa, 0xbb]).unwrap())
2116            .into_script();
2117        let (stripped, removed) = find_and_delete(script.as_bytes(), pattern.as_bytes());
2118        assert_eq!(removed, 0);
2119        assert_eq!(stripped, script.as_bytes());
2120    }
2121
2122    #[test]
2123    fn find_and_delete_matches_only_instruction_boundaries() {
2124        let pattern = single_push_script(&[]).unwrap();
2125        let script: ScriptBuf = ScriptBuf::from_bytes(vec![0x02, 0x00, 0x11, 0x00]);
2126        let (stripped, removed) = find_and_delete(script.as_bytes(), pattern.as_bytes());
2127        assert_eq!(removed, 1);
2128        assert_eq!(stripped, vec![0x02, 0x00, 0x11]);
2129    }
2130
2131    #[test]
2132    fn find_and_delete_core_edge_cases_matrix() {
2133        let check =
2134            |script: Vec<u8>, pattern: Vec<u8>, expected: Vec<u8>, expected_removed: usize| {
2135                let (stripped, removed) = find_and_delete(&script, &pattern);
2136                assert_eq!(removed, expected_removed);
2137                assert_eq!(stripped, expected);
2138            };
2139
2140        check(
2141            vec![all::OP_PUSHNUM_1.to_u8(), all::OP_PUSHNUM_2.to_u8()],
2142            vec![],
2143            vec![all::OP_PUSHNUM_1.to_u8(), all::OP_PUSHNUM_2.to_u8()],
2144            0,
2145        );
2146        check(
2147            vec![all::OP_PUSHNUM_1.to_u8(), all::OP_PUSHNUM_2.to_u8(), all::OP_PUSHNUM_3.to_u8()],
2148            vec![all::OP_PUSHNUM_2.to_u8()],
2149            vec![all::OP_PUSHNUM_1.to_u8(), all::OP_PUSHNUM_3.to_u8()],
2150            1,
2151        );
2152        check(
2153            vec![
2154                all::OP_PUSHNUM_3.to_u8(),
2155                all::OP_PUSHNUM_1.to_u8(),
2156                all::OP_PUSHNUM_3.to_u8(),
2157                all::OP_PUSHNUM_3.to_u8(),
2158                all::OP_PUSHNUM_4.to_u8(),
2159                all::OP_PUSHNUM_3.to_u8(),
2160            ],
2161            vec![all::OP_PUSHNUM_3.to_u8()],
2162            vec![all::OP_PUSHNUM_1.to_u8(), all::OP_PUSHNUM_4.to_u8()],
2163            4,
2164        );
2165        check(hex_bytes("0302ff03"), hex_bytes("0302ff03"), vec![], 1);
2166        check(hex_bytes("0302ff030302ff03"), hex_bytes("0302ff03"), vec![], 2);
2167        check(hex_bytes("0302ff030302ff03"), hex_bytes("02"), hex_bytes("0302ff030302ff03"), 0);
2168        check(hex_bytes("0302ff030302ff03"), hex_bytes("ff"), hex_bytes("0302ff030302ff03"), 0);
2169        check(hex_bytes("0302ff030302ff03"), hex_bytes("03"), hex_bytes("02ff0302ff03"), 2);
2170        check(hex_bytes("02feed5169"), hex_bytes("feed51"), hex_bytes("02feed5169"), 0);
2171        check(hex_bytes("02feed5169"), hex_bytes("02feed51"), hex_bytes("69"), 1);
2172        check(hex_bytes("516902feed5169"), hex_bytes("feed51"), hex_bytes("516902feed5169"), 0);
2173        check(hex_bytes("516902feed5169"), hex_bytes("02feed51"), hex_bytes("516969"), 1);
2174        check(
2175            vec![
2176                all::OP_PUSHBYTES_0.to_u8(),
2177                all::OP_PUSHBYTES_0.to_u8(),
2178                all::OP_PUSHNUM_1.to_u8(),
2179                all::OP_PUSHNUM_1.to_u8(),
2180            ],
2181            vec![all::OP_PUSHBYTES_0.to_u8(), all::OP_PUSHNUM_1.to_u8()],
2182            vec![all::OP_PUSHBYTES_0.to_u8(), all::OP_PUSHNUM_1.to_u8()],
2183            1,
2184        );
2185        check(
2186            vec![
2187                all::OP_PUSHBYTES_0.to_u8(),
2188                all::OP_PUSHBYTES_0.to_u8(),
2189                all::OP_PUSHNUM_1.to_u8(),
2190                all::OP_PUSHBYTES_0.to_u8(),
2191                all::OP_PUSHNUM_1.to_u8(),
2192                all::OP_PUSHNUM_1.to_u8(),
2193            ],
2194            vec![all::OP_PUSHBYTES_0.to_u8(), all::OP_PUSHNUM_1.to_u8()],
2195            vec![all::OP_PUSHBYTES_0.to_u8(), all::OP_PUSHNUM_1.to_u8()],
2196            2,
2197        );
2198        check(hex_bytes("0003feed"), hex_bytes("03feed"), hex_bytes("00"), 1);
2199        check(hex_bytes("0003feed"), hex_bytes("00"), hex_bytes("03feed"), 1);
2200    }
2201
2202    #[test]
2203    fn script_identity_depends_on_script_content() {
2204        let a: ScriptBuf = ScriptBuf::from_bytes(vec![all::OP_PUSHNUM_1.to_u8()]);
2205        let b: ScriptBuf = ScriptBuf::from_bytes(vec![all::OP_PUSHNUM_2.to_u8()]);
2206        assert_eq!(a.as_bytes().len(), b.as_bytes().len());
2207        assert!(ScriptIdentity::new(a.as_script()) != ScriptIdentity::new(b.as_script()));
2208    }
2209
2210    #[test]
2211    fn precomputed_is_lazy_for_no_signature_paths() {
2212        let spent_script = Builder::new().push_opcode(all::OP_PUSHNUM_1).into_script();
2213        let tx = Transaction {
2214            version: TransactionVersion::TWO,
2215            lock_time: LockTime::ZERO,
2216            inputs: vec![TxIn {
2217                previous_output: dummy_outpoint(),
2218                script_sig: ScriptSigBuf::new(),
2219                sequence: Sequence::MAX,
2220                witness: Witness::new(),
2221            }],
2222            outputs: vec![TxOut {
2223                amount: Amount::from_sat(50_000).expect("valid amount"),
2224                script_pubkey: ScriptPubKeyBuf::new(),
2225            }],
2226        };
2227        let tx_ctx = TransactionContext::new(&tx);
2228        let spend_context = SpendContext::new(spent_script.as_bytes(), None, 50_000, true);
2229        let flags = ScriptFlags::from_bits(0).expect("flags");
2230        let mut interpreter = Interpreter::new(&tx_ctx, 0, spend_context, flags).expect("new");
2231
2232        interpreter.verify().expect("op_true spend should validate");
2233        assert!(
2234            interpreter.precomputed.is_none(),
2235            "precomputed data should not be built when no signature opcodes execute"
2236        );
2237    }
2238
2239    #[test]
2240    fn scriptnum_overflow_maps_to_unknown() {
2241        let overflow = vec![0x00, 0x00, 0x00, 0x80, 0x00];
2242        let err = parse_scriptnum(&overflow, false, SCRIPTNUM_MAX_LEN).unwrap_err();
2243        assert_eq!(err, ScriptError::Unknown);
2244    }
2245
2246    #[test]
2247    fn scriptnum_minimal_violation_maps_to_unknown() {
2248        let non_minimal = vec![0x01, 0x00];
2249        let err = parse_scriptnum(&non_minimal, true, SCRIPTNUM_MAX_LEN).unwrap_err();
2250        assert_eq!(err, ScriptError::Unknown);
2251        let ok = parse_scriptnum(&non_minimal, false, SCRIPTNUM_MAX_LEN).unwrap();
2252        assert_eq!(ok, 1);
2253    }
2254
2255    #[test]
2256    fn script_code_materialization_depends_on_sigversion() {
2257        let script = Builder::new()
2258            .push_opcode(all::OP_PUSHNUM_1)
2259            .push_opcode(all::OP_CODESEPARATOR)
2260            .push_opcode(all::OP_PUSHNUM_2)
2261            .push_opcode(all::OP_CODESEPARATOR)
2262            .into_script();
2263
2264        let base = Interpreter::materialize_script_code(script.as_script(), 0, true)
2265            .expect("base script code materializes");
2266        assert_eq!(base.as_bytes(), &[all::OP_PUSHNUM_1.to_u8(), all::OP_PUSHNUM_2.to_u8()]);
2267
2268        let witness_v0 = Interpreter::materialize_script_code(script.as_script(), 0, false)
2269            .expect("witness v0 script code materializes");
2270        assert_eq!(witness_v0.as_bytes(), script.as_bytes());
2271    }
2272}