// SPDX-License-Identifier: CC0-1.0 use core::ops::{ Bound, Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive, }; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; use super::ScriptBuf; use crate::prelude::{Box, ToOwned, Vec}; internals::transparent_newtype! { /// Bitcoin script slice. /// /// *[See also the `bitcoin::script` module](super).* /// /// `Script` is a script slice, the most primitive script type. It's usually seen in its borrowed /// form `&Script`. It is always encoded as a series of bytes representing the opcodes and data /// pushes. /// /// ## Validity /// /// `Script` does not have any validity invariants - it's essentially just a marked slice of /// bytes. This is similar to [`Path`](std::path::Path) vs [`OsStr`](std::ffi::OsStr) where they /// are trivially cast-able to each-other and `Path` doesn't guarantee being a usable FS path but /// having a newtype still has value because of added methods, readability and basic type checking. /// /// Although at least data pushes could be checked not to overflow the script, bad scripts are /// allowed to be in a transaction (outputs just become unspendable) and there even are such /// transactions in the chain. Thus we must allow such scripts to be placed in the transaction. /// /// ## Slicing safety /// /// Slicing is similar to how `str` works: some ranges may be incorrect and indexing by /// `usize` is not supported. However, as opposed to `std`, we have no way of checking /// correctness without causing linear complexity so there are **no panics on invalid /// ranges!** If you supply an invalid range, you'll get a garbled script. /// /// The range is considered valid if it's at a boundary of instruction. Care must be taken /// especially with push operations because you could get a reference to arbitrary /// attacker-supplied bytes that look like a valid script. /// /// It is recommended to use `.instructions()` method to get an iterator over script /// instructions and work with that instead. /// /// ## Memory safety /// /// The type is `#[repr(transparent)]` for internal purposes only! /// No consumer crate may rely on the representation of the struct! /// /// ## References /// /// /// ### Bitcoin Core References /// /// * [CScript definition](https://github.com/bitcoin/bitcoin/blob/d492dc1cdaabdc52b0766bf4cba4bd73178325d0/src/script/script.h#L410) /// #[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct Script([u8]); impl Script { /// Treat byte slice as `Script` pub const fn from_bytes(bytes: &_) -> &Self; /// Treat mutable byte slice as `Script` pub fn from_bytes_mut(bytes: &mut _) -> &mut Self; pub(crate) fn from_boxed_bytes(bytes: Box<_>) -> Box; pub(crate) fn from_rc_bytes(bytes: Rc<_>) -> Rc; pub(crate) fn from_arc_bytes(bytes: Arc<_>) -> Arc; } } impl Default for &Script { #[inline] fn default() -> Self { Script::new() } } impl ToOwned for Script { type Owned = ScriptBuf; #[inline] fn to_owned(&self) -> Self::Owned { ScriptBuf::from_bytes(self.to_vec()) } } impl Script { /// Constructs a new empty script. #[inline] pub const fn new() -> &'static Self { Self::from_bytes(&[]) } /// Returns the script data as a byte slice. #[inline] pub const fn as_bytes(&self) -> &[u8] { &self.0 } /// Returns the script data as a mutable byte slice. #[inline] pub fn as_mut_bytes(&mut self) -> &mut [u8] { &mut self.0 } /// Returns a copy of the script data. #[inline] pub fn to_vec(&self) -> Vec { self.as_bytes().to_owned() } /// Returns a copy of the script data. #[inline] #[deprecated(since = "TBD", note = "use to_vec instead")] pub fn to_bytes(&self) -> Vec { self.to_vec() } /// Returns the length in bytes of the script. #[inline] pub const fn len(&self) -> usize { self.as_bytes().len() } /// Returns whether the script is the empty script. #[inline] pub const fn is_empty(&self) -> bool { self.as_bytes().is_empty() } /// Converts a [`Box