1use std::fmt;
7
8use crate::chunk::{decode_script, push_data_prefix, ScriptChunk};
9use crate::opcodes::*;
10use crate::ScriptError;
11
12#[derive(Clone, PartialEq, Eq)]
14pub struct Script(Vec<u8>);
15
16impl Script {
17 pub fn new() -> Self {
26 Script(Vec::new())
27 }
28
29 pub fn from_hex(hex_str: &str) -> Result<Self, ScriptError> {
37 let bytes = hex::decode(hex_str)?;
38 Ok(Script(bytes))
39 }
40
41 pub fn from_bytes(bytes: &[u8]) -> Self {
49 Script(bytes.to_vec())
50 }
51
52 pub fn from_asm(asm: &str) -> Result<Self, ScriptError> {
63 let mut script = Script::new();
64 if asm.is_empty() {
65 return Ok(script);
66 }
67 for section in asm.split(' ') {
68 if let Some(opcode) = string_to_opcode(section) {
69 script.append_opcodes(&[opcode])?;
70 } else {
71 script.append_push_data_hex(section)?;
72 }
73 }
74 Ok(script)
75 }
76
77 pub fn to_hex(&self) -> String {
86 hex::encode(&self.0)
87 }
88
89 pub fn to_asm(&self) -> String {
97 if self.0.is_empty() {
98 return String::new();
99 }
100 let mut parts = Vec::new();
101 let mut pos = 0;
102 while pos < self.0.len() {
103 match self.read_op(&mut pos) {
104 Ok(chunk) => {
105 let s = chunk.to_asm_string();
106 if !s.is_empty() {
107 parts.push(s);
108 }
109 }
110 Err(_) => return String::new(),
111 }
112 }
113 parts.join(" ")
114 }
115
116 pub fn to_bytes(&self) -> &[u8] {
121 &self.0
122 }
123
124 pub fn len(&self) -> usize {
129 self.0.len()
130 }
131
132 pub fn is_empty(&self) -> bool {
137 self.0.is_empty()
138 }
139
140 pub fn is_p2pkh(&self) -> bool {
151 let b = &self.0;
152 b.len() == 25
153 && b[0] == OP_DUP
154 && b[1] == OP_HASH160
155 && b[2] == OP_DATA_20
156 && b[23] == OP_EQUALVERIFY
157 && b[24] == OP_CHECKSIG
158 }
159
160 pub fn is_p2pk(&self) -> bool {
167 let parts = match self.chunks() {
168 Ok(p) => p,
169 Err(_) => return false,
170 };
171 if parts.len() == 2 && parts[1].op == OP_CHECKSIG {
172 if let Some(ref pubkey) = parts[0].data {
173 if !pubkey.is_empty() {
174 let version = pubkey[0];
175 if (version == 0x04 || version == 0x06 || version == 0x07) && pubkey.len() == 65
176 {
177 return true;
178 } else if (version == 0x03 || version == 0x02) && pubkey.len() == 33 {
179 return true;
180 }
181 }
182 }
183 }
184 false
185 }
186
187 pub fn is_p2sh(&self) -> bool {
194 let b = &self.0;
195 b.len() == 23 && b[0] == OP_HASH160 && b[1] == OP_DATA_20 && b[22] == OP_EQUAL
196 }
197
198 pub fn is_data(&self) -> bool {
203 let b = &self.0;
204 (!b.is_empty() && b[0] == OP_RETURN)
205 || (b.len() > 1 && b[0] == OP_FALSE && b[1] == OP_RETURN)
206 }
207
208 pub fn is_multisig_out(&self) -> bool {
215 let parts = match self.chunks() {
216 Ok(p) => p,
217 Err(_) => return false,
218 };
219 if parts.len() < 3 {
220 return false;
221 }
222 if !is_small_int_op(parts[0].op) {
223 return false;
224 }
225 for chunk in &parts[1..parts.len() - 2] {
226 match &chunk.data {
227 Some(d) if !d.is_empty() => {}
228 _ => return false,
229 }
230 }
231 let second_last = &parts[parts.len() - 2];
232 let last = &parts[parts.len() - 1];
233 is_small_int_op(second_last.op) && last.op == OP_CHECKMULTISIG
234 }
235
236 pub fn public_key_hash(&self) -> Result<Vec<u8>, ScriptError> {
247 if self.0.is_empty() {
248 return Err(ScriptError::EmptyScript);
249 }
250 if self.0.len() <= 2 || self.0[0] != OP_DUP || self.0[1] != OP_HASH160 {
251 return Err(ScriptError::NotP2PKH);
252 }
253 let tail = &self.0[2..];
254 let parts = decode_script(tail)?;
255 match parts.first() {
256 Some(chunk) => match &chunk.data {
257 Some(data) => Ok(data.clone()),
258 None => Err(ScriptError::NotP2PKH),
259 },
260 None => Err(ScriptError::NotP2PKH),
261 }
262 }
263
264 pub fn chunks(&self) -> Result<Vec<ScriptChunk>, ScriptError> {
269 decode_script(&self.0)
270 }
271
272 pub fn append_push_data(&mut self, data: &[u8]) -> Result<(), ScriptError> {
287 let prefix = push_data_prefix(data.len())?;
288 self.0.extend_from_slice(&prefix);
289 self.0.extend_from_slice(data);
290 Ok(())
291 }
292
293 pub fn append_push_data_hex(&mut self, hex_str: &str) -> Result<(), ScriptError> {
301 let data = hex::decode(hex_str).map_err(|_| ScriptError::InvalidOpcodeData)?;
302 self.append_push_data(&data)
303 }
304
305 pub fn append_opcodes(&mut self, opcodes: &[u8]) -> Result<(), ScriptError> {
316 for &op in opcodes {
317 if op >= OP_DATA_1 && op <= OP_PUSHDATA4 {
318 return Err(ScriptError::InvalidOpcodeType(
319 opcode_to_string(op).to_string(),
320 ));
321 }
322 }
323 self.0.extend_from_slice(opcodes);
324 Ok(())
325 }
326
327 pub fn equals(&self, other: &Script) -> bool {
335 self.0 == other.0
336 }
337
338 fn read_op(&self, pos: &mut usize) -> Result<ScriptChunk, ScriptError> {
352 let b = &self.0;
353 if *pos >= b.len() {
354 return Err(ScriptError::IndexOutOfRange);
355 }
356 let op = b[*pos];
357 match op {
358 OP_PUSHDATA1 => {
359 if b.len() < *pos + 2 {
360 return Err(ScriptError::DataTooSmall);
361 }
362 let length = b[*pos + 1] as usize;
363 *pos += 2;
364 if b.len() < *pos + length {
365 return Err(ScriptError::DataTooSmall);
366 }
367 let data = b[*pos..*pos + length].to_vec();
368 *pos += length;
369 Ok(ScriptChunk {
370 op: OP_PUSHDATA1,
371 data: Some(data),
372 })
373 }
374 OP_PUSHDATA2 => {
375 if b.len() < *pos + 3 {
376 return Err(ScriptError::DataTooSmall);
377 }
378 let length = u16::from_le_bytes([b[*pos + 1], b[*pos + 2]]) as usize;
379 *pos += 3;
380 if b.len() < *pos + length {
381 return Err(ScriptError::DataTooSmall);
382 }
383 let data = b[*pos..*pos + length].to_vec();
384 *pos += length;
385 Ok(ScriptChunk {
386 op: OP_PUSHDATA2,
387 data: Some(data),
388 })
389 }
390 OP_PUSHDATA4 => {
391 if b.len() < *pos + 5 {
392 return Err(ScriptError::DataTooSmall);
393 }
394 let length =
395 u32::from_le_bytes([b[*pos + 1], b[*pos + 2], b[*pos + 3], b[*pos + 4]])
396 as usize;
397 *pos += 5;
398 if b.len() < *pos + length {
399 return Err(ScriptError::DataTooSmall);
400 }
401 let data = b[*pos..*pos + length].to_vec();
402 *pos += length;
403 Ok(ScriptChunk {
404 op: OP_PUSHDATA4,
405 data: Some(data),
406 })
407 }
408 _ if op >= OP_DATA_1 && op < OP_PUSHDATA1 => {
409 let length = op as usize;
410 if b.len() < *pos + 1 + length {
411 return Err(ScriptError::DataTooSmall);
412 }
413 let data = b[*pos + 1..*pos + 1 + length].to_vec();
414 *pos += 1 + length;
415 Ok(ScriptChunk {
416 op,
417 data: Some(data),
418 })
419 }
420 _ => {
421 *pos += 1;
422 Ok(ScriptChunk { op, data: None })
423 }
424 }
425 }
426}
427
428impl Default for Script {
429 fn default() -> Self {
430 Self::new()
431 }
432}
433
434impl fmt::Display for Script {
435 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437 write!(f, "{}", self.to_hex())
438 }
439}
440
441impl fmt::Debug for Script {
442 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443 write!(f, "Script({})", self.to_hex())
444 }
445}
446
447impl serde::Serialize for Script {
448 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
449 where
450 S: serde::Serializer,
451 {
452 serializer.serialize_str(&self.to_hex())
453 }
454}
455
456impl<'de> serde::Deserialize<'de> for Script {
457 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
458 where
459 D: serde::Deserializer<'de>,
460 {
461 let s = String::deserialize(deserializer)?;
462 Script::from_hex(&s).map_err(serde::de::Error::custom)
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use super::*;
476 use crate::opcodes::*;
477
478 #[test]
485 fn test_from_hex_roundtrip() {
486 let hex_str = "76a914e2a623699e81b291c0327f408fea765d534baa2a88ac";
487 let script = Script::from_hex(hex_str).expect("valid hex should parse");
488 assert_eq!(script.to_hex(), hex_str);
489 }
490
491 #[test]
493 fn test_from_hex_empty() {
494 let script = Script::from_hex("").expect("empty hex should parse");
495 assert!(script.is_empty());
496 assert_eq!(script.to_hex(), "");
497 }
498
499 #[test]
501 fn test_from_hex_invalid() {
502 let result = Script::from_hex("ZZZZ");
503 assert!(result.is_err());
504 }
505
506 #[test]
508 fn test_to_asm_p2pkh() {
509 let hex_str = "76a914e2a623699e81b291c0327f408fea765d534baa2a88ac";
510 let script = Script::from_hex(hex_str).expect("valid hex should parse");
511 let asm = script.to_asm();
512 assert_eq!(
513 asm,
514 "OP_DUP OP_HASH160 e2a623699e81b291c0327f408fea765d534baa2a OP_EQUALVERIFY OP_CHECKSIG"
515 );
516 }
517
518 #[test]
520 fn test_to_asm_empty() {
521 let script = Script::from_hex("").expect("empty hex should parse");
522 assert_eq!(script.to_asm(), "");
523 }
524
525 #[test]
528 fn test_from_asm_p2pkh() {
529 let asm =
530 "OP_DUP OP_HASH160 e2a623699e81b291c0327f408fea765d534baa2a OP_EQUALVERIFY OP_CHECKSIG";
531 let script = Script::from_asm(asm).expect("valid ASM should parse");
532 assert_eq!(
533 script.to_hex(),
534 "76a914e2a623699e81b291c0327f408fea765d534baa2a88ac"
535 );
536 }
537
538 #[test]
540 fn test_from_asm_empty() {
541 let script = Script::from_asm("").expect("empty ASM should parse");
542 assert!(script.is_empty());
543 }
544
545 #[test]
547 fn test_hex_asm_roundtrip() {
548 let hex_str = "76a914e2a623699e81b291c0327f408fea765d534baa2a88ac";
549 let script = Script::from_hex(hex_str).expect("valid hex should parse");
550 let asm = script.to_asm();
551 let script2 = Script::from_asm(&asm).expect("roundtrip ASM should parse");
552 assert_eq!(script.to_hex(), script2.to_hex());
553 }
554
555 #[test]
561 fn test_is_p2pkh() {
562 let script = Script::from_hex("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
563 .expect("valid hex");
564 assert!(script.is_p2pkh());
565 }
566
567 #[test]
569 fn test_is_p2pkh_false_for_p2sh() {
570 let script =
571 Script::from_hex("a9149de5aeaff9c48431ba4dd6e8af73d51f38e451cb87").expect("valid hex");
572 assert!(!script.is_p2pkh());
573 }
574
575 #[test]
577 fn test_is_p2pk() {
578 let script = Script::from_hex(
579 "2102f0d97c290e79bf2a8660c406aa56b6f189ff79f2245cc5aff82808b58131b4d5ac",
580 )
581 .expect("valid hex");
582 assert!(script.is_p2pk());
583 }
584
585 #[test]
587 fn test_is_p2pk_false_for_p2pkh() {
588 let script = Script::from_hex("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
589 .expect("valid hex");
590 assert!(!script.is_p2pk());
591 }
592
593 #[test]
595 fn test_is_p2sh() {
596 let script =
597 Script::from_hex("a9149de5aeaff9c48431ba4dd6e8af73d51f38e451cb87").expect("valid hex");
598 assert!(script.is_p2sh());
599 }
600
601 #[test]
603 fn test_is_p2sh_false_for_p2pkh() {
604 let script = Script::from_hex("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
605 .expect("valid hex");
606 assert!(!script.is_p2sh());
607 }
608
609 #[test]
611 fn test_is_data_op_false_op_return() {
612 let script = Script::from_hex(
614 "006a04ac1eed884d53027b2276657273696f6e223a22302e31222c22686569676874223a3634323436302c22707265764d696e65724964223a22303365393264336535633366376264393435646662663438653761393933393362316266623366313166333830616533306432383665376666326165633561323730227d"
615 ).expect("valid hex");
616 assert!(script.is_data());
617 }
618
619 #[test]
621 fn test_is_data_op_return() {
622 let script = Script::from_bytes(&[OP_RETURN, 0x04, 0x01, 0x02, 0x03, 0x04]);
623 assert!(script.is_data());
624 }
625
626 #[test]
628 fn test_is_data_false_for_p2pkh() {
629 let script = Script::from_hex("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
630 .expect("valid hex");
631 assert!(!script.is_data());
632 }
633
634 #[test]
636 fn test_is_multisig_out() {
637 let script = Script::from_hex("5201110122013353ae").expect("valid hex");
639 assert!(script.is_multisig_out());
640 }
641
642 #[test]
644 fn test_is_multisig_out_false_for_p2pkh() {
645 let script = Script::from_hex("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
646 .expect("valid hex");
647 assert!(!script.is_multisig_out());
648 }
649
650 #[test]
656 fn test_public_key_hash() {
657 let script = Script::from_hex("76a91404d03f746652cfcb6cb55119ab473a045137d26588ac")
658 .expect("valid hex");
659 let pkh = script.public_key_hash().expect("should extract PKH");
660 assert_eq!(
661 hex::encode(&pkh),
662 "04d03f746652cfcb6cb55119ab473a045137d265"
663 );
664 }
665
666 #[test]
668 fn test_public_key_hash_from_bytes() {
669 let bytes =
670 hex::decode("76a91404d03f746652cfcb6cb55119ab473a045137d26588ac").expect("valid hex");
671 let script = Script::from_bytes(&bytes);
672 let pkh = script.public_key_hash().expect("should extract PKH");
673 assert_eq!(
674 hex::encode(&pkh),
675 "04d03f746652cfcb6cb55119ab473a045137d265"
676 );
677 }
678
679 #[test]
681 fn test_public_key_hash_empty() {
682 let script = Script::new();
683 let result = script.public_key_hash();
684 assert!(result.is_err());
685 }
686
687 #[test]
689 fn test_public_key_hash_nonstandard() {
690 let script = Script::from_hex("76").expect("valid hex");
691 let result = script.public_key_hash();
692 assert!(result.is_err());
693 }
694
695 #[test]
701 fn test_append_push_data_small() {
702 let mut script = Script::new();
703 let data = vec![0x01, 0x02, 0x03, 0x04, 0x05];
704 script.append_push_data(&data).expect("push should succeed");
705 assert_eq!(script.to_hex(), "050102030405");
707 }
708
709 #[test]
711 fn test_append_push_data_medium() {
712 let mut script = Script::new();
713 let data = vec![0xAA; 80]; script.append_push_data(&data).expect("push should succeed");
715 let hex_str = script.to_hex();
716 assert_eq!(&hex_str[..4], "4c50");
718 assert_eq!(hex_str.len(), 4 + 80 * 2);
719 }
720
721 #[test]
723 fn test_append_push_data_large() {
724 let mut script = Script::new();
725 let data = vec![0xBB; 256]; script.append_push_data(&data).expect("push should succeed");
727 let hex_str = script.to_hex();
728 assert_eq!(&hex_str[..6], "4d0001");
730 assert_eq!(hex_str.len(), 6 + 256 * 2);
731 }
732
733 #[test]
735 fn test_append_opcodes_single() {
736 let mut script = Script::from_asm("OP_2 OP_2 OP_ADD").expect("valid ASM");
737 script
738 .append_opcodes(&[OP_EQUALVERIFY])
739 .expect("should succeed");
740 assert_eq!(script.to_asm(), "OP_2 OP_2 OP_ADD OP_EQUALVERIFY");
741 }
742
743 #[test]
745 fn test_append_opcodes_multiple() {
746 let mut script = Script::from_asm("OP_2 OP_2 OP_ADD").expect("valid ASM");
747 script
748 .append_opcodes(&[OP_EQUAL, OP_VERIFY])
749 .expect("should succeed");
750 assert_eq!(script.to_asm(), "OP_2 OP_2 OP_ADD OP_EQUAL OP_VERIFY");
751 }
752
753 #[test]
755 fn test_append_opcodes_rejects_pushdata() {
756 let mut script = Script::from_asm("OP_2 OP_2 OP_ADD").expect("valid ASM");
757 let result = script.append_opcodes(&[OP_EQUAL, OP_PUSHDATA1]);
758 assert!(result.is_err());
759 }
760
761 #[test]
767 fn test_equals_same_hex() {
768 let s1 = Script::from_hex("76a91404d03f746652cfcb6cb55119ab473a045137d26588ac")
769 .expect("valid hex");
770 let s2 = Script::from_hex("76a91404d03f746652cfcb6cb55119ab473a045137d26588ac")
771 .expect("valid hex");
772 assert!(s1.equals(&s2));
773 assert_eq!(s1, s2);
774 }
775
776 #[test]
778 fn test_equals_same_bytes() {
779 let bytes = hex::decode("5201110122013353ae").expect("valid hex");
780 let s1 = Script::from_bytes(&bytes);
781 let s2 = Script::from_bytes(&bytes);
782 assert!(s1.equals(&s2));
783 }
784
785 #[test]
787 fn test_not_equals_different_hex() {
788 let s1 = Script::from_hex("76a91404d03f746652cfcb6cb55119ab473a045137d26566ac")
789 .expect("valid hex");
790 let s2 = Script::from_hex("76a91404d03f746652cfcb6cb55119ab473a045137d26588ac")
791 .expect("valid hex");
792 assert!(!s1.equals(&s2));
793 assert_ne!(s1, s2);
794 }
795
796 #[test]
802 fn test_serde_serialize() {
803 let script = Script::from_asm("OP_2 OP_2 OP_ADD OP_4 OP_EQUALVERIFY").expect("valid ASM");
804 let json_str = serde_json::to_string(&script).expect("should serialize");
805 assert_eq!(json_str, r#""5252935488""#);
806 }
807
808 #[test]
810 fn test_serde_deserialize() {
811 let json_str = r#""5252935488""#;
812 let script: Script = serde_json::from_str(json_str).expect("should deserialize");
813 assert_eq!(script.to_hex(), "5252935488");
814 }
815
816 #[test]
818 fn test_serde_deserialize_empty() {
819 let json_str = r#""""#;
820 let script: Script = serde_json::from_str(json_str).expect("should deserialize");
821 assert_eq!(script.to_hex(), "");
822 }
823
824 #[test]
830 fn test_display() {
831 let script = Script::from_hex("76a914e2a623699e81b291c0327f408fea765d534baa2a88ac")
832 .expect("valid hex");
833 assert_eq!(
834 format!("{}", script),
835 "76a914e2a623699e81b291c0327f408fea765d534baa2a88ac"
836 );
837 }
838
839 #[test]
841 fn test_debug() {
842 let script = Script::from_hex("76a914e2a623699e81b291c0327f408fea765d534baa2a88ac")
843 .expect("valid hex");
844 let debug_str = format!("{:?}", script);
845 assert!(debug_str.starts_with("Script("));
846 assert!(debug_str.contains("76a914"));
847 }
848
849 #[test]
855 fn test_op_false_op_return_asm() {
856 let hex_str = "006a223139694733575459537362796f7333754a373333794b347a45696f69314665734e55010042666166383166326364346433663239383061623162363564616166656231656631333561626339643534386461633466366134656361623230653033656365362d300274780134";
857 let script = Script::from_hex(hex_str).expect("valid hex");
858 let asm = script.to_asm();
859 assert!(asm.starts_with("OP_FALSE OP_RETURN"));
861 }
862
863 #[test]
869 fn test_from_bytes_len() {
870 let bytes =
871 hex::decode("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac").expect("valid hex");
872 let script = Script::from_bytes(&bytes);
873 assert_eq!(script.len(), 25);
874 assert!(!script.is_empty());
875 }
876
877 #[test]
879 fn test_default() {
880 let script = Script::default();
881 assert!(script.is_empty());
882 assert_eq!(script.len(), 0);
883 }
884}