1use 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#[derive(Debug, Clone, Copy)]
70pub struct ScriptFlags(u32);
71
72impl ScriptFlags {
73 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 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#[derive(Debug, Default, Clone)]
130pub struct ScriptStack {
131 items: Vec<Vec<u8>>,
132}
133
134impl ScriptStack {
135 pub fn new() -> Self {
137 Self { items: Vec::new() }
138 }
139
140 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 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 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 pub fn pop_bytes(&mut self) -> Result<Vec<u8>, Error> {
173 self.items.pop().ok_or(script_unknown())
174 }
175
176 pub fn last(&self) -> Option<&Vec<u8>> {
178 self.items.last()
179 }
180
181 pub fn len(&self) -> usize {
183 self.items.len()
184 }
185
186 pub fn is_empty(&self) -> bool {
188 self.items.is_empty()
189 }
190}
191
192pub struct SpendContext<'script> {
194 pub script_pubkey: &'script [u8],
196 pub spent_outputs: Option<SpentOutputs>,
198 pub amount: u64,
200 pub has_amount: bool,
202}
203
204impl<'script> SpendContext<'script> {
205 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
216pub 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 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 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 #[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 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 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}