Skip to main content

bitcoin_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, Decodable, Decoder};
11use internals::write_err;
12
13use super::Script;
14use crate::prelude::{Box, Vec};
15
16/// An owned, growable script.
17///
18/// `ScriptBuf` is the most common script type that has the ownership over the contents of the
19/// script. It has a close relationship with its borrowed counterpart, [`Script`].
20///
21/// Just as other similar types, this implements [`Deref`], so [deref coercions] apply. Also note
22/// that all the safety/validity restrictions that apply to [`Script`] apply to `ScriptBuf` as well.
23///
24/// # Hexadecimal strings
25///
26/// Scripts are consensus encoded with a length prefix and as a result of this in some places in the
27/// ecosystem one will encounter hex strings that include the prefix while in other places the
28/// prefix is excluded. To support parsing and formatting scripts as hex we provide a bunch of
29/// different APIs and trait implementations. Please see [`examples/script.rs`] for a thorough
30/// example of all the APIs.
31///
32/// [`examples/script.rs`]: <https://github.com/rust-bitcoin/rust-bitcoin/blob/master/bitcoin/examples/script.rs>
33/// [deref coercions]: https://doc.rust-lang.org/std/ops/trait.Deref.html#more-on-deref-coercion
34///
35/// # Panics
36///
37/// `ScriptBuf` is backed by [`Vec`] and inherits its panic behavior. This means that attempting to
38/// construct scripts larger than `isize::MAX` bytes will panic.
39#[derive(Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
40pub struct ScriptBuf<T>(PhantomData<T>, Vec<u8>);
41
42impl<T> ScriptBuf<T> {
43    /// Constructs a new empty script.
44    #[inline]
45    pub const fn new() -> Self { Self::from_bytes(Vec::new()) }
46
47    /// Converts byte vector into script.
48    ///
49    /// This method doesn't (re)allocate. `bytes` is just the script bytes **not** consensus
50    /// encoding (i.e no length prefix).
51    #[inline]
52    pub const fn from_bytes(bytes: Vec<u8>) -> Self { Self(PhantomData, bytes) }
53
54    /// Returns a reference to unsized script.
55    #[inline]
56    pub fn as_script(&self) -> &Script<T> { Script::from_bytes(&self.1) }
57
58    /// Returns a mutable reference to unsized script.
59    #[inline]
60    pub fn as_mut_script(&mut self) -> &mut Script<T> { Script::from_bytes_mut(&mut self.1) }
61
62    /// Converts the script into a byte vector.
63    ///
64    /// This method doesn't (re)allocate.
65    ///
66    /// # Returns
67    ///
68    /// Just the script bytes **not** consensus encoding (which includes a length prefix).
69    #[inline]
70    pub fn into_bytes(self) -> Vec<u8> { self.1 }
71
72    /// Converts this `ScriptBuf` into a [boxed](Box) [`Script`].
73    ///
74    /// This method reallocates if the capacity is greater than length of the script but should not
75    /// when they are equal. If you know beforehand that you need to create a script of exact size
76    /// use [`reserve_exact`](Self::reserve_exact) before adding data to the script so that the
77    /// reallocation can be avoided.
78    #[must_use]
79    #[inline]
80    pub fn into_boxed_script(self) -> Box<Script<T>> {
81        Script::from_boxed_bytes(self.into_bytes().into_boxed_slice())
82    }
83
84    /// Constructs a new empty script with at least the specified capacity.
85    #[inline]
86    pub fn with_capacity(capacity: usize) -> Self { Self::from_bytes(Vec::with_capacity(capacity)) }
87
88    /// Pre-allocates at least `additional_len` bytes if needed.
89    ///
90    /// Reserves capacity for at least `additional_len` more bytes to be inserted in the given
91    /// script. The script may reserve more space to speculatively avoid frequent reallocations.
92    /// After calling `reserve`, capacity will be greater than or equal to
93    /// `self.len() + additional_len`. Does nothing if capacity is already sufficient.
94    ///
95    /// # Panics
96    ///
97    /// Panics if the new capacity exceeds `isize::MAX bytes`.
98    #[inline]
99    pub fn reserve(&mut self, additional_len: usize) { self.1.reserve(additional_len); }
100
101    /// Pre-allocates exactly `additional_len` bytes if needed.
102    ///
103    /// Unlike `reserve`, this will not deliberately over-allocate to speculatively avoid frequent
104    /// allocations. After calling `reserve_exact`, capacity will be greater than or equal to
105    /// `self.len() + additional`. Does nothing if the capacity is already sufficient.
106    ///
107    /// Note that the allocator may give the collection more space than it requests. Therefore,
108    /// capacity cannot be relied upon to be precisely minimal. Prefer [`reserve`](Self::reserve)
109    /// if future insertions are expected.
110    ///
111    /// # Panics
112    ///
113    /// Panics if the new capacity exceeds `isize::MAX bytes`.
114    #[inline]
115    pub fn reserve_exact(&mut self, additional_len: usize) { self.1.reserve_exact(additional_len); }
116
117    /// Returns the number of **bytes** available for writing without reallocation.
118    ///
119    /// It is guaranteed that `script.capacity() >= script.len()` always holds.
120    #[inline]
121    pub fn capacity(&self) -> usize { self.1.capacity() }
122
123    /// Gets the hex representation of this script.
124    ///
125    /// # Returns
126    ///
127    /// Just the script bytes in hexadecimal **not** consensus encoding of the script i.e., the
128    /// string will not include a length prefix.
129    #[cfg(feature = "alloc")]
130    #[cfg(feature = "hex")]
131    #[inline]
132    #[deprecated(since = "1.0.0-rc.0", note = "use `format!(\"{var:x}\")` instead")]
133    pub fn to_hex(&self) -> alloc::string::String { alloc::format!("{:x}", self) }
134}
135
136// Cannot derive due to generics.
137impl<T> Default for ScriptBuf<T> {
138    fn default() -> Self { Self(PhantomData, Vec::new()) }
139}
140
141impl<T> Deref for ScriptBuf<T> {
142    type Target = Script<T>;
143
144    #[inline]
145    fn deref(&self) -> &Self::Target { self.as_script() }
146}
147
148impl<T> DerefMut for ScriptBuf<T> {
149    #[inline]
150    fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_script() }
151}
152
153/// The decoder for the [`ScriptBuf`] type.
154pub struct ScriptBufDecoder<T>(ByteVecDecoder, PhantomData<T>);
155
156impl<T> ScriptBufDecoder<T> {
157    /// Constructs a new [`ScriptBuf`] decoder.
158    pub const fn new() -> Self { Self(ByteVecDecoder::new(), PhantomData) }
159}
160
161impl<T> Default for ScriptBufDecoder<T> {
162    fn default() -> Self { Self::new() }
163}
164
165impl<T> Decoder for ScriptBufDecoder<T> {
166    type Output = ScriptBuf<T>;
167    type Error = ScriptBufDecoderError;
168
169    #[inline]
170    fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
171        Ok(self.0.push_bytes(bytes)?)
172    }
173
174    #[inline]
175    fn end(self) -> Result<Self::Output, Self::Error> { Ok(ScriptBuf::from_bytes(self.0.end()?)) }
176
177    #[inline]
178    fn read_limit(&self) -> usize { self.0.read_limit() }
179}
180
181impl<T> Decodable for ScriptBuf<T> {
182    type Decoder = ScriptBufDecoder<T>;
183    fn decoder() -> Self::Decoder { ScriptBufDecoder(ByteVecDecoder::new(), PhantomData) }
184}
185
186/// An error consensus decoding a `ScriptBuf<T>`.
187#[derive(Debug, Clone, PartialEq, Eq)]
188pub struct ScriptBufDecoderError(ByteVecDecoderError);
189
190impl From<Infallible> for ScriptBufDecoderError {
191    fn from(never: Infallible) -> Self { match never {} }
192}
193
194impl From<ByteVecDecoderError> for ScriptBufDecoderError {
195    fn from(e: ByteVecDecoderError) -> Self { Self(e) }
196}
197
198impl fmt::Display for ScriptBufDecoderError {
199    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write_err!(f, "decoder error"; self.0) }
200}
201
202#[cfg(feature = "std")]
203impl std::error::Error for ScriptBufDecoderError {
204    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) }
205}
206
207#[cfg(feature = "arbitrary")]
208impl<'a, T> Arbitrary<'a> for ScriptBuf<T> {
209    #[inline]
210    fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
211        let v = Vec::<u8>::arbitrary(u)?;
212        Ok(Self::from_bytes(v))
213    }
214}
215
216#[cfg(test)]
217mod tests {
218    // All tests should compile and pass no matter which script type you put here.
219    type ScriptBuf = super::super::ScriptSigBuf;
220
221    #[cfg(feature = "alloc")]
222    use alloc::string::ToString;
223    #[cfg(feature = "alloc")]
224    use alloc::vec;
225    #[cfg(feature = "std")]
226    use std::error::Error as _;
227
228    use super::*;
229
230    #[test]
231    fn script_buf_from_bytes() {
232        let bytes = vec![1, 2, 3];
233        let script = ScriptBuf::from_bytes(bytes.clone());
234        assert_eq!(script.as_bytes(), bytes);
235    }
236
237    #[test]
238    fn script_buf_as_script() {
239        let bytes = vec![1, 2, 3];
240        let script = ScriptBuf::from_bytes(bytes.clone());
241        let script_ref = script.as_script();
242        assert_eq!(script_ref.as_bytes(), bytes);
243    }
244
245    #[test]
246    fn script_buf_as_mut_script() {
247        let mut script = ScriptBuf::from_bytes(vec![1, 2, 3]);
248        let script_mut_ref = script.as_mut_script();
249        script_mut_ref.as_mut_bytes()[0] = 4;
250        assert_eq!(script.as_mut_bytes(), &[4, 2, 3]);
251    }
252
253    #[test]
254    fn script_buf_into_bytes() {
255        let bytes = vec![1, 2, 3];
256        let script = ScriptBuf::from_bytes(bytes.clone());
257        let result = script.into_bytes();
258        assert_eq!(result, bytes);
259    }
260
261    #[test]
262    fn script_buf_into_boxed_script() {
263        let bytes = vec![1, 2, 3];
264        let script = ScriptBuf::from_bytes(bytes.clone());
265        let boxed_script = script.into_boxed_script();
266        assert_eq!(boxed_script.as_bytes(), bytes);
267    }
268
269    #[test]
270    fn script_buf_capacity() {
271        let script = ScriptBuf::with_capacity(10);
272        assert!(script.capacity() >= 10);
273    }
274
275    #[test]
276    fn script_buf_reserve() {
277        let mut script = ScriptBuf::new();
278        script.reserve(10);
279        assert!(script.capacity() >= 10);
280    }
281
282    #[test]
283    fn script_buf_reserve_exact() {
284        let mut script = ScriptBuf::new();
285        script.reserve_exact(10);
286        assert!(script.capacity() >= 10);
287    }
288
289    #[test]
290    fn script_buf_default() {
291        let script: ScriptBuf = ScriptBuf::default();
292        assert!(script.is_empty());
293    }
294
295    #[test]
296    fn script_consensus_decode_empty() {
297        let bytes = vec![0_u8];
298        let mut push = bytes.as_slice();
299        let mut decoder = ScriptBuf::decoder();
300        decoder.push_bytes(&mut push).unwrap();
301
302        let got = decoder.end().unwrap();
303        let want = ScriptBuf::new();
304
305        assert_eq!(got, want);
306    }
307
308    #[test]
309    fn script_consensus_decode_empty_with_more_data() {
310        // An empty script sig with a bunch of unrelated data at the end.
311        let bytes = vec![0x00_u8, 0xff, 0xff, 0xff, 0xff];
312        let mut push = bytes.as_slice();
313        let mut decoder = ScriptBuf::decoder();
314        decoder.push_bytes(&mut push).unwrap();
315
316        let got = decoder.end().unwrap();
317        let want = ScriptBuf::new();
318
319        assert_eq!(got, want);
320    }
321
322    #[test]
323    fn decoder_full_read_limit() {
324        let mut decoder = ScriptBuf::decoder();
325        // ByteVecDecoder length prefix is CompactSize: needs 1 byte.
326        assert_eq!(decoder.read_limit(), 1);
327
328        // Script length prefix = 32.
329        let mut push = [32_u8].as_slice();
330        decoder.push_bytes(&mut push).unwrap();
331        // Limit is 32 for the script data.
332        assert_eq!(decoder.read_limit(), 32);
333
334        // Provide 1 byte of script data decreasing the read limit by 1.
335        let mut push = [0xAA_u8].as_slice();
336        decoder.push_bytes(&mut push).unwrap();
337        assert_eq!(decoder.read_limit(), 31);
338    }
339
340    #[test]
341    #[cfg(feature = "alloc")]
342    fn decoder_error_display() {
343        let bytes = vec![0x01_u8];
344        let mut push = bytes.as_slice();
345        let mut decoder = <ScriptBuf as Decodable>::Decoder::default();
346        decoder.push_bytes(&mut push).unwrap();
347
348        let err = decoder.end().unwrap_err();
349        assert!(!err.to_string().is_empty());
350        #[cfg(feature = "std")]
351        assert!(err.source().is_some());
352    }
353}