1use crate::script::error::ScriptError;
8use crate::script::locking_script::LockingScript;
9use crate::script::op::Op;
10use crate::script::unlocking_script::UnlockingScript;
11use crate::transaction::transaction_input::TransactionInput;
12use crate::transaction::transaction_output::TransactionOutput;
13
14const DEFAULT_MEMORY_LIMIT: usize = 32 * 1024 * 1024;
16
17const MAX_OPS: usize = 100_000;
19
20pub struct SpendParams {
22 pub locking_script: LockingScript,
23 pub unlocking_script: UnlockingScript,
24 pub source_txid: String,
25 pub source_output_index: usize,
26 pub source_satoshis: u64,
27 pub transaction_version: u32,
28 pub transaction_lock_time: u32,
29 pub transaction_sequence: u32,
30 pub other_inputs: Vec<TransactionInput>,
31 pub other_outputs: Vec<TransactionOutput>,
32 pub input_index: usize,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq)]
37pub(crate) enum ScriptContext {
38 Unlocking,
39 Locking,
40}
41
42pub struct Spend {
47 pub(crate) locking_script: LockingScript,
49 pub(crate) unlocking_script: UnlockingScript,
50
51 pub(crate) source_txid: String,
53 pub(crate) source_output_index: usize,
54 pub(crate) source_satoshis: u64,
55 pub(crate) transaction_version: u32,
56 pub(crate) transaction_lock_time: u32,
57 pub(crate) transaction_sequence: u32,
58 pub(crate) other_inputs: Vec<TransactionInput>,
59 pub(crate) other_outputs: Vec<TransactionOutput>,
60 pub(crate) input_index: usize,
61
62 pub(crate) stack: Vec<Vec<u8>>,
64 pub(crate) alt_stack: Vec<Vec<u8>>,
65 pub(crate) if_stack: Vec<bool>,
66 pub(crate) context: ScriptContext,
67 pub(crate) program_counter: usize,
68 pub(crate) last_code_separator: Option<usize>,
69
70 pub(crate) returning_from_conditional: bool,
76
77 pub(crate) memory_limit: usize,
79 pub(crate) stack_mem: usize,
80 pub(crate) alt_stack_mem: usize,
81
82 pub(crate) is_relaxed_override: bool,
84
85 pub(crate) ops_count: usize,
87}
88
89impl Spend {
90 pub fn new(params: SpendParams) -> Self {
92 Spend {
93 locking_script: params.locking_script,
94 unlocking_script: params.unlocking_script,
95 source_txid: params.source_txid,
96 source_output_index: params.source_output_index,
97 source_satoshis: params.source_satoshis,
98 transaction_version: params.transaction_version,
99 transaction_lock_time: params.transaction_lock_time,
100 transaction_sequence: params.transaction_sequence,
101 other_inputs: params.other_inputs,
102 other_outputs: params.other_outputs,
103 input_index: params.input_index,
104 stack: Vec::new(),
105 alt_stack: Vec::new(),
106 if_stack: Vec::new(),
107 context: ScriptContext::Unlocking,
108 program_counter: 0,
109 last_code_separator: None,
110 returning_from_conditional: false,
111 memory_limit: DEFAULT_MEMORY_LIMIT,
112 stack_mem: 0,
113 alt_stack_mem: 0,
114 is_relaxed_override: false,
115 ops_count: 0,
116 }
117 }
118
119 pub fn validate(&mut self) -> Result<bool, ScriptError> {
123 self.context = ScriptContext::Unlocking;
125 self.program_counter = 0;
126 loop {
127 let done = self.step()?;
128 if done {
129 break;
130 }
131 }
132
133 if !self.is_relaxed() && !self.unlocking_script.is_push_only() {
135 return Err(ScriptError::PushOnlyViolation);
136 }
137
138 self.context = ScriptContext::Locking;
140 self.program_counter = 0;
141 self.last_code_separator = None;
142 self.returning_from_conditional = false;
145 loop {
146 let done = self.step()?;
147 if done {
148 break;
149 }
150 }
151
152 if !self.if_stack.is_empty() {
154 return Err(ScriptError::InvalidScript(
155 "unbalanced IF/ENDIF".to_string(),
156 ));
157 }
158
159 if !self.is_relaxed() && self.stack.len() != 1 {
161 return Err(ScriptError::CleanStackViolation);
162 }
163
164 if self.stack.is_empty() {
166 return Ok(false);
167 }
168
169 let top = self.stack.last().unwrap();
171 Ok(Self::stack_to_bool(top))
172 }
173
174 pub fn step(&mut self) -> Result<bool, ScriptError> {
179 let chunks = match self.context {
180 ScriptContext::Unlocking => self.unlocking_script.chunks(),
181 ScriptContext::Locking => self.locking_script.chunks(),
182 };
183
184 if self.program_counter >= chunks.len() {
186 match self.context {
187 ScriptContext::Unlocking => {
188 return Ok(true);
190 }
191 ScriptContext::Locking => {
192 return Ok(true);
193 }
194 }
195 }
196
197 let chunk = chunks[self.program_counter].clone();
198 let op = chunk.op;
199
200 let in_exec = self.if_stack.iter().all(|&v| v) && !self.returning_from_conditional;
207
208 if !in_exec {
209 match op {
211 Op::OpIf | Op::OpNotIf | Op::OpVerIf | Op::OpVerNotIf => {
212 self.if_stack.push(false);
214 }
215 Op::OpElse => {
216 if let Some(last) = self.if_stack.last_mut() {
217 *last = !*last;
218 } else {
219 return Err(ScriptError::InvalidScript(
220 "OP_ELSE without OP_IF".to_string(),
221 ));
222 }
223 }
224 Op::OpEndIf => {
225 self.if_stack.pop().ok_or_else(|| {
226 ScriptError::InvalidScript("OP_ENDIF without OP_IF".to_string())
227 })?;
228 }
229 _ => {
230 }
232 }
233 self.program_counter += 1;
234 if self.returning_from_conditional && self.if_stack.is_empty() {
237 self.program_counter = chunks.len();
238 self.returning_from_conditional = false;
239 }
240 return Ok(false);
241 }
242
243 self.ops_count += 1;
245 if self.ops_count > MAX_OPS {
246 return Err(ScriptError::InvalidScript(
247 "exceeded maximum operation count".to_string(),
248 ));
249 }
250
251 self.execute_opcode(op, &chunk)?;
253 self.program_counter += 1;
254
255 Ok(false)
256 }
257
258 pub fn is_relaxed(&self) -> bool {
264 self.transaction_version > 1 || self.is_relaxed_override
265 }
266
267 pub fn set_relaxed_override(&mut self, v: bool) {
269 self.is_relaxed_override = v;
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276 use crate::script::locking_script::LockingScript;
277 use crate::script::unlocking_script::UnlockingScript;
278
279 fn make_spend(unlocking_asm: &str, locking_asm: &str) -> Spend {
281 Spend::new(SpendParams {
282 locking_script: LockingScript::from_asm(locking_asm),
283 unlocking_script: UnlockingScript::from_asm(unlocking_asm),
284 source_txid: "00".repeat(32),
285 source_output_index: 0,
286 source_satoshis: 0,
287 transaction_version: 1,
288 transaction_lock_time: 0,
289 transaction_sequence: 0xffffffff,
290 other_inputs: vec![],
291 other_outputs: vec![],
292 input_index: 0,
293 })
294 }
295
296 fn make_relaxed_spend(unlocking_asm: &str, locking_asm: &str) -> Spend {
298 Spend::new(SpendParams {
299 locking_script: LockingScript::from_asm(locking_asm),
300 unlocking_script: UnlockingScript::from_asm(unlocking_asm),
301 source_txid: "00".repeat(32),
302 source_output_index: 0,
303 source_satoshis: 0,
304 transaction_version: 2, transaction_lock_time: 0,
306 transaction_sequence: 0xffffffff,
307 other_inputs: vec![],
308 other_outputs: vec![],
309 input_index: 0,
310 })
311 }
312
313 #[test]
314 fn test_simple_push_only_script() {
315 let mut spend = make_spend("OP_1", "");
318 let result = spend.validate().unwrap();
319 assert!(result, "OP_1 should leave true on stack");
320 }
321
322 #[test]
323 fn test_op1_pushes_one() {
324 let mut spend = make_spend("OP_1", "");
325 spend.validate().unwrap();
326 assert_eq!(spend.stack, vec![vec![1u8]]);
327 }
328
329 #[test]
330 fn test_op_numbers() {
331 for n in 2..=16u8 {
333 let asm = format!("OP_{}", n);
334 let mut spend = make_spend(&asm, "");
335 spend.validate().unwrap();
336 assert_eq!(spend.stack, vec![vec![n]], "OP_{} should push [{}]", n, n);
337 }
338 }
339
340 #[test]
341 fn test_op_0_pushes_empty() {
342 let mut spend = make_relaxed_spend("0 OP_1", "");
344 spend.validate().unwrap();
345 assert_eq!(spend.stack.len(), 2);
346 assert_eq!(spend.stack[0], Vec::<u8>::new());
347 assert_eq!(spend.stack[1], vec![1u8]);
348 }
349
350 #[test]
351 fn test_op_1negate() {
352 let mut spend = make_spend("-1", "OP_1 OP_ADD");
353 let result = spend.validate().unwrap();
355 assert!(!result, "-1 + 1 = 0 should be false");
356 }
357
358 #[test]
359 fn test_if_else_endif_true_branch() {
360 let mut spend = make_spend("OP_1", "OP_IF OP_2 OP_ELSE OP_3 OP_ENDIF");
362 let result = spend.validate().unwrap();
363 assert!(result);
364 assert_eq!(spend.stack, vec![vec![2u8]]);
365 }
366
367 #[test]
368 fn test_if_else_endif_false_branch() {
369 let mut spend = make_spend("0", "OP_IF OP_2 OP_ELSE OP_3 OP_ENDIF");
370 let result = spend.validate().unwrap();
371 assert!(result);
372 assert_eq!(spend.stack, vec![vec![3u8]]);
373 }
374
375 #[test]
376 fn test_nested_if() {
377 let mut spend = make_spend("OP_1 OP_1", "OP_IF OP_IF OP_5 OP_ENDIF OP_ENDIF");
379 let result = spend.validate().unwrap();
380 assert!(result);
381 assert_eq!(spend.stack, vec![vec![5u8]]);
382 }
383
384 #[test]
385 fn test_op_verify_true() {
386 let mut spend = make_spend("OP_1", "OP_VERIFY OP_1");
387 let result = spend.validate().unwrap();
388 assert!(result);
389 }
390
391 #[test]
392 fn test_op_verify_false() {
393 let mut spend = make_spend("0", "OP_VERIFY OP_1");
394 let result = spend.validate();
395 assert!(result.is_err());
396 }
397
398 #[test]
399 fn test_op_return_terminates_successfully() {
400 let mut spend = make_spend("OP_1", "OP_RETURN");
407 let result = spend.validate();
408 assert!(matches!(result, Ok(true)));
409 }
410
411 #[test]
412 fn test_op_return_with_falsy_stack_returns_false() {
413 let mut spend = make_relaxed_spend("OP_0", "OP_RETURN");
418 let result = spend.validate();
419 assert!(matches!(result, Ok(false)));
420 }
421
422 #[test]
423 fn test_op_return_data_carrier_idiom() {
424 let mut spend = make_relaxed_spend("", "OP_FALSE OP_RETURN 6c6f6c");
429 let result = spend.validate();
430 assert!(matches!(result, Ok(false)));
431 }
432
433 #[test]
434 fn test_op_return_in_unexecuted_branch_does_not_terminate() {
435 let mut spend = make_spend("OP_0", "OP_IF OP_RETURN OP_ENDIF OP_1");
440 let result = spend.validate();
441 assert!(matches!(result, Ok(true)));
442 }
443
444 #[test]
445 fn test_op_return_in_executing_if_branch_defers_termination() {
446 let mut spend = make_spend("OP_1", "OP_1 OP_IF OP_RETURN OP_ENDIF");
454 let result = spend.validate();
455 assert!(matches!(result, Ok(true)));
456 }
457
458 #[test]
459 fn test_op_return_in_nested_if_defers_until_outermost_endif() {
460 let mut spend = make_spend("OP_1", "OP_1 OP_IF OP_1 OP_IF OP_RETURN OP_ENDIF OP_ENDIF");
465 let result = spend.validate();
466 assert!(matches!(result, Ok(true)));
467 }
468
469 #[test]
470 fn test_memory_limit_exceeded() {
471 let mut spend = make_spend("OP_1", "");
473 spend.memory_limit = 0;
474 let result = spend.validate();
475 assert!(matches!(result, Err(ScriptError::MemoryLimitExceeded)));
476 }
477
478 #[test]
479 fn test_stack_underflow() {
480 let mut spend = make_spend("", "OP_DUP");
483 let result = spend.validate();
484 assert!(result.is_err(), "expected error but got {:?}", result);
485 }
486
487 #[test]
488 fn test_stack_to_bool() {
489 assert!(!Spend::stack_to_bool(&[]));
490 assert!(!Spend::stack_to_bool(&[0]));
491 assert!(!Spend::stack_to_bool(&[0, 0]));
492 assert!(!Spend::stack_to_bool(&[0x80])); assert!(!Spend::stack_to_bool(&[0, 0x80])); assert!(Spend::stack_to_bool(&[1]));
495 assert!(Spend::stack_to_bool(&[0, 1]));
496 assert!(Spend::stack_to_bool(&[0x81])); }
498
499 #[test]
500 fn test_clean_stack_violation() {
501 let mut spend = make_spend("OP_1 OP_2", "");
503 let result = spend.validate();
504 assert!(matches!(result, Err(ScriptError::CleanStackViolation)));
505 }
506
507 #[test]
508 fn test_relaxed_mode_no_clean_stack() {
509 let mut spend = make_relaxed_spend("OP_1 OP_2", "");
511 let result = spend.validate().unwrap();
512 assert!(result); }
514
515 #[test]
516 fn test_push_only_violation() {
517 let mut spend = make_spend("", "OP_1");
519 spend.unlocking_script = UnlockingScript::from_asm("OP_DUP");
521 spend.stack.push(vec![1]);
523 let result = spend.validate();
524 assert!(matches!(result, Err(ScriptError::PushOnlyViolation)));
525 }
526
527 #[test]
528 fn test_step_api() {
529 let mut spend = make_spend("OP_1 OP_2", "OP_ADD");
530
531 assert!(!spend.step().unwrap()); assert_eq!(spend.stack, vec![vec![1u8]]);
534
535 assert!(!spend.step().unwrap()); assert_eq!(spend.stack, vec![vec![1u8], vec![2u8]]);
537
538 assert!(spend.step().unwrap()); spend.context = ScriptContext::Locking;
542 spend.program_counter = 0;
543
544 assert!(!spend.step().unwrap()); assert_eq!(spend.stack, vec![vec![3u8]]);
546
547 assert!(spend.step().unwrap()); }
549
550 #[test]
551 fn test_is_relaxed() {
552 let spend = make_spend("", "");
553 assert!(!spend.is_relaxed()); let spend2 = make_relaxed_spend("", "");
556 assert!(spend2.is_relaxed()); let mut spend3 = make_spend("", "");
559 spend3.set_relaxed_override(true);
560 assert!(spend3.is_relaxed()); }
562
563 #[test]
564 fn test_op_notif() {
565 let mut spend = make_spend("0", "OP_NOTIF OP_5 OP_ENDIF");
567 let result = spend.validate().unwrap();
568 assert!(result);
569 assert_eq!(spend.stack, vec![vec![5u8]]);
570 }
571
572 #[test]
577 fn test_op_add() {
578 let mut spend = make_spend("OP_3 OP_4", "OP_ADD OP_7 OP_EQUAL");
579 assert!(spend.validate().unwrap());
580 }
581
582 #[test]
583 fn test_op_sub() {
584 let mut spend = make_spend("OP_5 OP_3", "OP_SUB OP_2 OP_EQUAL");
585 assert!(spend.validate().unwrap());
586 }
587
588 #[test]
589 fn test_op_mul() {
590 let mut spend = make_spend("OP_3 OP_4", "OP_MUL OP_12 OP_EQUAL");
591 assert!(spend.validate().unwrap());
592 }
593
594 #[test]
595 fn test_op_div() {
596 let mut spend = make_spend("OP_6 OP_3", "OP_DIV OP_2 OP_EQUAL");
597 assert!(spend.validate().unwrap());
598 }
599
600 #[test]
601 fn test_op_mod() {
602 let mut spend = make_spend("OP_7 OP_3", "OP_MOD OP_1 OP_EQUAL");
603 assert!(spend.validate().unwrap());
604 }
605
606 #[test]
607 fn test_op_div_by_zero() {
608 let mut spend = make_spend("OP_5 0", "OP_DIV");
609 assert!(spend.validate().is_err());
610 }
611
612 #[test]
613 fn test_op_equal() {
614 let mut spend = make_spend("OP_3 OP_3", "OP_EQUAL");
615 assert!(spend.validate().unwrap());
616 }
617
618 #[test]
619 fn test_op_equal_false() {
620 let mut spend = make_spend("OP_3 OP_4", "OP_EQUAL");
621 assert!(!spend.validate().unwrap());
622 }
623
624 #[test]
625 fn test_op_equalverify() {
626 let mut spend = make_spend("OP_3 OP_3", "OP_EQUALVERIFY OP_1");
627 assert!(spend.validate().unwrap());
628 }
629
630 #[test]
631 fn test_op_equalverify_fail() {
632 let mut spend = make_spend("OP_3 OP_4", "OP_EQUALVERIFY OP_1");
633 assert!(spend.validate().is_err());
634 }
635
636 #[test]
637 fn test_op_dup_hash160_equalverify() {
638 use crate::primitives::hash::hash160;
641 let pubkey_data = vec![0x04; 33]; let hash = hash160(&pubkey_data);
643 let hash_hex: String = hash.iter().map(|b| format!("{:02x}", b)).collect();
644 let pubkey_hex: String = pubkey_data.iter().map(|b| format!("{:02x}", b)).collect();
645
646 let locking = format!("OP_DUP OP_HASH160 {} OP_EQUALVERIFY OP_DROP OP_1", hash_hex);
647 let mut spend = make_spend(&pubkey_hex, &locking);
648 assert!(spend.validate().unwrap());
649 }
650
651 #[test]
652 fn test_op_cat() {
653 let mut spend = make_relaxed_spend("01 02", "OP_CAT 0102 OP_EQUAL");
656 assert!(spend.validate().unwrap());
657 }
658
659 #[test]
660 fn test_op_split() {
661 let mut spend =
663 make_relaxed_spend("010203 OP_1", "OP_SPLIT 0203 OP_EQUALVERIFY 01 OP_EQUAL");
664 assert!(spend.validate().unwrap());
665 }
666
667 #[test]
668 fn test_op_size() {
669 let mut spend = make_relaxed_spend("010203", "OP_SIZE OP_3 OP_EQUALVERIFY OP_1");
670 assert!(spend.validate().unwrap());
671 }
672
673 #[test]
674 fn test_op_sha256() {
675 let mut spend = make_relaxed_spend("0", "OP_SHA256 OP_SIZE");
677 spend.validate().unwrap();
678 assert_eq!(spend.stack.len(), 2);
679 assert_eq!(spend.stack[0].len(), 32);
680 }
681
682 #[test]
683 fn test_op_hash160() {
684 let mut spend = make_relaxed_spend("01", "OP_HASH160 OP_SIZE");
686 spend.validate().unwrap();
687 assert_eq!(spend.stack[0].len(), 20);
688 }
689
690 #[test]
691 fn test_op_hash256() {
692 let mut spend = make_relaxed_spend("01", "OP_HASH256 OP_SIZE");
694 spend.validate().unwrap();
695 assert_eq!(spend.stack[0].len(), 32);
696 }
697
698 #[test]
699 fn test_op_toaltstack_fromaltstack() {
700 let mut spend = make_spend("OP_1", "OP_TOALTSTACK OP_FROMALTSTACK");
701 assert!(spend.validate().unwrap());
702 assert_eq!(spend.stack, vec![vec![1u8]]);
703 }
704
705 #[test]
706 fn test_op_depth() {
707 let mut spend = make_spend(
711 "OP_1 OP_2 OP_3",
712 "OP_DEPTH OP_3 OP_EQUALVERIFY OP_DROP OP_DROP OP_DROP OP_1",
713 );
714 let result = spend.validate();
715 assert!(result.is_ok(), "test_op_depth failed: {:?}", result);
716 }
717
718 #[test]
719 fn test_op_swap() {
720 let mut spend = make_relaxed_spend("OP_1 OP_2", "OP_SWAP");
721 spend.validate().unwrap();
722 assert_eq!(spend.stack, vec![vec![2u8], vec![1u8]]);
723 }
724
725 #[test]
726 fn test_op_rot() {
727 let mut spend = make_relaxed_spend("OP_1 OP_2 OP_3", "OP_ROT");
728 spend.validate().unwrap();
729 assert_eq!(spend.stack, vec![vec![2u8], vec![3u8], vec![1u8]]);
730 }
731
732 #[test]
733 fn test_op_over() {
734 let mut spend = make_relaxed_spend("OP_1 OP_2", "OP_OVER");
735 spend.validate().unwrap();
736 assert_eq!(spend.stack, vec![vec![1u8], vec![2u8], vec![1u8]]);
737 }
738
739 #[test]
740 fn test_op_nip() {
741 let mut spend = make_relaxed_spend("OP_1 OP_2", "OP_NIP");
742 spend.validate().unwrap();
743 assert_eq!(spend.stack, vec![vec![2u8]]);
744 }
745
746 #[test]
747 fn test_op_tuck() {
748 let mut spend = make_relaxed_spend("OP_1 OP_2", "OP_TUCK");
749 spend.validate().unwrap();
750 assert_eq!(spend.stack, vec![vec![2u8], vec![1u8], vec![2u8]]);
751 }
752
753 #[test]
754 fn test_op_pick() {
755 let mut spend = make_relaxed_spend("OP_1 OP_2 OP_3 OP_2", "OP_PICK");
756 spend.validate().unwrap();
757 assert_eq!(
758 spend.stack,
759 vec![vec![1u8], vec![2u8], vec![3u8], vec![1u8]]
760 );
761 }
762
763 #[test]
764 fn test_op_roll() {
765 let mut spend = make_relaxed_spend("OP_1 OP_2 OP_3 OP_2", "OP_ROLL");
766 spend.validate().unwrap();
767 assert_eq!(spend.stack, vec![vec![2u8], vec![3u8], vec![1u8]]);
768 }
769
770 #[test]
771 fn test_op_2dup() {
772 let mut spend = make_relaxed_spend("OP_1 OP_2", "OP_2DUP");
773 spend.validate().unwrap();
774 assert_eq!(
775 spend.stack,
776 vec![vec![1u8], vec![2u8], vec![1u8], vec![2u8]]
777 );
778 }
779
780 #[test]
781 fn test_op_3dup() {
782 let mut spend = make_relaxed_spend("OP_1 OP_2 OP_3", "OP_3DUP");
783 spend.validate().unwrap();
784 assert_eq!(spend.stack.len(), 6);
785 }
786
787 #[test]
788 fn test_op_2drop() {
789 let mut spend = make_spend("OP_1 OP_2 OP_3", "OP_2DROP");
790 assert!(spend.validate().unwrap());
791 assert_eq!(spend.stack, vec![vec![1u8]]);
792 }
793
794 #[test]
795 fn test_op_2swap() {
796 let mut spend = make_relaxed_spend("OP_1 OP_2 OP_3 OP_4", "OP_2SWAP");
797 spend.validate().unwrap();
798 assert_eq!(
799 spend.stack,
800 vec![vec![3u8], vec![4u8], vec![1u8], vec![2u8]]
801 );
802 }
803
804 #[test]
805 fn test_op_ifdup_true() {
806 let mut spend = make_relaxed_spend("OP_1", "OP_IFDUP");
807 spend.validate().unwrap();
808 assert_eq!(spend.stack, vec![vec![1u8], vec![1u8]]);
809 }
810
811 #[test]
812 fn test_op_ifdup_false() {
813 let mut spend = make_relaxed_spend("0", "OP_IFDUP");
814 spend.validate().unwrap();
815 assert_eq!(spend.stack, vec![Vec::<u8>::new()]);
816 }
817
818 #[test]
819 fn test_op_lessthan() {
820 let mut spend = make_spend("OP_1 OP_2", "OP_LESSTHAN");
821 assert!(spend.validate().unwrap());
822 }
823
824 #[test]
825 fn test_op_greaterthan() {
826 let mut spend = make_spend("OP_3 OP_2", "OP_GREATERTHAN");
827 assert!(spend.validate().unwrap());
828 }
829
830 #[test]
831 fn test_op_within() {
832 let mut spend = make_spend("OP_3 OP_2 OP_5", "OP_WITHIN");
834 assert!(spend.validate().unwrap());
835 }
836
837 #[test]
838 fn test_op_within_false() {
839 let mut spend = make_spend("OP_5 OP_2 OP_5", "OP_WITHIN");
841 assert!(!spend.validate().unwrap());
842 }
843
844 #[test]
845 fn test_op_min() {
846 let mut spend = make_spend("OP_3 OP_5", "OP_MIN OP_3 OP_EQUAL");
847 assert!(spend.validate().unwrap());
848 }
849
850 #[test]
851 fn test_op_max() {
852 let mut spend = make_spend("OP_3 OP_5", "OP_MAX OP_5 OP_EQUAL");
853 assert!(spend.validate().unwrap());
854 }
855
856 #[test]
857 fn test_op_booland() {
858 let mut spend = make_spend("OP_1 OP_1", "OP_BOOLAND");
859 assert!(spend.validate().unwrap());
860
861 let mut spend2 = make_spend("OP_1 0", "OP_BOOLAND");
862 assert!(!spend2.validate().unwrap());
863 }
864
865 #[test]
866 fn test_op_boolor() {
867 let mut spend = make_spend("0 0", "OP_BOOLOR");
868 assert!(!spend.validate().unwrap());
869
870 let mut spend2 = make_spend("OP_1 0", "OP_BOOLOR");
871 assert!(spend2.validate().unwrap());
872 }
873
874 #[test]
875 fn test_op_abs() {
876 let mut spend = make_spend("-1", "OP_ABS OP_1 OP_EQUAL");
878 assert!(spend.validate().unwrap());
879 }
880
881 #[test]
882 fn test_op_not() {
883 let mut spend = make_spend("0", "OP_NOT"); assert!(spend.validate().unwrap());
885
886 let mut spend2 = make_spend("OP_1", "OP_NOT"); assert!(!spend2.validate().unwrap());
888 }
889
890 #[test]
891 fn test_op_0notequal() {
892 let mut spend = make_spend("OP_5", "OP_0NOTEQUAL");
893 assert!(spend.validate().unwrap());
894
895 let mut spend2 = make_spend("0", "OP_0NOTEQUAL");
896 assert!(!spend2.validate().unwrap());
897 }
898
899 #[test]
900 fn test_op_negate() {
901 let mut spend = make_spend("OP_5", "OP_NEGATE OP_ABS OP_5 OP_EQUAL");
902 assert!(spend.validate().unwrap());
903 }
904
905 #[test]
906 fn test_op_1add_1sub() {
907 let mut spend = make_spend("OP_5", "OP_1ADD OP_6 OP_EQUAL");
908 assert!(spend.validate().unwrap());
909
910 let mut spend2 = make_spend("OP_5", "OP_1SUB OP_4 OP_EQUAL");
911 assert!(spend2.validate().unwrap());
912 }
913
914 #[test]
915 fn test_op_numequal() {
916 let mut spend = make_spend("OP_3 OP_3", "OP_NUMEQUAL");
917 assert!(spend.validate().unwrap());
918 }
919
920 #[test]
921 fn test_op_numequalverify() {
922 let mut spend = make_spend("OP_3 OP_3", "OP_NUMEQUALVERIFY OP_1");
923 assert!(spend.validate().unwrap());
924 }
925
926 #[test]
927 fn test_op_numnotequal() {
928 let mut spend = make_spend("OP_3 OP_4", "OP_NUMNOTEQUAL");
929 assert!(spend.validate().unwrap());
930 }
931
932 #[test]
933 fn test_op_invert() {
934 let mut spend = make_relaxed_spend("00", "OP_INVERT");
936 spend.validate().unwrap();
937 assert_eq!(spend.stack, vec![vec![0xff]]);
938 }
939
940 #[test]
941 fn test_op_and() {
942 let mut spend = make_relaxed_spend("ff 0f", "OP_AND");
943 spend.validate().unwrap();
944 assert_eq!(spend.stack, vec![vec![0x0f]]);
945 }
946
947 #[test]
948 fn test_op_or() {
949 let mut spend = make_relaxed_spend("f0 0f", "OP_OR");
950 spend.validate().unwrap();
951 assert_eq!(spend.stack, vec![vec![0xff]]);
952 }
953
954 #[test]
955 fn test_op_xor() {
956 let mut spend = make_relaxed_spend("ff ff", "OP_XOR");
957 spend.validate().unwrap();
958 assert_eq!(spend.stack, vec![vec![0x00]]);
959 }
960
961 #[test]
962 fn test_nested_if_deep() {
963 let mut spend = make_spend(
965 "OP_1 OP_1 OP_1",
966 "OP_IF OP_IF OP_IF OP_7 OP_ENDIF OP_ENDIF OP_ENDIF",
967 );
968 assert!(spend.validate().unwrap());
969 assert_eq!(spend.stack, vec![vec![7u8]]);
970 }
971
972 #[test]
973 fn test_op_codeseparator() {
974 let mut spend = make_spend("OP_1", "OP_CODESEPARATOR");
976 assert!(spend.validate().unwrap());
977 }
978
979 #[test]
980 fn test_chronicle_op_substr() {
981 let mut spend = make_relaxed_spend("0102030405 OP_1 OP_2", "OP_SUBSTR 0203 OP_EQUAL");
983 assert!(spend.validate().unwrap());
984 }
985
986 #[test]
987 fn test_chronicle_op_left() {
988 let mut spend = make_relaxed_spend("01020304 OP_2", "OP_LEFT 0102 OP_EQUAL");
989 assert!(spend.validate().unwrap());
990 }
991
992 #[test]
993 fn test_chronicle_op_right() {
994 let mut spend = make_relaxed_spend("01020304 OP_2", "OP_RIGHT 0304 OP_EQUAL");
995 assert!(spend.validate().unwrap());
996 }
997
998 #[test]
999 fn test_op_ripemd160() {
1000 let mut spend = make_relaxed_spend("01", "OP_RIPEMD160 OP_SIZE");
1001 spend.validate().unwrap();
1002 assert_eq!(spend.stack[0].len(), 20);
1003 }
1004
1005 #[test]
1006 fn test_op_sha1() {
1007 let mut spend = make_relaxed_spend("01", "OP_SHA1 OP_SIZE");
1008 spend.validate().unwrap();
1009 assert_eq!(spend.stack[0].len(), 20);
1010 }
1011
1012 #[test]
1013 fn test_op_checksig_empty_sig_fails() {
1014 let mut spend = make_relaxed_spend("0 01", "OP_CHECKSIG");
1016 spend.validate().unwrap();
1017 assert_eq!(spend.stack, vec![Vec::<u8>::new()]);
1019 }
1020
1021 #[test]
1022 fn test_relaxed_mode_gating() {
1023 let mut spend = make_relaxed_spend("OP_1 OP_2 OP_3", "");
1025 let result = spend.validate().unwrap();
1026 assert!(result); let mut spend2 = make_spend("OP_1 OP_2 OP_3", "");
1030 assert!(matches!(
1031 spend2.validate(),
1032 Err(ScriptError::CleanStackViolation)
1033 ));
1034 }
1035
1036 #[test]
1037 fn test_op_disabled_2mul() {
1038 let mut spend = make_spend("OP_1", "OP_2MUL");
1039 let result = spend.validate();
1040 assert!(matches!(result, Err(ScriptError::DisabledOpcode(_))));
1041 }
1042
1043 #[test]
1044 fn test_op_disabled_2div() {
1045 let mut spend = make_spend("OP_1", "OP_2DIV");
1046 let result = spend.validate();
1047 assert!(matches!(result, Err(ScriptError::DisabledOpcode(_))));
1048 }
1049
1050 fn parse_test_asm(asm: &str) -> crate::script::script::Script {
1059 use crate::script::script::Script;
1060 use crate::script::script_chunk::ScriptChunk;
1061
1062 let asm = asm.trim();
1063 if asm.is_empty() {
1064 return Script::new();
1065 }
1066
1067 let mut chunks = Vec::new();
1068 let tokens: Vec<&str> = asm.split_whitespace().collect();
1069 let mut i = 0;
1070
1071 while i < tokens.len() {
1072 let token = tokens[i];
1073
1074 if token == "0" {
1076 chunks.push(ScriptChunk::new_opcode(Op::Op0));
1077 i += 1;
1078 continue;
1079 }
1080 if token == "-1" {
1081 chunks.push(ScriptChunk::new_opcode(Op::Op1Negate));
1082 i += 1;
1083 continue;
1084 }
1085
1086 if token.starts_with('\'') {
1088 let text = if token.ends_with('\'') && token.len() > 1 {
1089 &token[1..token.len() - 1]
1090 } else {
1091 let mut s = token[1..].to_string();
1093 loop {
1094 i += 1;
1095 if i >= tokens.len() {
1096 break;
1097 }
1098 s.push(' ');
1099 s.push_str(tokens[i]);
1100 if tokens[i].ends_with('\'') {
1101 s.truncate(s.len() - 1);
1102 break;
1103 }
1104 }
1105 i += 1;
1106 let data = s.into_bytes();
1107 let len = data.len();
1108 let op_byte = if len < 0x4c { len as u8 } else { 0x4c };
1109 chunks.push(ScriptChunk::new_raw(op_byte, Some(data)));
1110 continue;
1111 };
1112 let data = text.as_bytes().to_vec();
1113 let len = data.len();
1114 let op_byte = if len < 0x4c { len as u8 } else { 0x4c };
1115 chunks.push(ScriptChunk::new_raw(op_byte, Some(data)));
1116 i += 1;
1117 continue;
1118 }
1119
1120 if token.starts_with("0x") || token.starts_with("0X") {
1122 let hex = &token[2..];
1123 if let Ok(push_len) = usize::from_str_radix(hex, 16) {
1124 if push_len > 0 && push_len <= 0x4e && i + 1 < tokens.len() {
1126 let next = tokens[i + 1];
1127 if next.starts_with("0x") || next.starts_with("0X") {
1128 let data_hex = &next[2..];
1129 if let Ok(data) = hex_decode(data_hex) {
1130 chunks.push(ScriptChunk::new_raw(push_len as u8, Some(data)));
1131 i += 2;
1132 continue;
1133 }
1134 }
1135 }
1136 if push_len <= 0xff {
1138 let op = Op::from(push_len as u8);
1139 chunks.push(ScriptChunk::new_raw(push_len as u8, None));
1140 let _ = op; i += 1;
1142 continue;
1143 }
1144 }
1145 i += 1;
1146 continue;
1147 }
1148
1149 if token == "PUSHDATA1" || token == "OP_PUSHDATA1" {
1151 if i + 2 < tokens.len() {
1152 let _len_hex = tokens[i + 1].strip_prefix("0x").unwrap_or(tokens[i + 1]);
1153 let data_hex = tokens[i + 2].strip_prefix("0x").unwrap_or(tokens[i + 2]);
1154 if let Ok(data) = hex_decode(data_hex) {
1155 chunks.push(ScriptChunk::new_raw(0x4c, Some(data)));
1156 i += 3;
1157 continue;
1158 }
1159 }
1160 i += 1;
1161 continue;
1162 }
1163 if token == "PUSHDATA2" || token == "OP_PUSHDATA2" {
1164 if i + 2 < tokens.len() {
1165 let data_hex = tokens[i + 2].strip_prefix("0x").unwrap_or(tokens[i + 2]);
1166 if let Ok(data) = hex_decode(data_hex) {
1167 chunks.push(ScriptChunk::new_raw(0x4d, Some(data)));
1168 i += 3;
1169 continue;
1170 }
1171 }
1172 i += 1;
1173 continue;
1174 }
1175 if token == "PUSHDATA4" || token == "OP_PUSHDATA4" {
1176 if i + 2 < tokens.len() {
1177 let data_hex = tokens[i + 2].strip_prefix("0x").unwrap_or(tokens[i + 2]);
1178 if let Ok(data) = hex_decode(data_hex) {
1179 chunks.push(ScriptChunk::new_raw(0x4e, Some(data)));
1180 i += 3;
1181 continue;
1182 }
1183 }
1184 i += 1;
1185 continue;
1186 }
1187
1188 if let Some(op) =
1190 Op::from_name(token).or_else(|| Op::from_name(&format!("OP_{}", token)))
1191 {
1192 chunks.push(ScriptChunk::new_opcode(op));
1193 i += 1;
1194 continue;
1195 }
1196
1197 if let Ok(n) = token.parse::<i64>() {
1199 use crate::primitives::big_number::BigNumber;
1200 let bn = BigNumber::from_number(n);
1201 let data = bn.to_script_num();
1202 if data.is_empty() {
1203 chunks.push(ScriptChunk::new_opcode(Op::Op0));
1204 } else {
1205 let len = data.len();
1206 let op_byte = if len < 0x4c { len as u8 } else { 0x4c };
1207 chunks.push(ScriptChunk::new_raw(op_byte, Some(data)));
1208 }
1209 i += 1;
1210 continue;
1211 }
1212
1213 i += 1;
1215 }
1216
1217 Script::from_chunks(chunks)
1218 }
1219
1220 fn hex_decode(hex: &str) -> Result<Vec<u8>, ()> {
1221 if hex.len() % 2 != 0 {
1222 return Err(());
1223 }
1224 let mut bytes = Vec::with_capacity(hex.len() / 2);
1225 for i in (0..hex.len()).step_by(2) {
1226 match u8::from_str_radix(&hex[i..i + 2], 16) {
1227 Ok(b) => bytes.push(b),
1228 Err(_) => return Err(()),
1229 }
1230 }
1231 Ok(bytes)
1232 }
1233
1234 #[test]
1235 fn test_script_tests_json() {
1236 let json_str = include_str!("../../test-vectors/script_tests.json");
1237 let entries: Vec<serde_json::Value> =
1238 serde_json::from_str(json_str).expect("failed to parse script_tests.json");
1239
1240 let mut passed = 0;
1241 let mut failed = 0;
1242 let mut skipped = 0;
1243
1244 for entry in &entries {
1245 let arr = match entry.as_array() {
1246 Some(a) => a,
1247 None => continue,
1248 };
1249
1250 if arr.len() < 4 {
1252 skipped += 1;
1253 continue;
1254 }
1255
1256 let (sig_asm, pubkey_asm, flags_str, expected) = if arr[0].is_array() {
1258 if arr.len() < 5 {
1260 skipped += 1;
1261 continue;
1262 }
1263 (
1264 arr[1].as_str().unwrap_or(""),
1265 arr[2].as_str().unwrap_or(""),
1266 arr[3].as_str().unwrap_or(""),
1267 arr[4].as_str().unwrap_or(""),
1268 )
1269 } else {
1270 (
1271 arr[0].as_str().unwrap_or(""),
1272 arr[1].as_str().unwrap_or(""),
1273 arr[2].as_str().unwrap_or(""),
1274 arr[3].as_str().unwrap_or(""),
1275 )
1276 };
1277
1278 let flags: Vec<&str> = if flags_str.is_empty() {
1280 vec![]
1281 } else {
1282 flags_str.split(',').collect()
1283 };
1284
1285 let has_strictenc = flags.contains(&"STRICTENC");
1286 let has_utxo_after_genesis = flags.contains(&"UTXO_AFTER_GENESIS");
1287 let has_p2sh = flags.contains(&"P2SH");
1288 let _has_sigpushonly = flags.contains(&"SIGPUSHONLY");
1289 let _has_minimaldata = flags.contains(&"MINIMALDATA");
1290
1291 if has_utxo_after_genesis || has_p2sh {
1294 skipped += 1;
1295 continue;
1296 }
1297
1298 let unlocking_script = UnlockingScript::from_script(parse_test_asm(sig_asm));
1300 let locking_script = LockingScript::from_script(parse_test_asm(pubkey_asm));
1301
1302 let version = if has_strictenc { 1u32 } else { 2u32 };
1305
1306 let mut spend = Spend::new(SpendParams {
1307 locking_script,
1308 unlocking_script,
1309 source_txid: "00".repeat(32),
1310 source_output_index: 0,
1311 source_satoshis: 0,
1312 transaction_version: version,
1313 transaction_lock_time: 0,
1314 transaction_sequence: 0xffffffff,
1315 other_inputs: vec![],
1316 other_outputs: vec![],
1317 input_index: 0,
1318 });
1319
1320 let result = spend.validate();
1321
1322 let expected_ok = expected == "OK";
1323
1324 match (expected_ok, &result) {
1325 (true, Ok(true)) => passed += 1,
1326 (true, Ok(false)) => {
1327 failed += 1;
1329 }
1330 (true, Err(_)) => {
1331 failed += 1;
1332 }
1333 (false, Err(_)) => passed += 1,
1334 (false, Ok(false)) => passed += 1, (false, Ok(true)) => {
1336 failed += 1;
1337 }
1338 }
1339 }
1340
1341 println!(
1342 "script_tests.json: {} passed, {} failed, {} skipped",
1343 passed, failed, skipped
1344 );
1345
1346 let total_run = passed + failed;
1348 let pass_rate = if total_run > 0 {
1349 (passed as f64 / total_run as f64) * 100.0
1350 } else {
1351 0.0
1352 };
1353 println!("Pass rate: {:.1}% ({}/{})", pass_rate, passed, total_run);
1354
1355 assert!(
1357 pass_rate >= 50.0,
1358 "script_tests.json pass rate too low: {:.1}% ({}/{})",
1359 pass_rate,
1360 passed,
1361 total_run
1362 );
1363 }
1364
1365 #[test]
1375 fn sighash_preimage_orders_by_input_index() {
1376 let prev_locking_hex = "76a914ffb76f52c809b14255e822c83653e4b16df7c91a88ac";
1377 let locking = LockingScript::from_hex(prev_locking_hex).unwrap();
1378
1379 let txid_be = "5b91184e6a2ff5d124c4d2fcd10b685497151f55cb70a2cd17b0e912dbbb129e";
1383 let other_input_0_sequence: u32 = 0xfffffffe;
1387 let current_sequence: u32 = 0xfffffffd;
1388 let other_input_0 = TransactionInput {
1389 source_txid: Some(txid_be.to_string()),
1390 source_output_index: 0,
1391 unlocking_script: None,
1392 sequence: other_input_0_sequence,
1393 source_transaction: None,
1394 };
1395
1396 let mut spend = Spend::new(SpendParams {
1397 locking_script: locking.clone(),
1398 unlocking_script: crate::script::unlocking_script::UnlockingScript::from_asm(""),
1399 source_txid: txid_be.to_string(),
1400 source_output_index: 1,
1401 source_satoshis: 1438,
1402 transaction_version: 1,
1403 transaction_lock_time: 0,
1404 transaction_sequence: current_sequence,
1405 other_inputs: vec![other_input_0],
1406 other_outputs: vec![
1407 crate::transaction::transaction_output::TransactionOutput {
1408 satoshis: Some(100),
1409 locking_script: LockingScript::from_hex(
1410 "76a914ffb76f52c809b14255e822c83653e4b16df7c91a88ac",
1411 )
1412 .unwrap(),
1413 change: false,
1414 },
1415 crate::transaction::transaction_output::TransactionOutput {
1416 satoshis: Some(780),
1417 locking_script: LockingScript::from_hex(
1418 "76a914ffb76f52c809b14255e822c83653e4b16df7c91a88ac",
1419 )
1420 .unwrap(),
1421 change: false,
1422 },
1423 ],
1424 input_index: 1,
1425 });
1426
1427 let preimage = spend.sighash_preimage(&locking.0, 0x41);
1428
1429 use crate::primitives::hash::hash256;
1433 let mut expected_prevouts = Vec::new();
1434 let txid_le = {
1435 let mut b = hex::decode(txid_be).unwrap();
1436 b.reverse();
1437 b
1438 };
1439 expected_prevouts.extend_from_slice(&txid_le);
1440 expected_prevouts.extend_from_slice(&0u32.to_le_bytes());
1441 expected_prevouts.extend_from_slice(&txid_le);
1442 expected_prevouts.extend_from_slice(&1u32.to_le_bytes());
1443 let expected_hash_prevouts = hash256(&expected_prevouts);
1444
1445 assert_eq!(
1446 &preimage[4..36],
1447 &expected_hash_prevouts[..],
1448 "hashPrevouts must serialize inputs in original tx order, regardless of input_index"
1449 );
1450
1451 let mut expected_sequences = Vec::new();
1454 expected_sequences.extend_from_slice(&other_input_0_sequence.to_le_bytes());
1455 expected_sequences.extend_from_slice(¤t_sequence.to_le_bytes());
1456 let expected_hash_sequence = hash256(&expected_sequences);
1457 assert_eq!(
1458 &preimage[36..68],
1459 &expected_hash_sequence[..],
1460 "hashSequence must serialize inputs in original tx order, regardless of input_index"
1461 );
1462 }
1463}