1use std::fmt;
8
9use crate::chunk::{decode_script, push_data_prefix, ScriptChunk};
10use crate::opcodes::*;
11use crate::ScriptError;
12
13#[derive(Clone, PartialEq, Eq)]
15pub struct Script(Vec<u8>);
16
17impl Script {
18 pub fn new() -> Self {
27 Script(Vec::new())
28 }
29
30 pub fn from_hex(hex_str: &str) -> Result<Self, ScriptError> {
38 let bytes = hex::decode(hex_str)
39 ?;
40 Ok(Script(bytes))
41 }
42
43 pub fn from_bytes(bytes: &[u8]) -> Self {
51 Script(bytes.to_vec())
52 }
53
54 pub fn from_asm(asm: &str) -> Result<Self, ScriptError> {
65 let mut script = Script::new();
66 if asm.is_empty() {
67 return Ok(script);
68 }
69 for section in asm.split(' ') {
70 if let Some(opcode) = string_to_opcode(section) {
71 script.append_opcodes(&[opcode])?;
72 } else {
73 script.append_push_data_hex(section)?;
74 }
75 }
76 Ok(script)
77 }
78
79 pub fn to_hex(&self) -> String {
88 hex::encode(&self.0)
89 }
90
91 pub fn to_asm(&self) -> String {
99 if self.0.is_empty() {
100 return String::new();
101 }
102 let mut parts = Vec::new();
103 let mut pos = 0;
104 while pos < self.0.len() {
105 match self.read_op(&mut pos) {
106 Ok(chunk) => {
107 let s = chunk.to_asm_string();
108 if !s.is_empty() {
109 parts.push(s);
110 }
111 }
112 Err(_) => return String::new(),
113 }
114 }
115 parts.join(" ")
116 }
117
118 pub fn to_bytes(&self) -> &[u8] {
123 &self.0
124 }
125
126 pub fn len(&self) -> usize {
131 self.0.len()
132 }
133
134 pub fn is_empty(&self) -> bool {
139 self.0.is_empty()
140 }
141
142 pub fn is_p2pkh(&self) -> bool {
153 let b = &self.0;
154 b.len() == 25
155 && b[0] == OP_DUP
156 && b[1] == OP_HASH160
157 && b[2] == OP_DATA_20
158 && b[23] == OP_EQUALVERIFY
159 && b[24] == OP_CHECKSIG
160 }
161
162 pub fn is_p2pk(&self) -> bool {
169 let parts = match self.chunks() {
170 Ok(p) => p,
171 Err(_) => return false,
172 };
173 if parts.len() == 2 && parts[1].op == OP_CHECKSIG {
174 if let Some(ref pubkey) = parts[0].data {
175 if !pubkey.is_empty() {
176 let version = pubkey[0];
177 if (version == 0x04 || version == 0x06 || version == 0x07) && pubkey.len() == 65 {
178 return true;
179 } else if (version == 0x03 || version == 0x02) && pubkey.len() == 33 {
180 return true;
181 }
182 }
183 }
184 }
185 false
186 }
187
188 pub fn is_p2sh(&self) -> bool {
195 let b = &self.0;
196 b.len() == 23
197 && b[0] == OP_HASH160
198 && b[1] == OP_DATA_20
199 && b[22] == OP_EQUAL
200 }
201
202 pub fn is_data(&self) -> bool {
207 let b = &self.0;
208 (!b.is_empty() && b[0] == OP_RETURN)
209 || (b.len() > 1 && b[0] == OP_FALSE && b[1] == OP_RETURN)
210 }
211
212 pub fn is_multisig_out(&self) -> bool {
219 let parts = match self.chunks() {
220 Ok(p) => p,
221 Err(_) => return false,
222 };
223 if parts.len() < 3 {
224 return false;
225 }
226 if !is_small_int_op(parts[0].op) {
227 return false;
228 }
229 for chunk in &parts[1..parts.len() - 2] {
230 match &chunk.data {
231 Some(d) if !d.is_empty() => {}
232 _ => return false,
233 }
234 }
235 let second_last = &parts[parts.len() - 2];
236 let last = &parts[parts.len() - 1];
237 is_small_int_op(second_last.op) && last.op == OP_CHECKMULTISIG
238 }
239
240 pub fn public_key_hash(&self) -> Result<Vec<u8>, ScriptError> {
251 if self.0.is_empty() {
252 return Err(ScriptError::EmptyScript);
253 }
254 if self.0.len() <= 2 || self.0[0] != OP_DUP || self.0[1] != OP_HASH160 {
255 return Err(ScriptError::NotP2PKH);
256 }
257 let tail = &self.0[2..];
258 let parts = decode_script(tail)?;
259 match parts.first() {
260 Some(chunk) => match &chunk.data {
261 Some(data) => Ok(data.clone()),
262 None => Err(ScriptError::NotP2PKH),
263 },
264 None => Err(ScriptError::NotP2PKH),
265 }
266 }
267
268 pub fn chunks(&self) -> Result<Vec<ScriptChunk>, ScriptError> {
273 decode_script(&self.0)
274 }
275
276 pub fn append_push_data(&mut self, data: &[u8]) -> Result<(), ScriptError> {
291 let prefix = push_data_prefix(data.len())?;
292 self.0.extend_from_slice(&prefix);
293 self.0.extend_from_slice(data);
294 Ok(())
295 }
296
297 pub fn append_push_data_hex(&mut self, hex_str: &str) -> Result<(), ScriptError> {
305 let data = hex::decode(hex_str)
306 .map_err(|_| ScriptError::InvalidOpcodeData)?;
307 self.append_push_data(&data)
308 }
309
310 pub fn append_opcodes(&mut self, opcodes: &[u8]) -> Result<(), ScriptError> {
321 for &op in opcodes {
322 if op >= OP_DATA_1 && op <= OP_PUSHDATA4 {
323 return Err(ScriptError::InvalidOpcodeType(
324 opcode_to_string(op).to_string(),
325 ));
326 }
327 }
328 self.0.extend_from_slice(opcodes);
329 Ok(())
330 }
331
332 pub fn equals(&self, other: &Script) -> bool {
340 self.0 == other.0
341 }
342
343 fn read_op(&self, pos: &mut usize) -> Result<ScriptChunk, ScriptError> {
357 let b = &self.0;
358 if *pos >= b.len() {
359 return Err(ScriptError::IndexOutOfRange);
360 }
361 let op = b[*pos];
362 match op {
363 OP_PUSHDATA1 => {
364 if b.len() < *pos + 2 {
365 return Err(ScriptError::DataTooSmall);
366 }
367 let length = b[*pos + 1] as usize;
368 *pos += 2;
369 if b.len() < *pos + length {
370 return Err(ScriptError::DataTooSmall);
371 }
372 let data = b[*pos..*pos + length].to_vec();
373 *pos += length;
374 Ok(ScriptChunk { op: OP_PUSHDATA1, data: Some(data) })
375 }
376 OP_PUSHDATA2 => {
377 if b.len() < *pos + 3 {
378 return Err(ScriptError::DataTooSmall);
379 }
380 let length = u16::from_le_bytes([b[*pos + 1], b[*pos + 2]]) as usize;
381 *pos += 3;
382 if b.len() < *pos + length {
383 return Err(ScriptError::DataTooSmall);
384 }
385 let data = b[*pos..*pos + length].to_vec();
386 *pos += length;
387 Ok(ScriptChunk { op: OP_PUSHDATA2, data: Some(data) })
388 }
389 OP_PUSHDATA4 => {
390 if b.len() < *pos + 5 {
391 return Err(ScriptError::DataTooSmall);
392 }
393 let length = u32::from_le_bytes([
394 b[*pos + 1], b[*pos + 2], b[*pos + 3], b[*pos + 4],
395 ]) as usize;
396 *pos += 5;
397 if b.len() < *pos + length {
398 return Err(ScriptError::DataTooSmall);
399 }
400 let data = b[*pos..*pos + length].to_vec();
401 *pos += length;
402 Ok(ScriptChunk { op: OP_PUSHDATA4, data: Some(data) })
403 }
404 _ if op >= OP_DATA_1 && op < OP_PUSHDATA1 => {
405 let length = op as usize;
406 if b.len() < *pos + 1 + length {
407 return Err(ScriptError::DataTooSmall);
408 }
409 let data = b[*pos + 1..*pos + 1 + length].to_vec();
410 *pos += 1 + length;
411 Ok(ScriptChunk { op, data: Some(data) })
412 }
413 _ => {
414 *pos += 1;
415 Ok(ScriptChunk { op, data: None })
416 }
417 }
418 }
419}
420
421impl Default for Script {
422 fn default() -> Self {
423 Self::new()
424 }
425}
426
427impl fmt::Display for Script {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430 write!(f, "{}", self.to_hex())
431 }
432}
433
434impl fmt::Debug for Script {
435 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
436 write!(f, "Script({})", self.to_hex())
437 }
438}
439
440impl serde::Serialize for Script {
441 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
442 where
443 S: serde::Serializer,
444 {
445 serializer.serialize_str(&self.to_hex())
446 }
447}
448
449impl<'de> serde::Deserialize<'de> for Script {
450 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
451 where
452 D: serde::Deserializer<'de>,
453 {
454 let s = String::deserialize(deserializer)?;
455 Script::from_hex(&s).map_err(serde::de::Error::custom)
456 }
457}
458
459#[cfg(test)]
460mod tests {
461 use super::*;
469 use crate::opcodes::*;
470
471 #[test]
478 fn test_from_hex_roundtrip() {
479 let hex_str = "76a914e2a623699e81b291c0327f408fea765d534baa2a88ac";
480 let script = Script::from_hex(hex_str).expect("valid hex should parse");
481 assert_eq!(script.to_hex(), hex_str);
482 }
483
484 #[test]
486 fn test_from_hex_empty() {
487 let script = Script::from_hex("").expect("empty hex should parse");
488 assert!(script.is_empty());
489 assert_eq!(script.to_hex(), "");
490 }
491
492 #[test]
494 fn test_from_hex_invalid() {
495 let result = Script::from_hex("ZZZZ");
496 assert!(result.is_err());
497 }
498
499 #[test]
501 fn test_to_asm_p2pkh() {
502 let hex_str = "76a914e2a623699e81b291c0327f408fea765d534baa2a88ac";
503 let script = Script::from_hex(hex_str).expect("valid hex should parse");
504 let asm = script.to_asm();
505 assert_eq!(
506 asm,
507 "OP_DUP OP_HASH160 e2a623699e81b291c0327f408fea765d534baa2a OP_EQUALVERIFY OP_CHECKSIG"
508 );
509 }
510
511 #[test]
513 fn test_to_asm_empty() {
514 let script = Script::from_hex("").expect("empty hex should parse");
515 assert_eq!(script.to_asm(), "");
516 }
517
518 #[test]
521 fn test_from_asm_p2pkh() {
522 let asm = "OP_DUP OP_HASH160 e2a623699e81b291c0327f408fea765d534baa2a OP_EQUALVERIFY OP_CHECKSIG";
523 let script = Script::from_asm(asm).expect("valid ASM should parse");
524 assert_eq!(
525 script.to_hex(),
526 "76a914e2a623699e81b291c0327f408fea765d534baa2a88ac"
527 );
528 }
529
530 #[test]
532 fn test_from_asm_empty() {
533 let script = Script::from_asm("").expect("empty ASM should parse");
534 assert!(script.is_empty());
535 }
536
537 #[test]
539 fn test_hex_asm_roundtrip() {
540 let hex_str = "76a914e2a623699e81b291c0327f408fea765d534baa2a88ac";
541 let script = Script::from_hex(hex_str).expect("valid hex should parse");
542 let asm = script.to_asm();
543 let script2 = Script::from_asm(&asm).expect("roundtrip ASM should parse");
544 assert_eq!(script.to_hex(), script2.to_hex());
545 }
546
547 #[test]
553 fn test_is_p2pkh() {
554 let script = Script::from_hex("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
555 .expect("valid hex");
556 assert!(script.is_p2pkh());
557 }
558
559 #[test]
561 fn test_is_p2pkh_false_for_p2sh() {
562 let script = Script::from_hex("a9149de5aeaff9c48431ba4dd6e8af73d51f38e451cb87")
563 .expect("valid hex");
564 assert!(!script.is_p2pkh());
565 }
566
567 #[test]
569 fn test_is_p2pk() {
570 let script = Script::from_hex(
571 "2102f0d97c290e79bf2a8660c406aa56b6f189ff79f2245cc5aff82808b58131b4d5ac",
572 )
573 .expect("valid hex");
574 assert!(script.is_p2pk());
575 }
576
577 #[test]
579 fn test_is_p2pk_false_for_p2pkh() {
580 let script = Script::from_hex("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
581 .expect("valid hex");
582 assert!(!script.is_p2pk());
583 }
584
585 #[test]
587 fn test_is_p2sh() {
588 let script = Script::from_hex("a9149de5aeaff9c48431ba4dd6e8af73d51f38e451cb87")
589 .expect("valid hex");
590 assert!(script.is_p2sh());
591 }
592
593 #[test]
595 fn test_is_p2sh_false_for_p2pkh() {
596 let script = Script::from_hex("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
597 .expect("valid hex");
598 assert!(!script.is_p2sh());
599 }
600
601 #[test]
603 fn test_is_data_op_false_op_return() {
604 let script = Script::from_hex(
606 "006a04ac1eed884d53027b2276657273696f6e223a22302e31222c22686569676874223a3634323436302c22707265764d696e65724964223a22303365393264336535633366376264393435646662663438653761393933393362316266623366313166333830616533306432383665376666326165633561323730227d"
607 ).expect("valid hex");
608 assert!(script.is_data());
609 }
610
611 #[test]
613 fn test_is_data_op_return() {
614 let script = Script::from_bytes(&[OP_RETURN, 0x04, 0x01, 0x02, 0x03, 0x04]);
615 assert!(script.is_data());
616 }
617
618 #[test]
620 fn test_is_data_false_for_p2pkh() {
621 let script = Script::from_hex("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
622 .expect("valid hex");
623 assert!(!script.is_data());
624 }
625
626 #[test]
628 fn test_is_multisig_out() {
629 let script = Script::from_hex("5201110122013353ae").expect("valid hex");
631 assert!(script.is_multisig_out());
632 }
633
634 #[test]
636 fn test_is_multisig_out_false_for_p2pkh() {
637 let script = Script::from_hex("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
638 .expect("valid hex");
639 assert!(!script.is_multisig_out());
640 }
641
642 #[test]
648 fn test_public_key_hash() {
649 let script = Script::from_hex("76a91404d03f746652cfcb6cb55119ab473a045137d26588ac")
650 .expect("valid hex");
651 let pkh = script.public_key_hash().expect("should extract PKH");
652 assert_eq!(hex::encode(&pkh), "04d03f746652cfcb6cb55119ab473a045137d265");
653 }
654
655 #[test]
657 fn test_public_key_hash_from_bytes() {
658 let bytes = hex::decode("76a91404d03f746652cfcb6cb55119ab473a045137d26588ac")
659 .expect("valid hex");
660 let script = Script::from_bytes(&bytes);
661 let pkh = script.public_key_hash().expect("should extract PKH");
662 assert_eq!(hex::encode(&pkh), "04d03f746652cfcb6cb55119ab473a045137d265");
663 }
664
665 #[test]
667 fn test_public_key_hash_empty() {
668 let script = Script::new();
669 let result = script.public_key_hash();
670 assert!(result.is_err());
671 }
672
673 #[test]
675 fn test_public_key_hash_nonstandard() {
676 let script = Script::from_hex("76").expect("valid hex");
677 let result = script.public_key_hash();
678 assert!(result.is_err());
679 }
680
681 #[test]
687 fn test_append_push_data_small() {
688 let mut script = Script::new();
689 let data = vec![0x01, 0x02, 0x03, 0x04, 0x05];
690 script.append_push_data(&data).expect("push should succeed");
691 assert_eq!(script.to_hex(), "050102030405");
693 }
694
695 #[test]
697 fn test_append_push_data_medium() {
698 let mut script = Script::new();
699 let data = vec![0xAA; 80]; script.append_push_data(&data).expect("push should succeed");
701 let hex_str = script.to_hex();
702 assert_eq!(&hex_str[..4], "4c50");
704 assert_eq!(hex_str.len(), 4 + 80 * 2);
705 }
706
707 #[test]
709 fn test_append_push_data_large() {
710 let mut script = Script::new();
711 let data = vec![0xBB; 256]; script.append_push_data(&data).expect("push should succeed");
713 let hex_str = script.to_hex();
714 assert_eq!(&hex_str[..6], "4d0001");
716 assert_eq!(hex_str.len(), 6 + 256 * 2);
717 }
718
719 #[test]
721 fn test_append_opcodes_single() {
722 let mut script = Script::from_asm("OP_2 OP_2 OP_ADD").expect("valid ASM");
723 script
724 .append_opcodes(&[OP_EQUALVERIFY])
725 .expect("should succeed");
726 assert_eq!(script.to_asm(), "OP_2 OP_2 OP_ADD OP_EQUALVERIFY");
727 }
728
729 #[test]
731 fn test_append_opcodes_multiple() {
732 let mut script = Script::from_asm("OP_2 OP_2 OP_ADD").expect("valid ASM");
733 script
734 .append_opcodes(&[OP_EQUAL, OP_VERIFY])
735 .expect("should succeed");
736 assert_eq!(script.to_asm(), "OP_2 OP_2 OP_ADD OP_EQUAL OP_VERIFY");
737 }
738
739 #[test]
741 fn test_append_opcodes_rejects_pushdata() {
742 let mut script = Script::from_asm("OP_2 OP_2 OP_ADD").expect("valid ASM");
743 let result = script.append_opcodes(&[OP_EQUAL, OP_PUSHDATA1]);
744 assert!(result.is_err());
745 }
746
747 #[test]
753 fn test_equals_same_hex() {
754 let s1 = Script::from_hex("76a91404d03f746652cfcb6cb55119ab473a045137d26588ac")
755 .expect("valid hex");
756 let s2 = Script::from_hex("76a91404d03f746652cfcb6cb55119ab473a045137d26588ac")
757 .expect("valid hex");
758 assert!(s1.equals(&s2));
759 assert_eq!(s1, s2);
760 }
761
762 #[test]
764 fn test_equals_same_bytes() {
765 let bytes = hex::decode("5201110122013353ae").expect("valid hex");
766 let s1 = Script::from_bytes(&bytes);
767 let s2 = Script::from_bytes(&bytes);
768 assert!(s1.equals(&s2));
769 }
770
771 #[test]
773 fn test_not_equals_different_hex() {
774 let s1 = Script::from_hex("76a91404d03f746652cfcb6cb55119ab473a045137d26566ac")
775 .expect("valid hex");
776 let s2 = Script::from_hex("76a91404d03f746652cfcb6cb55119ab473a045137d26588ac")
777 .expect("valid hex");
778 assert!(!s1.equals(&s2));
779 assert_ne!(s1, s2);
780 }
781
782 #[test]
788 fn test_serde_serialize() {
789 let script = Script::from_asm("OP_2 OP_2 OP_ADD OP_4 OP_EQUALVERIFY")
790 .expect("valid ASM");
791 let json_str = serde_json::to_string(&script).expect("should serialize");
792 assert_eq!(json_str, r#""5252935488""#);
793 }
794
795 #[test]
797 fn test_serde_deserialize() {
798 let json_str = r#""5252935488""#;
799 let script: Script = serde_json::from_str(json_str).expect("should deserialize");
800 assert_eq!(script.to_hex(), "5252935488");
801 }
802
803 #[test]
805 fn test_serde_deserialize_empty() {
806 let json_str = r#""""#;
807 let script: Script = serde_json::from_str(json_str).expect("should deserialize");
808 assert_eq!(script.to_hex(), "");
809 }
810
811 #[test]
817 fn test_display() {
818 let script = Script::from_hex("76a914e2a623699e81b291c0327f408fea765d534baa2a88ac")
819 .expect("valid hex");
820 assert_eq!(
821 format!("{}", script),
822 "76a914e2a623699e81b291c0327f408fea765d534baa2a88ac"
823 );
824 }
825
826 #[test]
828 fn test_debug() {
829 let script = Script::from_hex("76a914e2a623699e81b291c0327f408fea765d534baa2a88ac")
830 .expect("valid hex");
831 let debug_str = format!("{:?}", script);
832 assert!(debug_str.starts_with("Script("));
833 assert!(debug_str.contains("76a914"));
834 }
835
836 #[test]
842 fn test_op_false_op_return_asm() {
843 let hex_str = "006a223139694733575459537362796f7333754a373333794b347a45696f69314665734e55010042666166383166326364346433663239383061623162363564616166656231656631333561626339643534386461633466366134656361623230653033656365362d300274780134";
844 let script = Script::from_hex(hex_str).expect("valid hex");
845 let asm = script.to_asm();
846 assert!(asm.starts_with("OP_FALSE OP_RETURN"));
848 }
849
850 #[test]
856 fn test_from_bytes_len() {
857 let bytes = hex::decode("76a91403ececf2d12a7f614aef4c82ecf13c303bd9975d88ac")
858 .expect("valid hex");
859 let script = Script::from_bytes(&bytes);
860 assert_eq!(script.len(), 25);
861 assert!(!script.is_empty());
862 }
863
864 #[test]
866 fn test_default() {
867 let script = Script::default();
868 assert!(script.is_empty());
869 assert_eq!(script.len(), 0);
870 }
871}