bitcoin_primitives/script/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Bitcoin scripts.
4
5/// FIXME: Make this private.
6mod borrowed;
7/// FIXME: Make this private.
8mod owned;
9
10use core::cmp::Ordering;
11use core::fmt;
12use core::ops::{Deref, DerefMut};
13
14use hex::DisplayHex;
15use internals::script::{self, PushDataLenLen};
16
17use crate::opcodes::all::*;
18use crate::opcodes::{self, Opcode};
19use crate::prelude::rc::Rc;
20#[cfg(target_has_atomic = "ptr")]
21use crate::prelude::sync::Arc;
22use crate::prelude::{Borrow, BorrowMut, Box, Cow, ToOwned, Vec};
23
24#[rustfmt::skip]                // Keep public re-exports separate.
25#[doc(inline)]
26pub use self::{
27    borrowed::Script,
28    owned::ScriptBuf,
29};
30
31// We keep all the `Script` and `ScriptBuf` impls together since its easier to see side-by-side.
32
33impl From<ScriptBuf> for Box<Script> {
34    fn from(v: ScriptBuf) -> Self { v.into_boxed_script() }
35}
36
37impl From<ScriptBuf> for Cow<'_, Script> {
38    fn from(value: ScriptBuf) -> Self { Cow::Owned(value) }
39}
40
41impl<'a> From<Cow<'a, Script>> for ScriptBuf {
42    fn from(value: Cow<'a, Script>) -> Self {
43        match value {
44            Cow::Owned(owned) => owned,
45            Cow::Borrowed(borrwed) => borrwed.into(),
46        }
47    }
48}
49
50impl<'a> From<Cow<'a, Script>> for Box<Script> {
51    fn from(value: Cow<'a, Script>) -> Self {
52        match value {
53            Cow::Owned(owned) => owned.into(),
54            Cow::Borrowed(borrwed) => borrwed.into(),
55        }
56    }
57}
58
59impl<'a> From<&'a Script> for Box<Script> {
60    fn from(value: &'a Script) -> Self { value.to_owned().into() }
61}
62
63impl<'a> From<&'a Script> for ScriptBuf {
64    fn from(value: &'a Script) -> Self { value.to_owned() }
65}
66
67impl<'a> From<&'a Script> for Cow<'a, Script> {
68    fn from(value: &'a Script) -> Self { Cow::Borrowed(value) }
69}
70
71/// Note: This will fail to compile on old Rust for targets that don't support atomics
72#[cfg(target_has_atomic = "ptr")]
73impl<'a> From<&'a Script> for Arc<Script> {
74    fn from(value: &'a Script) -> Self {
75        let rw: *const [u8] = Arc::into_raw(Arc::from(&value.0));
76        // SAFETY: copied from `std`
77        // The pointer was just created from an Arc without deallocating
78        // Casting a slice to a transparent struct wrapping that slice is sound (same
79        // layout).
80        unsafe { Arc::from_raw(rw as *const Script) }
81    }
82}
83
84impl<'a> From<&'a Script> for Rc<Script> {
85    fn from(value: &'a Script) -> Self {
86        let rw: *const [u8] = Rc::into_raw(Rc::from(&value.0));
87        // SAFETY: copied from `std`
88        // The pointer was just created from an Rc without deallocating
89        // Casting a slice to a transparent struct wrapping that slice is sound (same
90        // layout).
91        unsafe { Rc::from_raw(rw as *const Script) }
92    }
93}
94
95impl From<Vec<u8>> for ScriptBuf {
96    fn from(v: Vec<u8>) -> Self { ScriptBuf(v) }
97}
98
99impl From<ScriptBuf> for Vec<u8> {
100    fn from(v: ScriptBuf) -> Self { v.0 }
101}
102
103impl AsRef<Script> for Script {
104    #[inline]
105    fn as_ref(&self) -> &Script { self }
106}
107
108impl AsRef<Script> for ScriptBuf {
109    fn as_ref(&self) -> &Script { self }
110}
111
112impl AsRef<[u8]> for Script {
113    #[inline]
114    fn as_ref(&self) -> &[u8] { self.as_bytes() }
115}
116
117impl AsRef<[u8]> for ScriptBuf {
118    fn as_ref(&self) -> &[u8] { self.as_bytes() }
119}
120
121impl AsMut<Script> for Script {
122    fn as_mut(&mut self) -> &mut Script { self }
123}
124
125impl AsMut<Script> for ScriptBuf {
126    fn as_mut(&mut self) -> &mut Script { self }
127}
128
129impl AsMut<[u8]> for Script {
130    #[inline]
131    fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
132}
133
134impl AsMut<[u8]> for ScriptBuf {
135    fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
136}
137
138impl fmt::Debug for Script {
139    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140        f.write_str("Script(")?;
141        fmt::Display::fmt(self, f)?;
142        f.write_str(")")
143    }
144}
145
146impl fmt::Debug for ScriptBuf {
147    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self.as_script(), f) }
148}
149
150impl fmt::Display for Script {
151    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
152        // This has to be a macro because it needs to break the loop
153        macro_rules! read_push_data_len {
154            ($iter:expr, $size:path, $formatter:expr) => {
155                match script::read_push_data_len($iter, $size) {
156                    Ok(n) => n,
157                    Err(_) => {
158                        $formatter.write_str("<unexpected end>")?;
159                        break;
160                    }
161                }
162            };
163        }
164
165        let mut iter = self.as_bytes().iter();
166        // Was at least one opcode emitted?
167        let mut at_least_one = false;
168        // `iter` needs to be borrowed in `read_push_data_len`, so we have to use `while let` instead
169        // of `for`.
170        while let Some(byte) = iter.next() {
171            let opcode = Opcode::from(*byte);
172
173            let data_len = if let opcodes::Class::PushBytes(n) =
174                opcode.classify(opcodes::ClassifyContext::Legacy)
175            {
176                n as usize
177            } else {
178                match opcode {
179                    OP_PUSHDATA1 => {
180                        // side effects: may write and break from the loop
181                        read_push_data_len!(&mut iter, PushDataLenLen::One, f)
182                    }
183                    OP_PUSHDATA2 => {
184                        // side effects: may write and break from the loop
185                        read_push_data_len!(&mut iter, PushDataLenLen::Two, f)
186                    }
187                    OP_PUSHDATA4 => {
188                        // side effects: may write and break from the loop
189                        read_push_data_len!(&mut iter, PushDataLenLen::Four, f)
190                    }
191                    _ => 0,
192                }
193            };
194
195            if at_least_one {
196                f.write_str(" ")?;
197            } else {
198                at_least_one = true;
199            }
200            // Write the opcode
201            if opcode == OP_PUSHBYTES_0 {
202                f.write_str("OP_0")?;
203            } else {
204                write!(f, "{:?}", opcode)?;
205            }
206            // Write any pushdata
207            if data_len > 0 {
208                f.write_str(" ")?;
209                if data_len <= iter.len() {
210                    for ch in iter.by_ref().take(data_len) {
211                        write!(f, "{:02x}", ch)?;
212                    }
213                } else {
214                    f.write_str("<push past end>")?;
215                    break;
216                }
217            }
218        }
219        Ok(())
220    }
221}
222
223impl fmt::Display for ScriptBuf {
224    #[inline]
225    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self.as_script(), f) }
226}
227
228impl fmt::LowerHex for Script {
229    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230        fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
231    }
232}
233#[cfg(feature = "alloc")]
234internals::impl_to_hex_from_lower_hex!(Script, |script: &Script| script.len() * 2);
235
236impl fmt::LowerHex for ScriptBuf {
237    #[inline]
238    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self.as_script(), f) }
239}
240#[cfg(feature = "alloc")]
241internals::impl_to_hex_from_lower_hex!(ScriptBuf, |script_buf: &ScriptBuf| script_buf.len() * 2);
242
243impl fmt::UpperHex for Script {
244    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245        fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
246    }
247}
248
249impl fmt::UpperHex for ScriptBuf {
250    #[inline]
251    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(self.as_script(), f) }
252}
253
254impl Deref for ScriptBuf {
255    type Target = Script;
256
257    fn deref(&self) -> &Self::Target { Script::from_bytes(&self.0) }
258}
259
260impl DerefMut for ScriptBuf {
261    fn deref_mut(&mut self) -> &mut Self::Target { Script::from_bytes_mut(&mut self.0) }
262}
263
264impl Borrow<Script> for ScriptBuf {
265    fn borrow(&self) -> &Script { self }
266}
267
268impl BorrowMut<Script> for ScriptBuf {
269    fn borrow_mut(&mut self) -> &mut Script { self }
270}
271
272impl PartialEq<ScriptBuf> for Script {
273    fn eq(&self, other: &ScriptBuf) -> bool { self.eq(other.as_script()) }
274}
275
276impl PartialEq<Script> for ScriptBuf {
277    fn eq(&self, other: &Script) -> bool { self.as_script().eq(other) }
278}
279
280impl PartialOrd<Script> for ScriptBuf {
281    fn partial_cmp(&self, other: &Script) -> Option<Ordering> {
282        self.as_script().partial_cmp(other)
283    }
284}
285
286impl PartialOrd<ScriptBuf> for Script {
287    fn partial_cmp(&self, other: &ScriptBuf) -> Option<Ordering> {
288        self.partial_cmp(other.as_script())
289    }
290}
291
292#[cfg(feature = "serde")]
293impl serde::Serialize for Script {
294    /// User-facing serialization for `Script`.
295    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
296    where
297        S: serde::Serializer,
298    {
299        if serializer.is_human_readable() {
300            serializer.collect_str(&format_args!("{:x}", self))
301        } else {
302            serializer.serialize_bytes(self.as_bytes())
303        }
304    }
305}
306
307/// Can only deserialize borrowed bytes.
308#[cfg(feature = "serde")]
309impl<'de> serde::Deserialize<'de> for &'de Script {
310    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
311    where
312        D: serde::Deserializer<'de>,
313    {
314        if deserializer.is_human_readable() {
315            use crate::serde::de::Error;
316
317            return Err(D::Error::custom(
318                "deserialization of `&Script` from human-readable formats is not possible",
319            ));
320        }
321
322        struct Visitor;
323        impl<'de> serde::de::Visitor<'de> for Visitor {
324            type Value = &'de Script;
325
326            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
327                formatter.write_str("borrowed bytes")
328            }
329
330            fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
331            where
332                E: serde::de::Error,
333            {
334                Ok(Script::from_bytes(v))
335            }
336        }
337        deserializer.deserialize_bytes(Visitor)
338    }
339}
340
341#[cfg(feature = "serde")]
342impl serde::Serialize for ScriptBuf {
343    /// User-facing serialization for `Script`.
344    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
345    where
346        S: serde::Serializer,
347    {
348        (**self).serialize(serializer)
349    }
350}
351
352#[cfg(feature = "serde")]
353impl<'de> serde::Deserialize<'de> for ScriptBuf {
354    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
355    where
356        D: serde::Deserializer<'de>,
357    {
358        use core::fmt::Formatter;
359
360        use hex::FromHex;
361
362        if deserializer.is_human_readable() {
363            struct Visitor;
364            impl serde::de::Visitor<'_> for Visitor {
365                type Value = ScriptBuf;
366
367                fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
368                    formatter.write_str("a script hex")
369                }
370
371                fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
372                where
373                    E: serde::de::Error,
374                {
375                    let v = Vec::from_hex(v).map_err(E::custom)?;
376                    Ok(ScriptBuf::from(v))
377                }
378            }
379            deserializer.deserialize_str(Visitor)
380        } else {
381            struct BytesVisitor;
382
383            impl serde::de::Visitor<'_> for BytesVisitor {
384                type Value = ScriptBuf;
385
386                fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
387                    formatter.write_str("a script Vec<u8>")
388                }
389
390                fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
391                where
392                    E: serde::de::Error,
393                {
394                    Ok(ScriptBuf::from(v.to_vec()))
395                }
396
397                fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E>
398                where
399                    E: serde::de::Error,
400                {
401                    Ok(ScriptBuf::from(v))
402                }
403            }
404            deserializer.deserialize_byte_buf(BytesVisitor)
405        }
406    }
407}