Skip to main content

tidecoin_primitives/script/
owned.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use core::convert::Infallible;
4use core::fmt;
5use core::marker::PhantomData;
6use core::ops::{Deref, DerefMut};
7
8#[cfg(feature = "arbitrary")]
9use arbitrary::{Arbitrary, Unstructured};
10use encoding::{ByteVecDecoder, ByteVecDecoderError, Encodable};
11use internals::write_err;
12
13use super::{encode_scriptnum, Error, Instruction, Script, ScriptEncoder};
14#[cfg(feature = "hex")]
15use crate::hex;
16use crate::opcodes::all::{
17    OP_1, OP_1NEGATE, OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY, OP_CHECKSIG, OP_CHECKSIGVERIFY,
18    OP_EQUAL, OP_EQUALVERIFY, OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_PUSHBYTES_0, OP_PUSHDATA1,
19    OP_PUSHDATA2, OP_PUSHDATA4, OP_VERIFY,
20};
21use crate::opcodes::Opcode;
22use crate::prelude::{Box, Vec};
23
24/// An owned, growable script.
25///
26/// `ScriptBuf` is the most common script type that has the ownership over the contents of the
27/// script. It has a close relationship with its borrowed counterpart, [`Script`].
28///
29/// Just as other similar types, this implements [`Deref`], so [deref coercions] apply. Also note
30/// that all the safety/validity restrictions that apply to [`Script`] apply to `ScriptBuf` as well.
31///
32/// # Hexadecimal strings
33///
34/// Scripts are consensus encoded with a length prefix and as a result of this in some places in the
35/// ecosystem one will encounter hex strings that include the prefix while in other places the
36/// prefix is excluded. To support parsing and formatting scripts as hex we provide a bunch of
37/// different APIs and trait implementations. Please see [`examples/script.rs`] for a thorough
38/// example of all the APIs.
39///
40/// [deref coercions]: https://doc.rust-lang.org/std/ops/trait.Deref.html#more-on-deref-coercion
41///
42/// # Panics
43///
44/// `ScriptBuf` is backed by [`Vec`] and inherits its panic behavior. This means that attempting to
45/// construct scripts larger than `isize::MAX` bytes will panic.
46#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
47pub struct ScriptBuf<T>(PhantomData<T>, Vec<u8>);
48
49impl<T> ScriptBuf<T> {
50    /// Constructs a new empty script.
51    #[inline]
52    pub const fn new() -> Self {
53        Self::from_bytes(Vec::new())
54    }
55
56    /// Converts byte vector into script.
57    ///
58    /// This method doesn't (re)allocate. `bytes` is just the script bytes **not** consensus
59    /// encoding (i.e no length prefix).
60    #[inline]
61    pub const fn from_bytes(bytes: Vec<u8>) -> Self {
62        Self(PhantomData, bytes)
63    }
64
65    /// Constructs a new [`ScriptBuf`] from a hex string.
66    ///
67    /// The input string is expected to be consensus encoded i.e., includes the length prefix.
68    ///
69    /// # Errors
70    ///
71    /// * If `s` cannot be parsed into a vector.
72    /// * If the parsed bytes cannot be decoded as a valid script (incl.the length prefix).
73    #[cfg(feature = "hex")]
74    pub fn from_hex_prefixed(s: &str) -> Result<Self, FromHexError> {
75        let v = hex::decode_to_vec(s)?;
76        Ok(encoding::decode_from_slice(&v)?)
77    }
78
79    /// Constructs a new [`ScriptBuf`] from a hex string.
80    ///
81    /// This is **not** consensus encoding. If your hex string is a consensus encoded script
82    /// then use `ScriptBuf::from_hex_prefixed`.
83    ///
84    /// There is no script decoding error path because what ever is in the hex input string is
85    /// assumed to be the script. This means if you pass a consensus encoded hex string into this
86    /// function there will be no error and the script will not be what you expect.
87    ///
88    /// # Errors
89    ///
90    /// Errors if `s` cannot be parsed into a vector.
91    #[cfg(feature = "hex")]
92    pub fn from_hex_no_length_prefix(s: &str) -> Result<Self, hex::DecodeVariableLengthBytesError> {
93        let v = hex::decode_to_vec(s)?;
94        Ok(Self::from_bytes(v))
95    }
96
97    /// Returns a reference to unsized script.
98    #[inline]
99    pub fn as_script(&self) -> &Script<T> {
100        Script::from_bytes(&self.1)
101    }
102
103    /// Returns a mutable reference to unsized script.
104    #[inline]
105    pub fn as_mut_script(&mut self) -> &mut Script<T> {
106        Script::from_bytes_mut(&mut self.1)
107    }
108
109    /// Converts the script into a byte vector.
110    ///
111    /// This method doesn't (re)allocate.
112    ///
113    /// # Returns
114    ///
115    /// Just the script bytes **not** consensus encoding (which includes a length prefix).
116    #[inline]
117    pub fn into_bytes(self) -> Vec<u8> {
118        self.1
119    }
120
121    /// Converts this `ScriptBuf` into a [boxed](Box) [`Script`].
122    ///
123    /// This method reallocates if the capacity is greater than length of the script but should not
124    /// when they are equal. If you know beforehand that you need to create a script of exact size
125    /// use [`reserve_exact`](Self::reserve_exact) before adding data to the script so that the
126    /// reallocation can be avoided.
127    #[must_use]
128    #[inline]
129    pub fn into_boxed_script(self) -> Box<Script<T>> {
130        Script::from_boxed_bytes(self.into_bytes().into_boxed_slice())
131    }
132
133    /// Constructs a new empty script with at least the specified capacity.
134    #[inline]
135    pub fn with_capacity(capacity: usize) -> Self {
136        Self::from_bytes(Vec::with_capacity(capacity))
137    }
138
139    /// Pre-allocates at least `additional_len` bytes if needed.
140    ///
141    /// Reserves capacity for at least `additional_len` more bytes to be inserted in the given
142    /// script. The script may reserve more space to speculatively avoid frequent reallocations.
143    /// After calling `reserve`, capacity will be greater than or equal to
144    /// `self.len() + additional_len`. Does nothing if capacity is already sufficient.
145    ///
146    /// # Panics
147    ///
148    /// Panics if the new capacity exceeds `isize::MAX bytes`.
149    #[inline]
150    pub fn reserve(&mut self, additional_len: usize) {
151        self.1.reserve(additional_len);
152    }
153
154    /// Pre-allocates exactly `additional_len` bytes if needed.
155    ///
156    /// Unlike `reserve`, this will not deliberately over-allocate to speculatively avoid frequent
157    /// allocations. After calling `reserve_exact`, capacity will be greater than or equal to
158    /// `self.len() + additional`. Does nothing if the capacity is already sufficient.
159    ///
160    /// Note that the allocator may give the collection more space than it requests. Therefore,
161    /// capacity cannot be relied upon to be precisely minimal. Prefer [`reserve`](Self::reserve)
162    /// if future insertions are expected.
163    ///
164    /// # Panics
165    ///
166    /// Panics if the new capacity exceeds `isize::MAX bytes`.
167    #[inline]
168    pub fn reserve_exact(&mut self, additional_len: usize) {
169        self.1.reserve_exact(additional_len);
170    }
171
172    pub(crate) fn as_byte_vec(&mut self) -> &mut Vec<u8> {
173        &mut self.1
174    }
175
176    /// Returns the number of **bytes** available for writing without reallocation.
177    ///
178    /// It is guaranteed that `script.capacity() >= script.len()` always holds.
179    #[inline]
180    pub fn capacity(&self) -> usize {
181        self.1.capacity()
182    }
183
184    /// Returns the encoded length for pushing a slice of bytes.
185    pub fn reserved_len_for_slice(len: usize) -> usize {
186        len + if len < 0x4c {
187            1
188        } else if len <= 0xff {
189            2
190        } else if len <= 0xffff {
191            3
192        } else {
193            5
194        }
195    }
196
197    /// Adds a single opcode to the script.
198    pub fn push_opcode(&mut self, opcode: Opcode) {
199        self.as_byte_vec().push(opcode.to_u8());
200    }
201
202    /// Adds instructions to push an integer onto the stack.
203    ///
204    /// # Errors
205    ///
206    /// Returns [`Error::NumericOverflow`] when `n` is outside the minimally encodable range.
207    pub fn push_int(&mut self, n: i32) -> Result<(), Error> {
208        if n == i32::MIN {
209            Err(Error::NumericOverflow)
210        } else {
211            self.push_int_unchecked(n.into());
212            Ok(())
213        }
214    }
215
216    /// Adds instructions to push an unchecked integer onto the stack.
217    pub fn push_int_unchecked(&mut self, n: i64) {
218        match n {
219            -1 => self.push_opcode(OP_1NEGATE),
220            0 => self.push_opcode(OP_PUSHBYTES_0),
221            1..=16 => self.push_opcode(Opcode::from(n as u8 + (OP_1.to_u8() - 1))),
222            _ => self.push_int_non_minimal(n),
223        }
224    }
225
226    /// Adds instructions to push an integer without numeric-opcode optimization.
227    ///
228    /// # Panics
229    ///
230    /// Panics only if the internally encoded script integer somehow exceeds the `PushBytes` limit.
231    pub fn push_int_non_minimal(&mut self, data: i64) {
232        let buf = encode_scriptnum(data);
233        let len = buf.len();
234        self.reserve(Self::reserved_len_for_slice(len));
235        self.push_slice_no_opt(
236            <&super::PushBytes>::try_from(buf.as_slice()).expect("scriptint bytes fit PushBytes"),
237        );
238    }
239
240    /// Adds instructions to push some arbitrary data onto the stack.
241    pub fn push_slice<D: AsRef<[u8]>>(&mut self, data: D) {
242        let bytes = data.as_ref();
243        if bytes.len() == 1 {
244            match bytes[0] {
245                0x81 => self.push_opcode(OP_1NEGATE),
246                1..=16 => self.push_opcode(Opcode::from(bytes[0] + (OP_1.to_u8() - 1))),
247                _ => self.push_slice_non_minimal(data),
248            }
249        } else {
250            self.push_slice_non_minimal(data);
251        }
252    }
253
254    /// Adds instructions to push arbitrary data without minimal-push optimization.
255    ///
256    /// # Panics
257    ///
258    /// Panics only if `data` exceeds the maximum size supported by `PushBytes`.
259    pub fn push_slice_non_minimal<D: AsRef<[u8]>>(&mut self, data: D) {
260        let data =
261            <&super::PushBytes>::try_from(data.as_ref()).expect("push data length fits PushBytes");
262        self.reserve(Self::reserved_len_for_slice(data.len()));
263        self.push_slice_no_opt(data);
264    }
265
266    /// Adds a single instruction.
267    pub fn push_instruction(&mut self, instruction: Instruction<'_>) {
268        match instruction {
269            Instruction::Op(opcode) => self.push_opcode(opcode),
270            Instruction::PushBytes(bytes) => self.push_slice(bytes),
271        }
272    }
273
274    /// Adds an `OP_VERIFY` or rewrites the last opcode to its VERIFY form when possible.
275    pub fn scan_and_push_verify(&mut self) {
276        match opcode_to_verify(self.last_opcode()) {
277            Some(opcode) => {
278                self.as_byte_vec().pop();
279                self.push_opcode(opcode);
280            }
281            None => self.push_opcode(OP_VERIFY),
282        }
283    }
284
285    fn push_slice_no_opt(&mut self, data: &super::PushBytes) {
286        let len = data.len();
287        let bytes = self.as_byte_vec();
288        match len {
289            n if n < OP_PUSHDATA1.to_u8() as usize => bytes.push(n as u8),
290            n if n <= 0xff => {
291                bytes.push(OP_PUSHDATA1.to_u8());
292                bytes.push(n as u8);
293            }
294            n if n <= 0xffff => {
295                bytes.push(OP_PUSHDATA2.to_u8());
296                bytes.extend_from_slice(&(n as u16).to_le_bytes());
297            }
298            n => {
299                bytes.push(OP_PUSHDATA4.to_u8());
300                bytes.extend_from_slice(&(n as u32).to_le_bytes());
301            }
302        }
303        bytes.extend_from_slice(data.as_bytes());
304    }
305}
306
307fn opcode_to_verify(opcode: Option<Opcode>) -> Option<Opcode> {
308    opcode.and_then(|opcode| match opcode {
309        OP_EQUAL => Some(OP_EQUALVERIFY),
310        OP_NUMEQUAL => Some(OP_NUMEQUALVERIFY),
311        OP_CHECKSIG => Some(OP_CHECKSIGVERIFY),
312        OP_CHECKMULTISIG => Some(OP_CHECKMULTISIGVERIFY),
313        _ => None,
314    })
315}
316
317// Cannot derive due to generics.
318impl<T> Default for ScriptBuf<T> {
319    fn default() -> Self {
320        Self(PhantomData, Vec::new())
321    }
322}
323
324impl<T> Deref for ScriptBuf<T> {
325    type Target = Script<T>;
326
327    #[inline]
328    fn deref(&self) -> &Self::Target {
329        self.as_script()
330    }
331}
332
333impl<T> DerefMut for ScriptBuf<T> {
334    #[inline]
335    fn deref_mut(&mut self) -> &mut Self::Target {
336        self.as_mut_script()
337    }
338}
339
340impl<T> Encodable for ScriptBuf<T> {
341    type Encoder<'e>
342        = ScriptEncoder<'e>
343    where
344        Self: 'e;
345
346    #[inline]
347    fn encoder(&self) -> Self::Encoder<'_> {
348        self.as_script().encoder()
349    }
350}
351
352/// The decoder for the [`ScriptBuf`] type.
353pub struct ScriptBufDecoder<T>(ByteVecDecoder, PhantomData<T>);
354
355impl<T> ScriptBufDecoder<T> {
356    /// Constructs a new [`ScriptBuf`] decoder.
357    pub const fn new() -> Self {
358        Self(ByteVecDecoder::new(), PhantomData)
359    }
360}
361
362impl<T> Default for ScriptBufDecoder<T> {
363    fn default() -> Self {
364        Self::new()
365    }
366}
367
368impl<T> encoding::Decoder for ScriptBufDecoder<T> {
369    type Output = ScriptBuf<T>;
370    type Error = ScriptBufDecoderError;
371
372    #[inline]
373    fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
374        self.0.push_bytes(bytes).map_err(ScriptBufDecoderError)
375    }
376
377    #[inline]
378    fn end(self) -> Result<Self::Output, Self::Error> {
379        Ok(ScriptBuf::from_bytes(self.0.end().map_err(ScriptBufDecoderError)?))
380    }
381
382    #[inline]
383    fn read_limit(&self) -> usize {
384        self.0.read_limit()
385    }
386}
387
388impl<T> encoding::Decodable for ScriptBuf<T> {
389    type Decoder = ScriptBufDecoder<T>;
390    fn decoder() -> Self::Decoder {
391        ScriptBufDecoder(ByteVecDecoder::new(), PhantomData)
392    }
393}
394
395/// An error consensus decoding a `ScriptBuf<T>`.
396#[derive(Debug, Clone, PartialEq, Eq)]
397pub struct ScriptBufDecoderError(ByteVecDecoderError);
398
399impl From<Infallible> for ScriptBufDecoderError {
400    fn from(never: Infallible) -> Self {
401        match never {}
402    }
403}
404
405impl fmt::Display for ScriptBufDecoderError {
406    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407        write_err!(f, "decoder error"; self.0)
408    }
409}
410
411#[cfg(feature = "std")]
412impl std::error::Error for ScriptBufDecoderError {
413    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
414        Some(&self.0)
415    }
416}
417
418/// An error parsing a script from hex.
419#[derive(Debug, Clone, PartialEq, Eq)]
420#[non_exhaustive]
421#[cfg(feature = "hex")]
422pub enum FromHexError {
423    /// Error parsing the hex input string.
424    Hex(hex::DecodeVariableLengthBytesError),
425    /// Error when decoding the script.
426    Decoder(encoding::DecodeError<ScriptBufDecoderError>),
427}
428
429#[cfg(feature = "hex")]
430impl From<Infallible> for FromHexError {
431    fn from(never: Infallible) -> Self {
432        match never {}
433    }
434}
435
436#[cfg(feature = "hex")]
437impl fmt::Display for FromHexError {
438    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
439        match *self {
440            Self::Hex(ref e) => write_err!(f, "script hex"; e),
441            Self::Decoder(ref e) => write_err!(f, "script decoder"; e),
442        }
443    }
444}
445
446#[cfg(all(feature = "std", feature = "hex"))]
447impl std::error::Error for FromHexError {
448    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
449        match *self {
450            Self::Hex(ref e) => Some(e),
451            Self::Decoder(ref e) => Some(e),
452        }
453    }
454}
455
456#[cfg(feature = "hex")]
457impl From<hex::DecodeVariableLengthBytesError> for FromHexError {
458    fn from(e: hex::DecodeVariableLengthBytesError) -> Self {
459        Self::Hex(e)
460    }
461}
462
463#[cfg(feature = "hex")]
464impl From<encoding::DecodeError<ScriptBufDecoderError>> for FromHexError {
465    fn from(e: encoding::DecodeError<ScriptBufDecoderError>) -> Self {
466        Self::Decoder(e)
467    }
468}
469
470#[cfg(feature = "arbitrary")]
471impl<'a, T> Arbitrary<'a> for ScriptBuf<T> {
472    #[inline]
473    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
474        let v = Vec::<u8>::arbitrary(u)?;
475        Ok(Self::from_bytes(v))
476    }
477}
478
479impl<'a, Tg> core::iter::FromIterator<Instruction<'a>> for ScriptBuf<Tg> {
480    fn from_iter<T>(iter: T) -> Self
481    where
482        T: IntoIterator<Item = Instruction<'a>>,
483    {
484        let mut script = Self::new();
485        script.extend(iter);
486        script
487    }
488}
489
490impl<'a, Tg> Extend<Instruction<'a>> for ScriptBuf<Tg> {
491    fn extend<T>(&mut self, iter: T)
492    where
493        T: IntoIterator<Item = Instruction<'a>>,
494    {
495        let iter = iter.into_iter();
496        if iter.size_hint().1.is_some_and(|max| max < 6) {
497            let mut iter = iter.fuse();
498            let mut head = [None; 5];
499            let mut total_size = 0;
500            for (head, instr) in head.iter_mut().zip(&mut iter) {
501                total_size += instr.script_serialized_len();
502                *head = Some(instr);
503            }
504            assert!(
505                iter.next().is_none(),
506                "Buggy implementation of `Iterator` on {} returns invalid upper bound",
507                core::any::type_name::<T::IntoIter>()
508            );
509            self.reserve(total_size);
510            for instr in head.iter().copied().flatten() {
511                match instr {
512                    Instruction::Op(opcode) => self.push_opcode(opcode),
513                    Instruction::PushBytes(bytes) => self.push_slice_no_opt(bytes),
514                }
515            }
516        } else {
517            for instr in iter {
518                self.push_instruction(instr);
519            }
520        }
521    }
522}