Skip to main content

bitcoin_primitives/script/
owned.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use core::marker::PhantomData;
4use core::ops::{Deref, DerefMut};
5
6#[cfg(feature = "arbitrary")]
7use arbitrary::{Arbitrary, Unstructured};
8use encoding::{ByteVecDecoder, DecoderStatus};
9
10use super::{Script, ScriptBufDecoderError, P2A_PROGRAM};
11use crate::opcodes::all::{OP_1, OP_1NEGATE, OP_EQUAL, OP_HASH160, OP_RETURN};
12use crate::opcodes::{self, Opcode};
13use crate::prelude::{Box, Vec};
14use crate::script::{Builder, PushBytes, ScriptHash, ScriptHashableTag, WScriptHash};
15use crate::witness_version::WitnessVersion;
16use crate::ScriptPubKeyBuf;
17
18/// An owned, growable script.
19///
20/// `ScriptBuf` is the most common script type that has the ownership over the contents of the
21/// script. It has a close relationship with its borrowed counterpart, [`Script`].
22///
23/// Just as other similar types, this implements [`Deref`], so [deref coercions] apply. Also note
24/// that all the safety/validity restrictions that apply to [`Script`] apply to `ScriptBuf` as well.
25///
26/// # Hexadecimal strings
27///
28/// Scripts are consensus encoded with a length prefix and as a result of this in some places in the
29/// ecosystem one will encounter hex strings that include the prefix while in other places the
30/// prefix is excluded. To support parsing and formatting scripts as hex we provide a bunch of
31/// different APIs and trait implementations. Please see [`examples/script.rs`] for a thorough
32/// example of all the APIs.
33///
34/// [`examples/script.rs`]: <https://github.com/rust-bitcoin/rust-bitcoin/blob/master/bitcoin/examples/script.rs>
35/// [deref coercions]: https://doc.rust-lang.org/std/ops/trait.Deref.html#more-on-deref-coercion
36///
37/// # Panics
38///
39/// `ScriptBuf` is backed by [`Vec`] and inherits its panic behavior. This means that attempting to
40/// construct scripts larger than `isize::MAX` bytes will panic.
41#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
42pub struct ScriptBuf<T>(PhantomData<T>, Vec<u8>);
43
44impl<T> ScriptBuf<T> {
45    /// Constructs a new empty script.
46    #[inline]
47    pub const fn new() -> Self { Self::from_bytes(Vec::new()) }
48
49    /// Converts byte vector into script.
50    ///
51    /// This method doesn't (re)allocate. `bytes` is just the script bytes **not** consensus
52    /// encoding (i.e no length prefix).
53    #[inline]
54    pub const fn from_bytes(bytes: Vec<u8>) -> Self { Self(PhantomData, bytes) }
55
56    /// Constructs a new [`ScriptBuf`] from a hex string.
57    ///
58    /// The input string is expected to be consensus encoded i.e., includes the length prefix.
59    ///
60    /// # Errors
61    ///
62    /// * If `s` cannot be parsed into a vector.
63    /// * If the parsed bytes cannot be decoded as a valid script (incl. the length prefix).
64    #[cfg(feature = "hex")]
65    pub fn from_hex_prefixed(
66        s: &str,
67    ) -> Result<Self, encoding::FromHexError<ScriptBufDecoderError>> {
68        encoding::decode_from_hex(s)
69    }
70
71    /// Constructs a new [`ScriptBuf`] from a hex string.
72    ///
73    /// This is **not** consensus encoding. If your hex string is a consensus encoded script
74    /// then use `ScriptBuf::from_hex_prefixed`.
75    ///
76    /// There is no script decoding error path because what ever is in the hex input string is
77    /// assumed to be the script. This means if you pass a consensus encoded hex string into this
78    /// function there will be no error and the script will not be what you expect.
79    ///
80    /// # Errors
81    ///
82    /// Errors if `s` cannot be parsed into a vector.
83    #[cfg(feature = "hex")]
84    pub fn from_hex_no_length_prefix(s: &str) -> Result<Self, hex::DecodeVariableLengthBytesError> {
85        let v = hex::decode_to_vec(s)?;
86        Ok(Self::from_bytes(v))
87    }
88
89    /// Returns a reference to unsized script.
90    #[inline]
91    pub fn as_script(&self) -> &Script<T> { Script::from_bytes(&self.1) }
92
93    /// Returns a mutable reference to unsized script.
94    #[inline]
95    pub fn as_mut_script(&mut self) -> &mut Script<T> { Script::from_bytes_mut(&mut self.1) }
96
97    /// Converts the script into a byte vector.
98    ///
99    /// This method doesn't (re)allocate.
100    ///
101    /// # Returns
102    ///
103    /// Just the script bytes **not** consensus encoding (which includes a length prefix).
104    #[inline]
105    pub fn into_bytes(self) -> Vec<u8> { self.1 }
106
107    /// Converts this `ScriptBuf` into a [boxed](Box) [`Script`].
108    ///
109    /// This method reallocates if the capacity is greater than length of the script but should not
110    /// when they are equal. If you know beforehand that you need to create a script of exact size
111    /// use [`reserve_exact`](Self::reserve_exact) before adding data to the script so that the
112    /// reallocation can be avoided.
113    #[must_use]
114    #[inline]
115    pub fn into_boxed_script(self) -> Box<Script<T>> {
116        Script::from_boxed_bytes(self.into_bytes().into_boxed_slice())
117    }
118
119    /// Constructs a new empty script with at least the specified capacity.
120    #[inline]
121    pub fn with_capacity(capacity: usize) -> Self { Self::from_bytes(Vec::with_capacity(capacity)) }
122
123    /// Pre-allocates at least `additional_len` bytes if needed.
124    ///
125    /// Reserves capacity for at least `additional_len` more bytes to be inserted in the given
126    /// script. The script may reserve more space to speculatively avoid frequent reallocations.
127    /// After calling `reserve`, capacity will be greater than or equal to
128    /// `self.len() + additional_len`. Does nothing if capacity is already sufficient.
129    ///
130    /// # Panics
131    ///
132    /// Panics if the new capacity exceeds `isize::MAX` bytes.
133    #[inline]
134    pub fn reserve(&mut self, additional_len: usize) { self.1.reserve(additional_len); }
135
136    /// Pre-allocates exactly `additional_len` bytes if needed.
137    ///
138    /// Unlike `reserve`, this will not deliberately over-allocate to speculatively avoid frequent
139    /// allocations. After calling `reserve_exact`, capacity will be greater than or equal to
140    /// `self.len() + additional`. Does nothing if the capacity is already sufficient.
141    ///
142    /// Note that the allocator may give the collection more space than it requests. Therefore,
143    /// capacity cannot be relied upon to be precisely minimal. Prefer [`reserve`](Self::reserve)
144    /// if future insertions are expected.
145    ///
146    /// # Panics
147    ///
148    /// Panics if the new capacity exceeds `isize::MAX` bytes.
149    #[inline]
150    pub fn reserve_exact(&mut self, additional_len: usize) { self.1.reserve_exact(additional_len); }
151
152    /// Returns the number of **bytes** available for writing without reallocation.
153    ///
154    /// It is guaranteed that `script.capacity() >= script.len()` always holds.
155    #[inline]
156    pub fn capacity(&self) -> usize { self.1.capacity() }
157
158    /// Gets the hex representation of this script.
159    ///
160    /// # Returns
161    ///
162    /// Just the script bytes in hexadecimal **not** consensus encoding of the script i.e., the
163    /// string will not include a length prefix.
164    #[cfg(feature = "hex")]
165    #[inline]
166    #[deprecated(since = "1.0.0-rc.0", note = "use `format!(\"{var:x}\")` instead")]
167    pub fn to_hex(&self) -> alloc::string::String { alloc::format!("{:x}", self) }
168
169    /// Constructs a new script builder
170    pub fn builder() -> Builder<T> { Builder::new() }
171
172    /// Adds a single opcode to the script.
173    pub fn push_opcode(&mut self, data: Opcode) { self.as_byte_vec().push(data.to_u8()); }
174
175    /// Adds instructions to push some arbitrary data onto the stack.
176    ///
177    /// If the data can be exactly produced by a numeric opcode, that opcode
178    /// will be used, since its behavior is equivalent but will not violate minimality
179    /// rules. To avoid this, use [`ScriptBuf::push_slice_non_minimal`] which will always
180    /// use a push opcode.
181    ///
182    /// However, this method does *not* enforce any numeric minimality rules.
183    /// If your pushes should be interpreted as numbers, ensure your input does
184    /// not have any leading zeros. In particular, the number 0 should be encoded
185    /// as an empty string rather than as a single 0 byte.
186    pub fn push_slice<D: AsRef<PushBytes>>(&mut self, data: D) {
187        let bytes = data.as_ref().as_bytes();
188        if bytes.len() == 1 {
189            match bytes[0] {
190                0x81 => {
191                    self.push_opcode(OP_1NEGATE);
192                }
193                1..=16 => {
194                    self.push_opcode(Opcode::from(bytes[0] + (OP_1.to_u8() - 1)));
195                }
196                _ => {
197                    self.push_slice_non_minimal(data);
198                }
199            }
200        } else {
201            self.push_slice_non_minimal(data);
202        }
203    }
204
205    /// Adds instructions to push some arbitrary data onto the stack without minimality.
206    ///
207    /// Standardness rules require push minimality according to [CheckMinimalPush] of core.
208    ///
209    /// [CheckMinimalPush]: <https://github.com/bitcoin/bitcoin/blob/99a4ddf5ab1b3e514d08b90ad8565827fda7b63b/src/script/script.cpp#L366>
210    pub fn push_slice_non_minimal<D: AsRef<PushBytes>>(&mut self, data: D) {
211        let data = data.as_ref();
212        self.reserve(Self::reserved_len_for_slice(data.len()));
213        self.push_slice_no_opt(data);
214    }
215
216    /// Computes the sum of `len` and the length of an appropriate push opcode.
217    fn reserved_len_for_slice(len: usize) -> usize {
218        len + match len {
219            0..=0x4b => 1,
220            0x4c..=0xff => 2,
221            0x100..=0xffff => 3,
222            // we don't care about oversized, the other fn will panic anyway
223            _ => 5,
224        }
225    }
226
227    /// Pretends to convert `&mut ScriptBuf` to `&mut Vec<u8>` so that it can be modified.
228    ///
229    /// Note: if the returned value leaks the original `ScriptBuf` will become empty.
230    fn as_byte_vec(&mut self) -> ScriptBufAsVec<'_, T> {
231        let vec = core::mem::take(self).into_bytes();
232        ScriptBufAsVec(self, vec)
233    }
234
235    /// Pushes the slice without reserving
236    fn push_slice_no_opt(&mut self, data: &PushBytes) {
237        let mut this = self.as_byte_vec();
238        // Start with a PUSH opcode
239        match data.len() as u64 {
240            n if n < opcodes::OP_PUSHDATA1.into() => {
241                this.push(n as u8);
242            }
243            n if n < 0x100 => {
244                this.push(opcodes::OP_PUSHDATA1);
245                this.push(n as u8);
246            }
247            n if n < 0x10000 => {
248                this.push(opcodes::OP_PUSHDATA2);
249                this.push((n % 0x100) as u8);
250                this.push((n / 0x100) as u8);
251            }
252            // `PushBytes` enforces len < 0x100000000
253            n => {
254                this.push(opcodes::OP_PUSHDATA4);
255                this.push((n % 0x100) as u8);
256                this.push(((n / 0x100) % 0x100) as u8);
257                this.push(((n / 0x10000) % 0x100) as u8);
258                this.push((n / 0x0100_0000) as u8);
259            }
260        }
261        // Then push the raw bytes
262        this.extend_from_slice(data.as_bytes());
263    }
264}
265
266impl ScriptPubKeyBuf {
267    /// Generates OP_RETURN-type of scriptPubkey for the given data.
268    pub fn new_op_return<T: AsRef<PushBytes>>(data: T) -> Self {
269        Builder::new().push_opcode(OP_RETURN).push_slice(data).into_script()
270    }
271
272    /// Generates P2SH-type of scriptPubkey with a given hash of the redeem script.
273    pub fn new_p2sh(script_hash: ScriptHash) -> Self {
274        Builder::new()
275            .push_opcode(OP_HASH160)
276            .push_slice(script_hash)
277            .push_opcode(OP_EQUAL)
278            .into_script()
279    }
280
281    /// Generates pay to anchor output.
282    pub fn new_p2a() -> Self {
283        super::new_witness_program_unchecked(WitnessVersion::V1, P2A_PROGRAM)
284    }
285}
286
287impl<T: ScriptHashableTag> ScriptBuf<T> {
288    /// Generates a P2WSH witness program script with a given hash of the witness script.
289    pub fn new_p2wsh(script_hash: WScriptHash) -> Self {
290        // script hash is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv0)
291        super::new_witness_program_unchecked(WitnessVersion::V0, script_hash)
292    }
293}
294
295// Cannot derive due to generics.
296impl<T> Default for ScriptBuf<T> {
297    fn default() -> Self { Self(PhantomData, Vec::new()) }
298}
299
300impl<T> Deref for ScriptBuf<T> {
301    type Target = Script<T>;
302
303    #[inline]
304    fn deref(&self) -> &Self::Target { self.as_script() }
305}
306
307impl<T> DerefMut for ScriptBuf<T> {
308    #[inline]
309    fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_script() }
310}
311
312impl<T> encoding::Decode for ScriptBuf<T> {
313    type Decoder = ScriptBufDecoder<T>;
314}
315
316/// The decoder for the [`ScriptBuf`] type.
317#[derive(Debug, Clone)]
318pub struct ScriptBufDecoder<T>(ByteVecDecoder, PhantomData<T>);
319
320impl<T> ScriptBufDecoder<T> {
321    /// Constructs a new [`ScriptBuf`] decoder.
322    pub const fn new() -> Self { Self(ByteVecDecoder::new(), PhantomData) }
323}
324
325impl<T> Default for ScriptBufDecoder<T> {
326    fn default() -> Self { Self::new() }
327}
328
329impl<T> encoding::Decoder for ScriptBufDecoder<T> {
330    type Output = ScriptBuf<T>;
331    type Error = ScriptBufDecoderError;
332
333    #[inline]
334    fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<DecoderStatus, Self::Error> {
335        self.0.push_bytes(bytes).map_err(ScriptBufDecoderError)
336    }
337
338    #[inline]
339    fn end(self) -> Result<Self::Output, Self::Error> {
340        Ok(ScriptBuf::from_bytes(self.0.end().map_err(ScriptBufDecoderError)?))
341    }
342
343    #[inline]
344    fn read_limit(&self) -> usize { self.0.read_limit() }
345}
346
347/// Pretends that this is a mutable reference to [`ScriptBuf`]'s internal buffer.
348///
349/// In reality the backing `Vec<u8>` is swapped with an empty one and this is holding both the
350/// reference and the vec. The vec is put back when this drops so it also covers panics. (But not
351/// leaks, which is OK since we never leak.)
352pub(crate) struct ScriptBufAsVec<'a, T>(&'a mut ScriptBuf<T>, Vec<u8>);
353
354impl<T> core::ops::Deref for ScriptBufAsVec<'_, T> {
355    type Target = Vec<u8>;
356
357    fn deref(&self) -> &Self::Target { &self.1 }
358}
359
360impl<T> core::ops::DerefMut for ScriptBufAsVec<'_, T> {
361    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.1 }
362}
363
364impl<T> Drop for ScriptBufAsVec<'_, T> {
365    fn drop(&mut self) {
366        let vec = core::mem::take(&mut self.1);
367        *(self.0) = ScriptBuf::from_bytes(vec);
368    }
369}
370
371#[cfg(feature = "arbitrary")]
372impl<'a, T> Arbitrary<'a> for ScriptBuf<T> {
373    #[inline]
374    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
375        let v = Vec::<u8>::arbitrary(u)?;
376        Ok(Self::from_bytes(v))
377    }
378}
379
380#[cfg(test)]
381mod tests {
382    use alloc::vec;
383
384    use super::ScriptBuf;
385    use crate::script::ScriptSigTag as Tag;
386
387    #[test]
388    fn reserved_len_for_slice() {
389        // Length plus the size of the push opcode that prefixes it.
390        assert_eq!(ScriptBuf::<Tag>::reserved_len_for_slice(0), 1);
391        assert_eq!(ScriptBuf::<Tag>::reserved_len_for_slice(0x4b), 0x4b + 1);
392        assert_eq!(ScriptBuf::<Tag>::reserved_len_for_slice(0x4c), 0x4c + 2);
393        assert_eq!(ScriptBuf::<Tag>::reserved_len_for_slice(0xff), 0xff + 2);
394        assert_eq!(ScriptBuf::<Tag>::reserved_len_for_slice(0x100), 0x100 + 3);
395        assert_eq!(ScriptBuf::<Tag>::reserved_len_for_slice(0xffff), 0xffff + 3);
396        assert_eq!(ScriptBuf::<Tag>::reserved_len_for_slice(0x10000), 0x10000 + 5);
397    }
398
399    #[test]
400    fn as_byte_vec_deref_restores() {
401        let mut script = ScriptBuf::<Tag>::from_bytes(vec![1, 2, 3]);
402        {
403            let vec = script.as_byte_vec();
404            assert_eq!(vec.len(), 3);
405            assert_eq!(vec.as_slice(), &[1, 2, 3]);
406        }
407        assert_eq!(script.as_bytes(), &[1, 2, 3]);
408    }
409}