Skip to main content

tidecoin_primitives/script/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Tidecoin scripts.
4
5mod 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]                // Keep public re-exports separate.
30#[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
48/// A P2SH redeem script.
49pub type RedeemScriptBuf = ScriptBuf<RedeemScriptTag>;
50
51/// A reference to a P2SH redeem script.
52pub type RedeemScript = Script<RedeemScriptTag>;
53
54/// A reference to a `scriptPubKey` (locking script).
55pub type ScriptPubKey = Script<ScriptPubKeyTag>;
56
57/// A reference to a script signature (scriptSig).
58pub type ScriptSig = Script<ScriptSigTag>;
59
60/// A `scriptPubKey` (locking script).
61pub type ScriptPubKeyBuf = ScriptBuf<ScriptPubKeyTag>;
62
63/// A `scriptPubKey` decoder.
64pub type ScriptPubKeyBufDecoder = ScriptBufDecoder<ScriptPubKeyTag>;
65
66/// A script signature (scriptSig).
67pub type ScriptSigBuf = ScriptBuf<ScriptSigTag>;
68
69/// A `scriptSig` decoder.
70pub type ScriptSigBufDecoder = ScriptBufDecoder<ScriptSigTag>;
71
72/// A Segwit v0 witness script.
73pub type WitnessScriptBuf = ScriptBuf<WitnessScriptTag>;
74
75/// A reference to a Segwit v0 witness script.
76pub type WitnessScript = Script<WitnessScriptTag>;
77
78/// Basic script decoding/building errors.
79#[derive(Debug, Clone, PartialEq, Eq)]
80pub enum Error {
81    /// Non-minimal push encoding.
82    NonMinimalPush,
83    /// Script ended while parsing an instruction.
84    EarlyEndOfScript,
85    /// Numeric overflow while parsing or serializing a script integer.
86    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
104/// The maximum allowed redeem script size for a P2SH output.
105pub const MAX_REDEEM_SCRIPT_SIZE: usize = 520;
106/// The maximum allowed redeem script size of the witness script.
107pub const MAX_WITNESS_SCRIPT_SIZE: usize = 10_000;
108/// Standard script-number byte limit used by arithmetic and most script opcodes.
109pub const SCRIPTNUM_STANDARD_MAX_LEN: usize = 4;
110/// Extended script-number byte limit used by lock-time related opcodes.
111pub const SCRIPTNUM_CLTV_MAX_LEN: usize = 5;
112
113/// Either a redeem script or a Segwit version 0 scriptpubkey.
114///
115/// In the case of P2SH-wrapped Segwit version outputs, we take a Segwit scriptPubKey
116/// and put it in a redeem script slot. Tidecoin script validation has special logic to handle this
117/// case, which is reflected in our API in several methods
118/// relating to P2SH and signature hashing. These methods take either a normal
119/// P2SH redeem script, or a Segwit version 0 scriptpubkey.
120///
121/// Higher witness versions do **not** support P2SH-wrapping, and such scriptPubKeys should not be
122/// used with this trait.
123pub 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
188/// Encodes an integer in script number format.
189///
190/// # Panics
191///
192/// Panics if the encoded value exceeds the legacy 8-byte output buffer.
193pub 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
200/// Encodes an integer in script number format into a freshly allocated buffer.
201pub 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
225/// Decodes a script integer without enforcing minimal encoding.
226///
227/// # Errors
228///
229/// Returns [`ScriptIntError::NumericOverflow`] when `v` exceeds the standard 4-byte script bound.
230///
231/// # Panics
232///
233/// Panics only if the internal 4-byte bound invariant is violated.
234pub 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
239/// Decodes a script number with caller-selected minimal-encoding and length rules.
240///
241/// # Errors
242///
243/// Returns [`ScriptIntError::NumericOverflow`] when `v` is longer than `max_len`, and
244/// [`ScriptIntError::NonMinimal`] when `require_minimal` is true and the encoding is non-minimal.
245pub 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
273/// Returns whether a script-number byte slice uses minimal encoding for the provided bound.
274pub 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/// Decodes a script truth value.
296///
297/// This uses script boolean semantics: all zero bytes and negative zero are false; every other
298/// byte string is true. Numeric-overflow rules do not apply.
299#[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
307// We keep all the `Script` and `ScriptBuf` impls together since it's easier to see side-by-side.
308
309impl<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/// Note: This will fail to compile on old Rust for targets that don't support atomics
365#[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        // This has to be a macro because it needs to break the loop
468        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        // Was at least one opcode emitted?
482        let mut at_least_one = false;
483        // `iter` needs to be borrowed in `read_push_data_len`, so we have to use `while let` instead
484        // of `for`.
485        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                        // side effects: may write and break from the loop
494                        read_push_data_len!(&mut iter, PushDataLenLen::One, f)
495                    }
496                    OP_PUSHDATA2 => {
497                        // side effects: may write and break from the loop
498                        read_push_data_len!(&mut iter, PushDataLenLen::Two, f)
499                    }
500                    OP_PUSHDATA4 => {
501                        // side effects: may write and break from the loop
502                        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            // Write the opcode
514            crate::opcodes::fmt_opcode(byte, f)?;
515            // Write any pushdata
516            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    /// User-facing serialization for `Script`.
616    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/// Can only deserialize borrowed bytes.
629#[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    /// User-facing serialization for `Script`.
666    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}