1mod borrowed;
6mod owned;
7mod tag;
8
9use core::cmp::Ordering;
10use core::fmt;
11#[cfg(feature = "serde")]
12use core::marker::PhantomData;
13
14#[cfg(feature = "hex")]
15use hex_unstable::DisplayHex;
16use internals::script::{self, PushDataLenLen};
17
18use crate::prelude::rc::Rc;
19#[cfg(target_has_atomic = "ptr")]
20use crate::prelude::sync::Arc;
21use crate::prelude::{Borrow, BorrowMut, Box, Cow, ToOwned, Vec};
22
23#[rustfmt::skip] #[doc(inline)]
25pub use self::{
26 borrowed::{Script, ScriptEncoder},
27 owned::{ScriptBuf, ScriptBufDecoder, ScriptBufDecoderError},
28 tag::{Tag, RedeemScriptTag, ScriptPubKeyTag, ScriptSigTag, TapScriptTag, WitnessScriptTag},
29};
30#[doc(inline)]
31pub use crate::hash_types::{
32 RedeemScriptSizeError, ScriptHash, WScriptHash, WitnessScriptSizeError,
33};
34
35pub type RedeemScriptBuf = ScriptBuf<RedeemScriptTag>;
37
38pub type RedeemScript = Script<RedeemScriptTag>;
40
41pub type ScriptPubKey = Script<ScriptPubKeyTag>;
43
44pub type ScriptSig = Script<ScriptSigTag>;
46
47pub type ScriptPubKeyBuf = ScriptBuf<ScriptPubKeyTag>;
49
50pub type ScriptPubKeyBufDecoder = ScriptBufDecoder<ScriptPubKeyTag>;
52
53pub type ScriptSigBuf = ScriptBuf<ScriptSigTag>;
55
56pub type ScriptSigBufDecoder = ScriptBufDecoder<ScriptSigTag>;
58
59pub type TapScriptBuf = ScriptBuf<TapScriptTag>;
61
62pub type TapScript = Script<TapScriptTag>;
64
65pub type WitnessScriptBuf = ScriptBuf<WitnessScriptTag>;
67
68pub type WitnessScript = Script<WitnessScriptTag>;
70
71pub const MAX_REDEEM_SCRIPT_SIZE: usize = 520;
73pub const MAX_WITNESS_SCRIPT_SIZE: usize = 10_000;
75
76pub trait ScriptHashableTag: sealed::Sealed {}
87
88impl ScriptHashableTag for RedeemScriptTag {}
89impl ScriptHashableTag for ScriptPubKeyTag {}
90
91mod sealed {
92 pub trait Sealed {}
93 impl Sealed for super::RedeemScriptTag {}
94 impl Sealed for super::ScriptPubKeyTag {}
95}
96
97impl<T: ScriptHashableTag> TryFrom<ScriptBuf<T>> for ScriptHash {
98 type Error = RedeemScriptSizeError;
99
100 #[inline]
101 fn try_from(redeem_script: ScriptBuf<T>) -> Result<Self, Self::Error> {
102 Self::from_script(&redeem_script)
103 }
104}
105
106impl<T: ScriptHashableTag> TryFrom<&ScriptBuf<T>> for ScriptHash {
107 type Error = RedeemScriptSizeError;
108
109 #[inline]
110 fn try_from(redeem_script: &ScriptBuf<T>) -> Result<Self, Self::Error> {
111 Self::from_script(redeem_script)
112 }
113}
114
115impl<T: ScriptHashableTag> TryFrom<&Script<T>> for ScriptHash {
116 type Error = RedeemScriptSizeError;
117
118 #[inline]
119 fn try_from(redeem_script: &Script<T>) -> Result<Self, Self::Error> {
120 Self::from_script(redeem_script)
121 }
122}
123
124impl TryFrom<WitnessScriptBuf> for WScriptHash {
125 type Error = WitnessScriptSizeError;
126
127 #[inline]
128 fn try_from(witness_script: WitnessScriptBuf) -> Result<Self, Self::Error> {
129 Self::from_script(&witness_script)
130 }
131}
132
133impl TryFrom<&WitnessScriptBuf> for WScriptHash {
134 type Error = WitnessScriptSizeError;
135
136 #[inline]
137 fn try_from(witness_script: &WitnessScriptBuf) -> Result<Self, Self::Error> {
138 Self::from_script(witness_script)
139 }
140}
141
142impl TryFrom<&WitnessScript> for WScriptHash {
143 type Error = WitnessScriptSizeError;
144
145 #[inline]
146 fn try_from(witness_script: &WitnessScript) -> Result<Self, Self::Error> {
147 Self::from_script(witness_script)
148 }
149}
150
151impl<T> From<ScriptBuf<T>> for Box<Script<T>> {
154 #[inline]
155 fn from(v: ScriptBuf<T>) -> Self { v.into_boxed_script() }
156}
157
158impl<T> From<ScriptBuf<T>> for Cow<'_, Script<T>> {
159 #[inline]
160 fn from(value: ScriptBuf<T>) -> Self { Cow::Owned(value) }
161}
162
163impl<'a, T> From<Cow<'a, Script<T>>> for ScriptBuf<T> {
164 #[inline]
165 fn from(value: Cow<'a, Script<T>>) -> Self {
166 match value {
167 Cow::Owned(owned) => owned,
168 Cow::Borrowed(borrowed) => borrowed.into(),
169 }
170 }
171}
172
173impl<'a, T> From<Cow<'a, Script<T>>> for Box<Script<T>> {
174 #[inline]
175 fn from(value: Cow<'a, Script<T>>) -> Self {
176 match value {
177 Cow::Owned(owned) => owned.into(),
178 Cow::Borrowed(borrowed) => borrowed.into(),
179 }
180 }
181}
182
183impl<'a, T> From<&'a Script<T>> for Box<Script<T>> {
184 #[inline]
185 fn from(value: &'a Script<T>) -> Self { value.to_owned().into() }
186}
187
188impl<'a, T> From<&'a Script<T>> for ScriptBuf<T> {
189 #[inline]
190 fn from(value: &'a Script<T>) -> Self { value.to_owned() }
191}
192
193impl<'a, T> From<&'a Script<T>> for Cow<'a, Script<T>> {
194 #[inline]
195 fn from(value: &'a Script<T>) -> Self { Cow::Borrowed(value) }
196}
197
198#[cfg(target_has_atomic = "ptr")]
200impl<'a, T> From<&'a Script<T>> for Arc<Script<T>> {
201 #[inline]
202 fn from(value: &'a Script<T>) -> Self { Script::from_arc_bytes(Arc::from(value.as_bytes())) }
203}
204
205impl<'a, T> From<&'a Script<T>> for Rc<Script<T>> {
206 #[inline]
207 fn from(value: &'a Script<T>) -> Self { Script::from_rc_bytes(Rc::from(value.as_bytes())) }
208}
209
210impl<T> From<Vec<u8>> for ScriptBuf<T> {
211 #[inline]
212 fn from(v: Vec<u8>) -> Self { Self::from_bytes(v) }
213}
214
215impl<T> From<ScriptBuf<T>> for Vec<u8> {
216 #[inline]
217 fn from(v: ScriptBuf<T>) -> Self { v.into_bytes() }
218}
219
220impl<T> AsRef<Self> for Script<T> {
221 #[inline]
222 fn as_ref(&self) -> &Self { self }
223}
224
225impl<T> AsRef<Script<T>> for ScriptBuf<T> {
226 #[inline]
227 fn as_ref(&self) -> &Script<T> { self }
228}
229
230impl<T> AsRef<[u8]> for Script<T> {
231 #[inline]
232 fn as_ref(&self) -> &[u8] { self.as_bytes() }
233}
234
235impl<T> AsRef<[u8]> for ScriptBuf<T> {
236 #[inline]
237 fn as_ref(&self) -> &[u8] { self.as_bytes() }
238}
239
240impl<T> AsMut<Self> for Script<T> {
241 #[inline]
242 fn as_mut(&mut self) -> &mut Self { self }
243}
244
245impl<T> AsMut<Script<T>> for ScriptBuf<T> {
246 #[inline]
247 fn as_mut(&mut self) -> &mut Script<T> { self }
248}
249
250impl<T> AsMut<[u8]> for Script<T> {
251 #[inline]
252 fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
253}
254
255impl<T> AsMut<[u8]> for ScriptBuf<T> {
256 #[inline]
257 fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
258}
259
260impl<T> fmt::Debug for Script<T> {
261 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
262 f.write_str("Script(")?;
263 fmt::Display::fmt(self, f)?;
264 f.write_str(")")
265 }
266}
267
268impl<T> fmt::Debug for ScriptBuf<T> {
269 #[inline]
270 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self.as_script(), f) }
271}
272
273impl<T> fmt::Display for Script<T> {
274 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
275 macro_rules! read_push_data_len {
277 ($iter:expr, $size:path, $formatter:expr) => {
278 match script::read_push_data_len($iter, $size) {
279 Ok(n) => n,
280 Err(_) => {
281 $formatter.write_str("<unexpected end>")?;
282 break;
283 }
284 }
285 };
286 }
287
288 let mut iter = self.as_bytes().iter();
289 let mut at_least_one = false;
291 while let Some(byte) = iter.next().copied() {
294 use crate::opcodes::{OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4};
295
296 let data_len = if byte <= 75 {
297 usize::from(byte)
298 } else {
299 match byte {
300 OP_PUSHDATA1 => {
301 read_push_data_len!(&mut iter, PushDataLenLen::One, f)
303 }
304 OP_PUSHDATA2 => {
305 read_push_data_len!(&mut iter, PushDataLenLen::Two, f)
307 }
308 OP_PUSHDATA4 => {
309 read_push_data_len!(&mut iter, PushDataLenLen::Four, f)
311 }
312 _ => 0,
313 }
314 };
315
316 if at_least_one {
317 f.write_str(" ")?;
318 } else {
319 at_least_one = true;
320 }
321 crate::opcodes::fmt_opcode(byte, f)?;
323 if data_len > 0 {
325 f.write_str(" ")?;
326 if data_len <= iter.len() {
327 for ch in iter.by_ref().take(data_len) {
328 write!(f, "{:02x}", ch)?;
329 }
330 } else {
331 f.write_str("<push past end>")?;
332 break;
333 }
334 }
335 }
336 Ok(())
337 }
338}
339
340impl<T> fmt::Display for ScriptBuf<T> {
341 #[inline]
342 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self.as_script(), f) }
343}
344
345#[cfg(feature = "hex")]
346impl<T> fmt::LowerHex for Script<T> {
347 #[inline]
348 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
349 fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
350 }
351}
352
353#[cfg(feature = "hex")]
354impl<T> fmt::LowerHex for ScriptBuf<T> {
355 #[inline]
356 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self.as_script(), f) }
357}
358
359#[cfg(feature = "hex")]
360impl<T> fmt::UpperHex for Script<T> {
361 #[inline]
362 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
363 fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
364 }
365}
366
367#[cfg(feature = "hex")]
368impl<T> fmt::UpperHex for ScriptBuf<T> {
369 #[inline]
370 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(self.as_script(), f) }
371}
372
373impl<T> Borrow<Script<T>> for ScriptBuf<T> {
374 #[inline]
375 fn borrow(&self) -> &Script<T> { self }
376}
377
378impl<T> BorrowMut<Script<T>> for ScriptBuf<T> {
379 #[inline]
380 fn borrow_mut(&mut self) -> &mut Script<T> { self }
381}
382
383impl<T: PartialEq> PartialEq<ScriptBuf<T>> for Script<T> {
384 #[inline]
385 fn eq(&self, other: &ScriptBuf<T>) -> bool { self.eq(other.as_script()) }
386}
387
388impl<T: PartialEq> PartialEq<Script<T>> for ScriptBuf<T> {
389 #[inline]
390 fn eq(&self, other: &Script<T>) -> bool { self.as_script().eq(other) }
391}
392
393impl<T: PartialOrd> PartialOrd<Script<T>> for ScriptBuf<T> {
394 #[inline]
395 fn partial_cmp(&self, other: &Script<T>) -> Option<Ordering> {
396 self.as_script().partial_cmp(other)
397 }
398}
399
400impl<T: PartialOrd> PartialOrd<ScriptBuf<T>> for Script<T> {
401 #[inline]
402 fn partial_cmp(&self, other: &ScriptBuf<T>) -> Option<Ordering> {
403 self.partial_cmp(other.as_script())
404 }
405}
406
407#[cfg(feature = "serde")]
408impl<T> serde::Serialize for Script<T> {
409 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
411 where
412 S: serde::Serializer,
413 {
414 if serializer.is_human_readable() {
415 serializer.collect_str(&format_args!("{:x}", self))
416 } else {
417 serializer.serialize_bytes(self.as_bytes())
418 }
419 }
420}
421
422#[cfg(feature = "serde")]
424impl<'de, T> serde::Deserialize<'de> for &'de Script<T> {
425 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
426 where
427 D: serde::Deserializer<'de>,
428 {
429 struct Visitor<T>(PhantomData<T>);
430 impl<'de, T: 'de> serde::de::Visitor<'de> for Visitor<T> {
431 type Value = &'de Script<T>;
432
433 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
434 formatter.write_str("borrowed bytes")
435 }
436
437 fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
438 where
439 E: serde::de::Error,
440 {
441 Ok(Script::from_bytes(v))
442 }
443 }
444
445 if deserializer.is_human_readable() {
446 use crate::serde::de::Error;
447
448 return Err(D::Error::custom(
449 "deserialization of `&Script` from human-readable formats is not possible",
450 ));
451 }
452
453 deserializer.deserialize_bytes(Visitor(PhantomData))
454 }
455}
456
457#[cfg(feature = "serde")]
458impl<T> serde::Serialize for ScriptBuf<T> {
459 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
461 where
462 S: serde::Serializer,
463 {
464 (**self).serialize(serializer)
465 }
466}
467
468#[cfg(feature = "serde")]
469impl<'de, T> serde::Deserialize<'de> for ScriptBuf<T> {
470 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
471 where
472 D: serde::Deserializer<'de>,
473 {
474 use core::fmt::Formatter;
475
476 if deserializer.is_human_readable() {
477 struct Visitor<T>(PhantomData<T>);
478 impl<T> serde::de::Visitor<'_> for Visitor<T> {
479 type Value = ScriptBuf<T>;
480
481 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
482 formatter.write_str("a script hex")
483 }
484
485 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
486 where
487 E: serde::de::Error,
488 {
489 let v = hex::decode_to_vec(v).map_err(E::custom)?;
490 Ok(ScriptBuf::from(v))
491 }
492 }
493 deserializer.deserialize_str(Visitor(PhantomData))
494 } else {
495 struct BytesVisitor<T>(PhantomData<T>);
496
497 impl<T> serde::de::Visitor<'_> for BytesVisitor<T> {
498 type Value = ScriptBuf<T>;
499
500 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
501 formatter.write_str("a script Vec<u8>")
502 }
503
504 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
505 where
506 E: serde::de::Error,
507 {
508 Ok(ScriptBuf::from(v.to_vec()))
509 }
510
511 fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
512 where
513 E: serde::de::Error,
514 {
515 Ok(ScriptBuf::from(v))
516 }
517 }
518 deserializer.deserialize_byte_buf(BytesVisitor(PhantomData))
519 }
520 }
521}
522
523#[cfg(test)]
524mod tests {
525 #[cfg(feature = "alloc")]
526 use alloc::{format, vec};
527
528 use hashes::{hash160, sha256};
529
530 use super::*;
531
532 type Script = ScriptSig;
534 type ScriptBuf = ScriptSigBuf;
535
536 #[test]
537 fn scriptbuf_from_vec_u8() {
538 let vec = vec![0x51, 0x52, 0x53];
539 let script_buf: ScriptBuf = vec.clone().into();
540 let result: Vec<u8> = script_buf.into();
541 assert_eq!(result, vec);
542 }
543
544 #[test]
545 fn scriptbuf_as_ref() {
546 let script_buf = ScriptBuf::from(vec![0x51, 0x52, 0x53]);
547 let script_ref: &[u8] = script_buf.as_ref();
548 assert_eq!(script_ref, &[0x51, 0x52, 0x53]);
549
550 let script_ref: &Script = script_buf.as_ref();
551 assert_eq!(script_ref.as_bytes(), &[0x51, 0x52, 0x53]);
552 }
553
554 #[test]
555 fn scriptbuf_as_mut() {
556 let mut script_buf = ScriptBuf::from(vec![0x51, 0x52, 0x53]);
557
558 let script_mut: &mut [u8] = script_buf.as_mut();
559 script_mut[0] = 0x50;
560 assert_eq!(script_mut, [0x50, 0x52, 0x53]);
561
562 let script_mut: &mut Script = script_buf.as_mut();
563 script_mut.as_mut_bytes()[1] = 0x51;
564 assert_eq!(script_buf.as_bytes(), &[0x50, 0x51, 0x53]);
565 }
566
567 #[test]
568 fn scriptbuf_borrow_mut() {
569 let mut script_buf = ScriptBuf::from(vec![0x51, 0x52, 0x53]);
570 let script_mut: &mut Script = script_buf.borrow_mut();
571 script_mut.as_mut_bytes()[0] = 0x50;
572
573 assert_eq!(script_buf.as_bytes(), &[0x50, 0x52, 0x53]);
574 }
575
576 #[test]
577 #[allow(clippy::useless_asref)]
578 fn script_as_ref() {
579 let script = Script::from_bytes(&[0x51, 0x52, 0x53]);
580 let script_ref: &[u8] = script.as_ref();
581 assert_eq!(script_ref, &[0x51, 0x52, 0x53]);
582
583 let script_ref: &Script = script.as_ref();
584 assert_eq!(script_ref.as_bytes(), &[0x51, 0x52, 0x53]);
585 }
586
587 #[test]
588 #[allow(clippy::useless_asref)]
589 fn script_as_mut() {
590 let bytes = &mut [0x51, 0x52, 0x53];
591 let script = Script::from_bytes_mut(bytes);
592
593 let script_mut: &mut [u8] = script.as_mut();
594 script_mut[0] = 0x50;
595 assert_eq!(script_mut, [0x50, 0x52, 0x53]);
596
597 let script_mut: &mut Script = script.as_mut();
598 script_mut.as_mut_bytes()[1] = 0x51;
599 assert_eq!(script.as_bytes(), &[0x50, 0x51, 0x53]);
600 }
601
602 #[test]
603 fn partial_ord() {
604 let script_small = Script::from_bytes(&[0x51, 0x52, 0x53]);
605 let script_big = Script::from_bytes(&[0x54, 0x55, 0x56]);
606 let script_buf_small = ScriptBuf::from(vec![0x51, 0x52, 0x53]);
607 let script_buf_big = ScriptBuf::from(vec![0x54, 0x55, 0x56]);
608
609 assert!(script_small == &script_buf_small);
610 assert!(script_buf_small == *script_small);
611 assert!(script_small != &script_buf_big);
612 assert!(script_buf_small != *script_big);
613
614 assert!(script_small < &script_buf_big);
615 assert!(script_buf_small < *script_big);
616 assert!(script_big > &script_buf_small);
617 assert!(script_buf_big > *script_small);
618 }
619
620 #[test]
621 fn script_hash_from_script() {
622 let script = RedeemScript::from_bytes(&[0x51; 520]);
623 assert!(ScriptHash::from_script(script).is_ok());
624
625 let script = RedeemScript::from_bytes(&[0x51; 521]);
626 assert!(ScriptHash::from_script(script).is_err());
627 }
628
629 #[test]
630 fn script_hash_from_script_unchecked() {
631 let script = WitnessScript::from_bytes(&[0x51; 521]);
632
633 let got = ScriptHash::from_script_unchecked(script);
634 let want =
635 ScriptHash::from_byte_array(hash160::Hash::hash(script.as_bytes()).to_byte_array());
636
637 assert_eq!(got, want);
638 }
639
640 #[test]
641 fn wscript_hash_from_script() {
642 let script = WitnessScript::from_bytes(&[0x51; 10_000]);
643 assert!(WScriptHash::from_script(script).is_ok());
644
645 let script = WitnessScript::from_bytes(&[0x51; 10_001]);
646 assert!(WScriptHash::from_script(script).is_err());
647 }
648
649 #[test]
650 fn wscript_hash_from_script_unchecked() {
651 let script = WitnessScript::from_bytes(&[0x51; 10_001]);
652
653 let got = WScriptHash::from_script_unchecked(script);
654 let want =
655 WScriptHash::from_byte_array(sha256::Hash::hash(script.as_bytes()).to_byte_array());
656
657 assert_eq!(got, want);
658 }
659
660 #[test]
661 fn try_from_scriptpubkeybuf_for_scripthash() {
662 let script = ScriptPubKeyBuf::from(vec![0x51; 520]);
663 assert!(ScriptHash::try_from(script).is_ok());
664
665 let script = ScriptPubKeyBuf::from(vec![0x51; 521]);
666 assert!(ScriptHash::try_from(script).is_err());
667 }
668
669 #[test]
670 fn try_from_scriptpubkeybuf_ref_for_scripthash() {
671 let script = ScriptPubKeyBuf::from(vec![0x51; 520]);
672 assert!(ScriptHash::try_from(&script).is_ok());
673
674 let script = ScriptPubKeyBuf::from(vec![0x51; 521]);
675 assert!(ScriptHash::try_from(&script).is_err());
676 }
677
678 #[test]
679 fn try_from_script_for_scripthash() {
680 let script = RedeemScript::from_bytes(&[0x51; 520]);
681 assert!(ScriptHash::try_from(script).is_ok());
682
683 let script = RedeemScript::from_bytes(&[0x51; 521]);
684 assert!(ScriptHash::try_from(script).is_err());
685 }
686
687 #[test]
688 fn try_from_scriptbuf_for_wscript_hash() {
689 let script = WitnessScriptBuf::from(vec![0x51; 10_000]);
690 assert!(WScriptHash::try_from(script).is_ok());
691
692 let script = WitnessScriptBuf::from(vec![0x51; 10_001]);
693 assert!(WScriptHash::try_from(script).is_err());
694 }
695
696 #[test]
697 fn try_from_scriptbuf_ref_for_wscript_hash() {
698 let script = WitnessScriptBuf::from(vec![0x51; 10_000]);
699 assert!(WScriptHash::try_from(&script).is_ok());
700
701 let script = WitnessScriptBuf::from(vec![0x51; 10_001]);
702 assert!(WScriptHash::try_from(&script).is_err());
703 }
704
705 #[test]
706 fn try_from_script_for_wscript_hash() {
707 let script = WitnessScript::from_bytes(&[0x51; 10_000]);
708 assert!(WScriptHash::try_from(script).is_ok());
709
710 let script = WitnessScript::from_bytes(&[0x51; 10_001]);
711 assert!(WScriptHash::try_from(script).is_err());
712 }
713
714 #[test]
715 fn script_display() {
716 let script = Script::from_bytes(&[0x00, 0xa1, 0xb2]);
717 assert_eq!(format!("{}", script), "OP_0 OP_LESSTHANOREQUAL OP_CSV");
718
719 #[cfg(feature = "hex")]
720 {
721 assert_eq!(format!("{:x}", script), "00a1b2");
722 assert_eq!(format!("{:X}", script), "00A1B2");
723 }
724 assert!(!format!("{:?}", script).is_empty());
725 }
726
727 #[test]
728 fn script_display_pushdata() {
729 let script = Script::from_bytes(&[0x4c, 0x02, 0xab, 0xcd]);
731 assert_eq!(format!("{}", script), "OP_PUSHDATA1 abcd");
732
733 let script = Script::from_bytes(&[0x4d, 0x02, 0x00, 0x12, 0x34]);
735 assert_eq!(format!("{}", script), "OP_PUSHDATA2 1234");
736
737 let script = Script::from_bytes(&[0x4e, 0x02, 0x00, 0x00, 0x00, 0x56, 0x78]);
739 assert_eq!(format!("{}", script), "OP_PUSHDATA4 5678");
740 }
741
742 #[test]
743 fn scriptbuf_display() {
744 let script_buf = ScriptBuf::from(vec![0x00, 0xa1, 0xb2]);
745 assert_eq!(format!("{}", script_buf), "OP_0 OP_LESSTHANOREQUAL OP_CSV");
746
747 #[cfg(feature = "hex")]
748 {
749 assert_eq!(format!("{:x}", script_buf), "00a1b2");
750 assert_eq!(format!("{:X}", script_buf), "00A1B2");
751 }
752 assert!(!format!("{:?}", script_buf).is_empty());
753 }
754
755 #[test]
756 fn cow_script_to_scriptbuf() {
757 let script = Script::from_bytes(&[0x51, 0x52, 0x53]);
758 let cow_borrowed: Cow<Script> = Cow::Borrowed(script);
759 let script_buf: ScriptBuf = cow_borrowed.into();
760 assert_eq!(script_buf.as_bytes(), &[0x51, 0x52, 0x53]);
761 }
762
763 #[test]
764 fn cow_scriptbuf_to_script() {
765 let cow_owned: Cow<Script> = Cow::Owned(ScriptBuf::from(vec![0x51, 0x52, 0x53]));
766 let script: &Script = cow_owned.borrow();
767 assert_eq!(script.as_bytes(), &[0x51, 0x52, 0x53]);
768 }
769
770 #[test]
771 fn cow_scriptbuf_to_box_script() {
772 let script_buf = ScriptBuf::from(vec![0x51, 0x52, 0x53]);
773 let cow_owned: Cow<Script> = Cow::Owned(script_buf.clone());
774 let boxed_script: Box<Script> = cow_owned.into();
775 let script_buf2 = boxed_script.into_script_buf();
776 assert_eq!(script_buf2, script_buf);
777 }
778
779 #[test]
780 fn cow_owned_to_scriptbuf() {
781 let script_buf = ScriptBuf::from(vec![0x51, 0x52, 0x53]);
782 let cow_owned: Cow<Script> = Cow::Owned(script_buf.clone());
783 let script_buf_2: ScriptBuf = cow_owned.into();
784 assert_eq!(script_buf_2, script_buf);
785 }
786
787 #[test]
788 fn cow_script_to_box_script() {
789 let script = Script::from_bytes(&[0x51, 0x52, 0x53]);
790 let cow_borrowed: Cow<Script> = Cow::Borrowed(script);
791 let boxed_script: Box<Script> = cow_borrowed.into();
792 assert_eq!(boxed_script.as_bytes(), &[0x51, 0x52, 0x53]);
793
794 let cow_owned: Cow<Script> = Cow::from(script.to_owned());
795 assert_eq!(cow_owned.as_ref().as_bytes(), &[0x51, 0x52, 0x53]);
796
797 let cow_from_script: Cow<Script> = Cow::from(script);
798 assert_eq!(cow_from_script.as_ref().as_bytes(), &[0x51, 0x52, 0x53]);
799 }
800
801 #[test]
802 fn redeem_script_size_error() {
803 let script = RedeemScriptBuf::from(vec![0x51; 521]);
804 let result = ScriptHash::try_from(script);
805
806 let err = result.unwrap_err();
807 assert_eq!(err.invalid_size(), 521);
808
809 let err_msg = format!("{}", err);
810 assert!(err_msg.contains("521"));
811 }
812
813 #[test]
814 fn witness_script_size_error() {
815 let script = WitnessScriptBuf::from(vec![0x51; 10_001]);
816 let result = WScriptHash::try_from(script);
817
818 let err = result.unwrap_err();
819 assert_eq!(err.invalid_size(), 10_001);
820
821 let err_msg = format!("{}", err);
822 assert!(err_msg.contains("10001"));
823 }
824
825 #[test]
826 #[cfg(target_has_atomic = "ptr")]
827 fn script_to_arc() {
828 let script = Script::from_bytes(&[0x51, 0x52, 0x53]);
829 let arc_script: Arc<Script> = Arc::from(script);
830
831 assert_eq!(arc_script.as_bytes(), script.as_bytes());
832 assert_eq!(Arc::strong_count(&arc_script), 1);
833 }
834
835 #[test]
836 fn script_to_rc() {
837 let script = Script::from_bytes(&[0x51, 0x52, 0x53]);
838 let rc_script: Rc<Script> = Rc::from(script);
839
840 assert_eq!(rc_script.as_bytes(), script.as_bytes());
841 assert_eq!(Rc::strong_count(&rc_script), 1);
842 }
843
844 #[test]
845 fn pushdata_end_conditions() {
846 let push_past_end_script = Script::from_bytes(&[0x4c, 0x02]);
847 let formatted_script = format!("{}", push_past_end_script);
848 assert!(formatted_script.contains("<push past end>"));
849
850 let unexpected_end_script = Script::from_bytes(&[0x4c]);
851 let formatted_script = format!("{}", unexpected_end_script);
852 assert!(formatted_script.contains("<unexpected end>"));
853 }
854
855 #[test]
856 fn legacy_opcode() {
857 let script = Script::from_bytes(&[0x03, 0xaa, 0xbb, 0xcc]);
858 assert_eq!(format!("{}", script), "OP_PUSHBYTES_3 aabbcc");
859 }
860
861 #[test]
862 #[cfg(feature = "alloc")]
863 #[cfg(feature = "hex")]
864 fn script_to_hex() {
865 let script = Script::from_bytes(&[0xa1, 0xb2, 0xc3]);
866 let hex = alloc::format!("{script:x}");
867 assert_eq!(hex, "a1b2c3");
868 }
869
870 #[test]
871 #[cfg(feature = "alloc")]
872 #[cfg(feature = "hex")]
873 fn scriptbuf_to_hex() {
874 let script = ScriptBuf::from_bytes(vec![0xa1, 0xb2, 0xc3]);
875 let hex = alloc::format!("{script:x}");
876 assert_eq!(hex, "a1b2c3");
877 }
878}