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}