tidecoin_primitives/script/
mod.rs1mod borrowed;
6mod builder;
7mod instruction;
8mod owned;
9mod push_bytes;
10mod tag;
11#[cfg(test)]
12mod tests;
13mod witness_program;
14
15use core::cmp::Ordering;
16use core::fmt;
17#[cfg(feature = "serde")]
18use core::marker::PhantomData;
19
20#[cfg(feature = "hex")]
21use internals::hex::DisplayHex;
22use internals::script::{self, PushDataLenLen};
23
24use crate::prelude::rc::Rc;
25#[cfg(target_has_atomic = "ptr")]
26use crate::prelude::sync::Arc;
27use crate::prelude::{Borrow, BorrowMut, Box, Cow, ToOwned, Vec};
28
29#[rustfmt::skip] #[doc(inline)]
31pub use self::{
32 builder::Builder,
33 borrowed::{Script, ScriptEncoder},
34 instruction::{Instruction, InstructionIndices, Instructions},
35 owned::{ScriptBuf, ScriptBufDecoder, ScriptBufDecoderError},
36 push_bytes::{PushBytes, PushBytesBuf, PushBytesError, ScriptIntError},
37 tag::{Tag, RedeemScriptTag, ScriptPubKeyTag, ScriptSigTag, WitnessScriptTag},
38 witness_program::{
39 validate_witness_program, ParsedWitnessProgram, WitnessProgramClass, WitnessProgramError,
40 P2A_PROGRAM, WITNESS_PROGRAM_MAX_SIZE, WITNESS_PROGRAM_MIN_SIZE,
41 },
42};
43#[doc(inline)]
44pub use crate::hash_types::{
45 RedeemScriptSizeError, ScriptHash, WScriptHash, WitnessScriptSizeError,
46};
47
48pub type RedeemScriptBuf = ScriptBuf<RedeemScriptTag>;
50
51pub type RedeemScript = Script<RedeemScriptTag>;
53
54pub type ScriptPubKey = Script<ScriptPubKeyTag>;
56
57pub type ScriptSig = Script<ScriptSigTag>;
59
60pub type ScriptPubKeyBuf = ScriptBuf<ScriptPubKeyTag>;
62
63pub type ScriptPubKeyBufDecoder = ScriptBufDecoder<ScriptPubKeyTag>;
65
66pub type ScriptSigBuf = ScriptBuf<ScriptSigTag>;
68
69pub type ScriptSigBufDecoder = ScriptBufDecoder<ScriptSigTag>;
71
72pub type WitnessScriptBuf = ScriptBuf<WitnessScriptTag>;
74
75pub type WitnessScript = Script<WitnessScriptTag>;
77
78#[derive(Debug, Clone, PartialEq, Eq)]
80pub enum Error {
81 NonMinimalPush,
83 EarlyEndOfScript,
85 NumericOverflow,
87}
88
89impl fmt::Display for Error {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 match self {
92 Self::NonMinimalPush => f.write_str("non-minimal datapush"),
93 Self::EarlyEndOfScript => f.write_str("unexpected end of script"),
94 Self::NumericOverflow => {
95 f.write_str("numeric overflow (number on stack larger than 4 bytes)")
96 }
97 }
98 }
99}
100
101#[cfg(feature = "std")]
102impl std::error::Error for Error {}
103
104pub const MAX_REDEEM_SCRIPT_SIZE: usize = 520;
106pub const MAX_WITNESS_SCRIPT_SIZE: usize = 10_000;
108pub const SCRIPTNUM_STANDARD_MAX_LEN: usize = 4;
110pub const SCRIPTNUM_CLTV_MAX_LEN: usize = 5;
112
113pub trait ScriptHashableTag: sealed::Sealed {}
124
125impl ScriptHashableTag for RedeemScriptTag {}
126impl ScriptHashableTag for ScriptPubKeyTag {}
127
128mod sealed {
129 pub trait Sealed {}
130 impl Sealed for super::RedeemScriptTag {}
131 impl Sealed for super::ScriptPubKeyTag {}
132}
133
134impl<T: ScriptHashableTag> TryFrom<ScriptBuf<T>> for ScriptHash {
135 type Error = RedeemScriptSizeError;
136
137 #[inline]
138 fn try_from(redeem_script: ScriptBuf<T>) -> Result<Self, Self::Error> {
139 Self::from_script(&redeem_script)
140 }
141}
142
143impl<T: ScriptHashableTag> TryFrom<&ScriptBuf<T>> for ScriptHash {
144 type Error = RedeemScriptSizeError;
145
146 #[inline]
147 fn try_from(redeem_script: &ScriptBuf<T>) -> Result<Self, Self::Error> {
148 Self::from_script(redeem_script)
149 }
150}
151
152impl<T: ScriptHashableTag> TryFrom<&Script<T>> for ScriptHash {
153 type Error = RedeemScriptSizeError;
154
155 #[inline]
156 fn try_from(redeem_script: &Script<T>) -> Result<Self, Self::Error> {
157 Self::from_script(redeem_script)
158 }
159}
160
161impl TryFrom<WitnessScriptBuf> for WScriptHash {
162 type Error = WitnessScriptSizeError;
163
164 #[inline]
165 fn try_from(witness_script: WitnessScriptBuf) -> Result<Self, Self::Error> {
166 Self::from_script(&witness_script)
167 }
168}
169
170impl TryFrom<&WitnessScriptBuf> for WScriptHash {
171 type Error = WitnessScriptSizeError;
172
173 #[inline]
174 fn try_from(witness_script: &WitnessScriptBuf) -> Result<Self, Self::Error> {
175 Self::from_script(witness_script)
176 }
177}
178
179impl TryFrom<&WitnessScript> for WScriptHash {
180 type Error = WitnessScriptSizeError;
181
182 #[inline]
183 fn try_from(witness_script: &WitnessScript) -> Result<Self, Self::Error> {
184 Self::from_script(witness_script)
185 }
186}
187
188pub fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize {
194 let encoded = encode_scriptnum(n);
195 assert!(encoded.len() <= out.len(), "encoded script integer exceeds output buffer");
196 out[..encoded.len()].copy_from_slice(&encoded);
197 encoded.len()
198}
199
200pub fn encode_scriptnum(n: i64) -> Vec<u8> {
202 if n == 0 {
203 return Vec::new();
204 }
205
206 let mut encoded = Vec::new();
207 let neg = n < 0;
208 let mut abs = n.unsigned_abs();
209 while abs > 0 {
210 encoded.push((abs & 0xff) as u8);
211 abs >>= 8;
212 }
213
214 if let Some(last) = encoded.last_mut() {
215 if *last & 0x80 != 0 {
216 encoded.push(if neg { 0x80 } else { 0 });
217 } else if neg {
218 *last |= 0x80;
219 }
220 }
221
222 encoded
223}
224
225pub fn read_scriptint_non_minimal(v: &[u8]) -> Result<i32, ScriptIntError> {
235 let ret = read_scriptnum(v, false, SCRIPTNUM_STANDARD_MAX_LEN)?;
236 Ok(i32::try_from(ret).expect("4 bytes or less fits in i32"))
237}
238
239pub fn read_scriptnum(
246 v: &[u8],
247 require_minimal: bool,
248 max_len: usize,
249) -> Result<i64, ScriptIntError> {
250 if v.is_empty() {
251 return Ok(0);
252 }
253 if v.len() > max_len {
254 return Err(ScriptIntError::NumericOverflow);
255 }
256 if require_minimal && !is_minimally_encoded_scriptnum(v, max_len) {
257 return Err(ScriptIntError::NonMinimal);
258 }
259
260 let mut ret = 0i64;
261 let mut sh = 0;
262 for byte in v {
263 ret += i64::from(*byte) << sh;
264 sh += 8;
265 }
266 if v[v.len() - 1] & 0x80 != 0 {
267 ret &= (1 << (sh - 1)) - 1;
268 ret = -ret;
269 }
270 Ok(ret)
271}
272
273pub fn is_minimally_encoded_scriptnum(v: &[u8], max_len: usize) -> bool {
275 if v.len() > max_len {
276 return false;
277 }
278 if v.is_empty() {
279 return true;
280 }
281
282 let last = v[v.len() - 1];
283 if last.trailing_zeros() >= 7 {
284 if v.len() == 1 {
285 return false;
286 }
287 if v[v.len() - 2] & 0x80 == 0 {
288 return false;
289 }
290 }
291
292 true
293}
294
295#[inline]
300pub fn read_scriptbool(v: &[u8]) -> bool {
301 match v.split_last() {
302 Some((last, rest)) => !((last & !0x80 == 0x00) && rest.iter().all(|&b| b == 0)),
303 None => false,
304 }
305}
306
307impl<T> From<ScriptBuf<T>> for Box<Script<T>> {
310 #[inline]
311 fn from(v: ScriptBuf<T>) -> Self {
312 v.into_boxed_script()
313 }
314}
315
316impl<T> From<ScriptBuf<T>> for Cow<'_, Script<T>> {
317 #[inline]
318 fn from(value: ScriptBuf<T>) -> Self {
319 Cow::Owned(value)
320 }
321}
322
323impl<'a, T> From<Cow<'a, Script<T>>> for ScriptBuf<T> {
324 #[inline]
325 fn from(value: Cow<'a, Script<T>>) -> Self {
326 match value {
327 Cow::Owned(owned) => owned,
328 Cow::Borrowed(borrowed) => borrowed.into(),
329 }
330 }
331}
332
333impl<'a, T> From<Cow<'a, Script<T>>> for Box<Script<T>> {
334 #[inline]
335 fn from(value: Cow<'a, Script<T>>) -> Self {
336 match value {
337 Cow::Owned(owned) => owned.into(),
338 Cow::Borrowed(borrowed) => borrowed.into(),
339 }
340 }
341}
342
343impl<'a, T> From<&'a Script<T>> for Box<Script<T>> {
344 #[inline]
345 fn from(value: &'a Script<T>) -> Self {
346 value.to_owned().into()
347 }
348}
349
350impl<'a, T> From<&'a Script<T>> for ScriptBuf<T> {
351 #[inline]
352 fn from(value: &'a Script<T>) -> Self {
353 value.to_owned()
354 }
355}
356
357impl<'a, T> From<&'a Script<T>> for Cow<'a, Script<T>> {
358 #[inline]
359 fn from(value: &'a Script<T>) -> Self {
360 Cow::Borrowed(value)
361 }
362}
363
364#[cfg(target_has_atomic = "ptr")]
366impl<'a, T> From<&'a Script<T>> for Arc<Script<T>> {
367 #[inline]
368 fn from(value: &'a Script<T>) -> Self {
369 Script::from_arc_bytes(Arc::from(value.as_bytes()))
370 }
371}
372
373impl<'a, T> From<&'a Script<T>> for Rc<Script<T>> {
374 #[inline]
375 fn from(value: &'a Script<T>) -> Self {
376 Script::from_rc_bytes(Rc::from(value.as_bytes()))
377 }
378}
379
380impl<T> From<Vec<u8>> for ScriptBuf<T> {
381 #[inline]
382 fn from(v: Vec<u8>) -> Self {
383 Self::from_bytes(v)
384 }
385}
386
387impl<T> From<ScriptBuf<T>> for Vec<u8> {
388 #[inline]
389 fn from(v: ScriptBuf<T>) -> Self {
390 v.into_bytes()
391 }
392}
393
394impl<T> AsRef<Self> for Script<T> {
395 #[inline]
396 fn as_ref(&self) -> &Self {
397 self
398 }
399}
400
401impl<T> AsRef<Script<T>> for ScriptBuf<T> {
402 #[inline]
403 fn as_ref(&self) -> &Script<T> {
404 self
405 }
406}
407
408impl<T> AsRef<[u8]> for Script<T> {
409 #[inline]
410 fn as_ref(&self) -> &[u8] {
411 self.as_bytes()
412 }
413}
414
415impl<T> AsRef<[u8]> for ScriptBuf<T> {
416 #[inline]
417 fn as_ref(&self) -> &[u8] {
418 self.as_bytes()
419 }
420}
421
422impl<T> AsMut<Self> for Script<T> {
423 #[inline]
424 fn as_mut(&mut self) -> &mut Self {
425 self
426 }
427}
428
429impl<T> AsMut<Script<T>> for ScriptBuf<T> {
430 #[inline]
431 fn as_mut(&mut self) -> &mut Script<T> {
432 self
433 }
434}
435
436impl<T> AsMut<[u8]> for Script<T> {
437 #[inline]
438 fn as_mut(&mut self) -> &mut [u8] {
439 self.as_mut_bytes()
440 }
441}
442
443impl<T> AsMut<[u8]> for ScriptBuf<T> {
444 #[inline]
445 fn as_mut(&mut self) -> &mut [u8] {
446 self.as_mut_bytes()
447 }
448}
449
450impl<T> fmt::Debug for Script<T> {
451 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
452 f.write_str("Script(")?;
453 fmt::Display::fmt(self, f)?;
454 f.write_str(")")
455 }
456}
457
458impl<T> fmt::Debug for ScriptBuf<T> {
459 #[inline]
460 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
461 fmt::Debug::fmt(self.as_script(), f)
462 }
463}
464
465impl<T> fmt::Display for Script<T> {
466 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
467 macro_rules! read_push_data_len {
469 ($iter:expr, $size:path, $formatter:expr) => {
470 match script::read_push_data_len($iter, $size) {
471 Ok(n) => n,
472 Err(_) => {
473 $formatter.write_str("<unexpected end>")?;
474 break;
475 }
476 }
477 };
478 }
479
480 let mut iter = self.as_bytes().iter();
481 let mut at_least_one = false;
483 while let Some(byte) = iter.next().copied() {
486 use crate::opcodes::{OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4};
487
488 let data_len = if byte <= 75 {
489 usize::from(byte)
490 } else {
491 match byte {
492 OP_PUSHDATA1 => {
493 read_push_data_len!(&mut iter, PushDataLenLen::One, f)
495 }
496 OP_PUSHDATA2 => {
497 read_push_data_len!(&mut iter, PushDataLenLen::Two, f)
499 }
500 OP_PUSHDATA4 => {
501 read_push_data_len!(&mut iter, PushDataLenLen::Four, f)
503 }
504 _ => 0,
505 }
506 };
507
508 if at_least_one {
509 f.write_str(" ")?;
510 } else {
511 at_least_one = true;
512 }
513 crate::opcodes::fmt_opcode(byte, f)?;
515 if data_len > 0 {
517 f.write_str(" ")?;
518 if data_len <= iter.len() {
519 for ch in iter.by_ref().take(data_len) {
520 write!(f, "{:02x}", ch)?;
521 }
522 } else {
523 f.write_str("<push past end>")?;
524 break;
525 }
526 }
527 }
528 Ok(())
529 }
530}
531
532impl<T> fmt::Display for ScriptBuf<T> {
533 #[inline]
534 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
535 fmt::Display::fmt(self.as_script(), f)
536 }
537}
538
539#[cfg(feature = "hex")]
540impl<T> fmt::LowerHex for Script<T> {
541 #[inline]
542 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
543 fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
544 }
545}
546
547#[cfg(feature = "hex")]
548impl<T> fmt::LowerHex for ScriptBuf<T> {
549 #[inline]
550 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
551 fmt::LowerHex::fmt(self.as_script(), f)
552 }
553}
554
555#[cfg(feature = "hex")]
556impl<T> fmt::UpperHex for Script<T> {
557 #[inline]
558 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
559 fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
560 }
561}
562
563#[cfg(feature = "hex")]
564impl<T> fmt::UpperHex for ScriptBuf<T> {
565 #[inline]
566 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
567 fmt::UpperHex::fmt(self.as_script(), f)
568 }
569}
570
571impl<T> Borrow<Script<T>> for ScriptBuf<T> {
572 #[inline]
573 fn borrow(&self) -> &Script<T> {
574 self
575 }
576}
577
578impl<T> BorrowMut<Script<T>> for ScriptBuf<T> {
579 #[inline]
580 fn borrow_mut(&mut self) -> &mut Script<T> {
581 self
582 }
583}
584
585impl<T: PartialEq> PartialEq<ScriptBuf<T>> for Script<T> {
586 #[inline]
587 fn eq(&self, other: &ScriptBuf<T>) -> bool {
588 self.eq(other.as_script())
589 }
590}
591
592impl<T: PartialEq> PartialEq<Script<T>> for ScriptBuf<T> {
593 #[inline]
594 fn eq(&self, other: &Script<T>) -> bool {
595 self.as_script().eq(other)
596 }
597}
598
599impl<T: PartialOrd> PartialOrd<Script<T>> for ScriptBuf<T> {
600 #[inline]
601 fn partial_cmp(&self, other: &Script<T>) -> Option<Ordering> {
602 self.as_script().partial_cmp(other)
603 }
604}
605
606impl<T: PartialOrd> PartialOrd<ScriptBuf<T>> for Script<T> {
607 #[inline]
608 fn partial_cmp(&self, other: &ScriptBuf<T>) -> Option<Ordering> {
609 self.partial_cmp(other.as_script())
610 }
611}
612
613#[cfg(feature = "serde")]
614impl<T> serde::Serialize for Script<T> {
615 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
617 where
618 S: serde::Serializer,
619 {
620 if serializer.is_human_readable() {
621 serializer.collect_str(&format_args!("{:x}", self))
622 } else {
623 serializer.serialize_bytes(self.as_bytes())
624 }
625 }
626}
627
628#[cfg(feature = "serde")]
630impl<'de, T> serde::Deserialize<'de> for &'de Script<T> {
631 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
632 where
633 D: serde::Deserializer<'de>,
634 {
635 struct Visitor<T>(PhantomData<T>);
636 impl<'de, T: 'de> serde::de::Visitor<'de> for Visitor<T> {
637 type Value = &'de Script<T>;
638
639 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
640 formatter.write_str("borrowed bytes")
641 }
642
643 fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
644 where
645 E: serde::de::Error,
646 {
647 Ok(Script::from_bytes(v))
648 }
649 }
650
651 if deserializer.is_human_readable() {
652 use crate::serde::de::Error;
653
654 return Err(D::Error::custom(
655 "deserialization of `&Script` from human-readable formats is not possible",
656 ));
657 }
658
659 deserializer.deserialize_bytes(Visitor(PhantomData))
660 }
661}
662
663#[cfg(feature = "serde")]
664impl<T> serde::Serialize for ScriptBuf<T> {
665 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
667 where
668 S: serde::Serializer,
669 {
670 (**self).serialize(serializer)
671 }
672}
673
674#[cfg(feature = "serde")]
675impl<'de, T> serde::Deserialize<'de> for ScriptBuf<T> {
676 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
677 where
678 D: serde::Deserializer<'de>,
679 {
680 use core::fmt::Formatter;
681
682 if deserializer.is_human_readable() {
683 struct Visitor<T>(PhantomData<T>);
684 impl<T> serde::de::Visitor<'_> for Visitor<T> {
685 type Value = ScriptBuf<T>;
686
687 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
688 formatter.write_str("a script hex")
689 }
690
691 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
692 where
693 E: serde::de::Error,
694 {
695 let v = hex::decode_to_vec(v).map_err(E::custom)?;
696 Ok(ScriptBuf::from(v))
697 }
698 }
699 deserializer.deserialize_str(Visitor(PhantomData))
700 } else {
701 struct BytesVisitor<T>(PhantomData<T>);
702
703 impl<T> serde::de::Visitor<'_> for BytesVisitor<T> {
704 type Value = ScriptBuf<T>;
705
706 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
707 formatter.write_str("a script Vec<u8>")
708 }
709
710 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
711 where
712 E: serde::de::Error,
713 {
714 Ok(ScriptBuf::from(v.to_vec()))
715 }
716
717 fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
718 where
719 E: serde::de::Error,
720 {
721 Ok(ScriptBuf::from(v))
722 }
723 }
724 deserializer.deserialize_byte_buf(BytesVisitor(PhantomData))
725 }
726 }
727}