diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs index 48cf871fd..df8e04067 100644 --- a/bitcoin/src/address/mod.rs +++ b/bitcoin/src/address/mod.rs @@ -308,96 +308,101 @@ pub enum AddressData { }, } -/// A Bitcoin address. -/// -/// ### Parsing addresses -/// -/// When parsing string as an address, one has to pay attention to the network, on which the parsed -/// address is supposed to be valid. For the purpose of this validation, `Address` has -/// [`is_valid_for_network`](Address::is_valid_for_network) method. In order to provide more safety, -/// enforced by compiler, `Address` also contains a special marker type, which indicates whether network of the parsed -/// address has been checked. This marker type will prevent from calling certain functions unless the network -/// verification has been successfully completed. -/// -/// The result of parsing an address is `Address` suggesting that network of the parsed address -/// has not yet been verified. To perform this verification, method [`require_network`](Address::require_network) -/// can be called, providing network on which the address is supposed to be valid. If the verification succeeds, -/// `Address` is returned. -/// -/// The types `Address` and `Address` are synonymous, i. e. they can be used interchangeably. -/// -/// ```rust -/// use std::str::FromStr; -/// use bitcoin::{Address, Network}; -/// use bitcoin::address::{NetworkUnchecked, NetworkChecked}; -/// -/// // variant 1 -/// let address: Address = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap(); -/// let _address: Address = address.require_network(Network::Bitcoin).unwrap(); -/// -/// // variant 2 -/// let _address: Address = Address::from_str("32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf").unwrap() -/// .require_network(Network::Bitcoin).unwrap(); -/// -/// // variant 3 -/// let _address: Address = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse::>() -/// .unwrap().require_network(Network::Bitcoin).unwrap(); -/// ``` -/// -/// ### Formatting addresses -/// -/// To format address into its textual representation, both `Debug` (for usage in programmer-facing, -/// debugging context) and `Display` (for user-facing output) can be used, with the following caveats: -/// -/// 1. `Display` is implemented only for `Address`: -/// -/// ``` -/// # use bitcoin::address::{Address, NetworkChecked}; -/// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() -/// .unwrap().assume_checked(); -/// assert_eq!(address.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); -/// ``` -/// -/// ```ignore -/// # use bitcoin::address::{Address, NetworkChecked}; -/// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() -/// .unwrap(); -/// let s = address.to_string(); // does not compile -/// ``` -/// -/// 2. `Debug` on `Address` does not produce clean address but address wrapped by -/// an indicator that its network has not been checked. This is to encourage programmer to properly -/// check the network and use `Display` in user-facing context. -/// -/// ``` -/// # use bitcoin::address::{Address, NetworkUnchecked}; -/// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() -/// .unwrap(); -/// assert_eq!(format!("{:?}", address), "Address(132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM)"); -/// ``` -/// -/// ``` -/// # use bitcoin::address::{Address, NetworkChecked}; -/// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() -/// .unwrap().assume_checked(); -/// assert_eq!(format!("{:?}", address), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); -/// ``` -/// -/// ### Relevant BIPs -/// -/// * [BIP13 - Address Format for pay-to-script-hash](https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki) -/// * [BIP16 - Pay to Script Hash](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki) -/// * [BIP141 - Segregated Witness (Consensus layer)](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki) -/// * [BIP142 - Address Format for Segregated Witness](https://github.com/bitcoin/bips/blob/master/bip-0142.mediawiki) -/// * [BIP341 - Taproot: SegWit version 1 spending rules](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) -/// * [BIP350 - Bech32m format for v1+ witness addresses](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -// The `#[repr(transparent)]` attribute is used to guarantee the layout of the `Address` struct. It -// is an implementation detail and users should not rely on it in their code. -#[repr(transparent)] -pub struct Address(PhantomData, AddressInner) -where - V: NetworkValidation; +internals::transparent_newtype! { + /// A Bitcoin address. + /// + /// ### Parsing addresses + /// + /// When parsing string as an address, one has to pay attention to the network, on which the parsed + /// address is supposed to be valid. For the purpose of this validation, `Address` has + /// [`is_valid_for_network`](Address::is_valid_for_network) method. In order to provide more safety, + /// enforced by compiler, `Address` also contains a special marker type, which indicates whether network of the parsed + /// address has been checked. This marker type will prevent from calling certain functions unless the network + /// verification has been successfully completed. + /// + /// The result of parsing an address is `Address` suggesting that network of the parsed address + /// has not yet been verified. To perform this verification, method [`require_network`](Address::require_network) + /// can be called, providing network on which the address is supposed to be valid. If the verification succeeds, + /// `Address` is returned. + /// + /// The types `Address` and `Address` are synonymous, i. e. they can be used interchangeably. + /// + /// ```rust + /// use std::str::FromStr; + /// use bitcoin::{Address, Network}; + /// use bitcoin::address::{NetworkUnchecked, NetworkChecked}; + /// + /// // variant 1 + /// let address: Address = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap(); + /// let _address: Address = address.require_network(Network::Bitcoin).unwrap(); + /// + /// // variant 2 + /// let _address: Address = Address::from_str("32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf").unwrap() + /// .require_network(Network::Bitcoin).unwrap(); + /// + /// // variant 3 + /// let _address: Address = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse::>() + /// .unwrap().require_network(Network::Bitcoin).unwrap(); + /// ``` + /// + /// ### Formatting addresses + /// + /// To format address into its textual representation, both `Debug` (for usage in programmer-facing, + /// debugging context) and `Display` (for user-facing output) can be used, with the following caveats: + /// + /// 1. `Display` is implemented only for `Address`: + /// + /// ``` + /// # use bitcoin::address::{Address, NetworkChecked}; + /// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() + /// .unwrap().assume_checked(); + /// assert_eq!(address.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); + /// ``` + /// + /// ```ignore + /// # use bitcoin::address::{Address, NetworkChecked}; + /// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() + /// .unwrap(); + /// let s = address.to_string(); // does not compile + /// ``` + /// + /// 2. `Debug` on `Address` does not produce clean address but address wrapped by + /// an indicator that its network has not been checked. This is to encourage programmer to properly + /// check the network and use `Display` in user-facing context. + /// + /// ``` + /// # use bitcoin::address::{Address, NetworkUnchecked}; + /// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() + /// .unwrap(); + /// assert_eq!(format!("{:?}", address), "Address(132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM)"); + /// ``` + /// + /// ``` + /// # use bitcoin::address::{Address, NetworkChecked}; + /// let address: Address = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::>() + /// .unwrap().assume_checked(); + /// assert_eq!(format!("{:?}", address), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); + /// ``` + /// + /// ### Relevant BIPs + /// + /// * [BIP13 - Address Format for pay-to-script-hash](https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki) + /// * [BIP16 - Pay to Script Hash](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki) + /// * [BIP141 - Segregated Witness (Consensus layer)](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki) + /// * [BIP142 - Address Format for Segregated Witness](https://github.com/bitcoin/bips/blob/master/bip-0142.mediawiki) + /// * [BIP341 - Taproot: SegWit version 1 spending rules](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki) + /// * [BIP350 - Bech32m format for v1+ witness addresses](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) + #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] + // The `#[repr(transparent)]` attribute is used to guarantee the layout of the `Address` struct. It + // is an implementation detail and users should not rely on it in their code. + pub struct Address(PhantomData, AddressInner) + where + V: NetworkValidation; + + impl Address { + fn from_inner_ref(inner: &_) -> &Self; + } +} #[cfg(feature = "serde")] struct DisplayUnchecked<'a, N: NetworkValidation>(&'a Address); @@ -468,7 +473,7 @@ impl Address { /// Returns a reference to the address as if it was unchecked. pub fn as_unchecked(&self) -> &Address { - unsafe { &*(self as *const Address as *const Address) } + Address::from_inner_ref(self.inner()) } /// Marks the network of this address as unchecked. @@ -803,7 +808,7 @@ impl Address { /// /// This function is dangerous in case the address is not a valid checked address. pub fn assume_checked_ref(&self) -> &Address { - unsafe { &*(self as *const Address as *const Address) } + Address::from_inner_ref(self.inner()) } /// Parsed addresses do not always have *one* network. The problem is that legacy testnet, diff --git a/bitcoin/src/blockdata/script/push_bytes.rs b/bitcoin/src/blockdata/script/push_bytes.rs index bae7902b3..f469290f0 100644 --- a/bitcoin/src/blockdata/script/push_bytes.rs +++ b/bitcoin/src/blockdata/script/push_bytes.rs @@ -35,33 +35,29 @@ mod primitive { } } - /// Byte slices that can be in Bitcoin script. - /// - /// The encoding of Bitcoin script restricts data pushes to be less than 2^32 bytes long. - /// This type represents slices that are guaranteed to be within the limit so they can be put in - /// the script safely. - #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] - #[repr(transparent)] - pub struct PushBytes([u8]); + internals::transparent_newtype! { + /// Byte slices that can be in Bitcoin script. + /// + /// The encoding of Bitcoin script restricts data pushes to be less than 2^32 bytes long. + /// This type represents slices that are guaranteed to be within the limit so they can be put in + /// the script safely. + #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] + pub struct PushBytes([u8]); + + impl PushBytes { + /// Constructs a new `&PushBytes` without checking the length. + /// + /// The caller is responsible for checking that the length is less than the 2^32. + fn from_slice_unchecked(bytes: &_) -> &Self; + + /// Constructs a new `&mut PushBytes` without checking the length. + /// + /// The caller is responsible for checking that the length is less than the 2^32. + fn from_mut_slice_unchecked(bytes: &mut _) -> &mut Self; + } + } impl PushBytes { - /// Constructs a new `&PushBytes` without checking the length. - /// - /// The caller is responsible for checking that the length is less than the 2^32. - fn from_slice_unchecked(bytes: &[u8]) -> &Self { - // SAFETY: The conversion is sound because &[u8] and &PushBytes - // have the same layout (because of #[repr(transparent)] on PushBytes). - unsafe { &*(bytes as *const [u8] as *const PushBytes) } - } - - /// Constructs a new `&mut PushBytes` without checking the length. - /// - /// The caller is responsible for checking that the length is less than the 2^32. - fn from_mut_slice_unchecked(bytes: &mut [u8]) -> &mut Self { - // SAFETY: The conversion is sound because &mut [u8] and &mut PushBytes - // have the same layout (because of #[repr(transparent)] on PushBytes). - unsafe { &mut *(bytes as *mut [u8] as *mut PushBytes) } - } /// Constructs an empty `&PushBytes`. pub fn empty() -> &'static Self { Self::from_slice_unchecked(&[]) } diff --git a/bitcoin/src/taproot/merkle_branch/borrowed.rs b/bitcoin/src/taproot/merkle_branch/borrowed.rs index 58538f09d..6ca681e25 100644 --- a/bitcoin/src/taproot/merkle_branch/borrowed.rs +++ b/bitcoin/src/taproot/merkle_branch/borrowed.rs @@ -9,10 +9,16 @@ pub use privacy_boundary::TaprootMerkleBranch; mod privacy_boundary { use super::*; - /// The Merkle proof for inclusion of a tree in a Taproot tree hash. - #[repr(transparent)] - #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct TaprootMerkleBranch([TapNodeHash]); + internals::transparent_newtype! { + /// The Merkle proof for inclusion of a tree in a Taproot tree hash. + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct TaprootMerkleBranch([TapNodeHash]); + + impl TaprootMerkleBranch { + pub(super) const fn from_hashes_unchecked(hashes: &_) -> &Self; + pub(super) fn from_mut_hashes_unchecked(hashes: &mut _) -> &mut Self; + } + } impl TaprootMerkleBranch { /// Returns a reference to the slice of hashes. @@ -22,18 +28,6 @@ mod privacy_boundary { /// Returns a reference to the mutable slice of hashes. #[inline] pub fn as_mut_slice(&mut self) -> &mut [TapNodeHash] { &mut self.0 } - - pub(super) const fn from_hashes_unchecked(hashes: &[TapNodeHash]) -> &Self { - unsafe { - &*(hashes as *const _ as *const Self) - } - } - - pub(super) fn from_mut_hashes_unchecked(hashes: &mut [TapNodeHash]) -> &mut Self { - unsafe { - &mut *(hashes as *mut _ as *mut Self) - } - } } } diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs index 5e9599322..19945b46c 100644 --- a/hashes/src/internal_macros.rs +++ b/hashes/src/internal_macros.rs @@ -117,10 +117,21 @@ pub(crate) use general_hash_type; macro_rules! hash_type_no_default { ($bits:expr, $reverse:expr, $doc:literal) => { - #[doc = $doc] - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - #[repr(transparent)] - pub struct Hash([u8; $bits / 8]); + internals::transparent_newtype! { + #[doc = $doc] + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct Hash([u8; $bits / 8]); + + impl Hash { + /// Zero cost conversion between a fixed length byte array shared reference and + /// a shared reference to this Hash type. + pub fn from_bytes_ref(bytes: &_) -> &Self; + + /// Zero cost conversion between a fixed length byte array exclusive reference and + /// an exclusive reference to this Hash type. + pub fn from_bytes_mut(bytes: &mut _) -> &mut Self; + } + } impl Hash { const fn internal_new(arr: [u8; $bits / 8]) -> Self { Hash(arr) } @@ -130,20 +141,6 @@ macro_rules! hash_type_no_default { Self::internal_new(bytes) } - /// Zero cost conversion between a fixed length byte array shared reference and - /// a shared reference to this Hash type. - pub fn from_bytes_ref(bytes: &[u8; $bits / 8]) -> &Self { - // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8] - unsafe { &*(bytes as *const _ as *const Self) } - } - - /// Zero cost conversion between a fixed length byte array exclusive reference and - /// an exclusive reference to this Hash type. - pub fn from_bytes_mut(bytes: &mut [u8; $bits / 8]) -> &mut Self { - // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8] - unsafe { &mut *(bytes as *mut _ as *mut Self) } - } - /// Copies a byte slice into a hash object. #[deprecated(since = "0.15.0", note = "use `from_byte_array` instead")] #[allow(deprecated_in_future)] // Because of `FromSliceError`. diff --git a/hashes/src/sha256t/mod.rs b/hashes/src/sha256t/mod.rs index 59f73bf0f..526892db2 100644 --- a/hashes/src/sha256t/mod.rs +++ b/hashes/src/sha256t/mod.rs @@ -43,9 +43,20 @@ pub trait Tag { const MIDSTATE: sha256::Midstate; } -/// Output of the SHA256t hash function. -#[repr(transparent)] -pub struct Hash(PhantomData, [u8; 32]); +internals::transparent_newtype! { + /// Output of the SHA256t hash function. + pub struct Hash(PhantomData, [u8; 32]); + + impl Hash { + /// Zero cost conversion between a fixed length byte array shared reference and + /// a shared reference to this Hash type. + pub fn from_bytes_ref(bytes: &_) -> &Self; + + /// Zero cost conversion between a fixed length byte array exclusive reference and + /// an exclusive reference to this Hash type. + pub fn from_bytes_mut(bytes: &mut _) -> &mut Self; + } +} impl Hash where @@ -56,20 +67,6 @@ where /// Constructs a new hash from the underlying byte array. pub const fn from_byte_array(bytes: [u8; 32]) -> Self { Self::internal_new(bytes) } - /// Zero cost conversion between a fixed length byte array shared reference and - /// a shared reference to this Hash type. - pub fn from_bytes_ref(bytes: &[u8; 32]) -> &Self { - // Safety: Sound because Self is #[repr(transparent)] containing [u8; 32] - unsafe { &*(bytes as *const _ as *const Self) } - } - - /// Zero cost conversion between a fixed length byte array exclusive reference and - /// an exclusive reference to this Hash type. - pub fn from_bytes_mut(bytes: &mut [u8; 32]) -> &mut Self { - // Safety: Sound because Self is #[repr(transparent)] containing [u8; 32] - unsafe { &mut *(bytes as *mut _ as *mut Self) } - } - /// Copies a byte slice into a hash object. #[deprecated(since = "0.15.0", note = "use `from_byte_array` instead")] #[allow(deprecated_in_future)] // Because of `FromSliceError`. diff --git a/internals/src/lib.rs b/internals/src/lib.rs index c2e2ce708..35c179142 100644 --- a/internals/src/lib.rs +++ b/internals/src/lib.rs @@ -35,6 +35,12 @@ pub mod rust_version { include!(concat!(env!("OUT_DIR"), "/rust_version.rs")); } +#[doc(hidden)] +pub mod _export { + #[cfg(feature = "alloc")] + pub extern crate alloc; +} + pub mod array; pub mod array_vec; pub mod compact_size; diff --git a/internals/src/macros.rs b/internals/src/macros.rs index 69725e232..aa5ed1b62 100644 --- a/internals/src/macros.rs +++ b/internals/src/macros.rs @@ -37,3 +37,211 @@ macro_rules! impl_to_hex_from_lower_hex { } }; } + +/// Creates a transparent wrapper around an inner type and soundly implements reference casts. +/// +/// This macro takes care of several issues related to newtypes that need to allow casting their +/// inner types to themselves: +/// +/// * It makes sure to put repr(transparent) on the type +/// * It optionally implements conversions from `&`, `&mut`, `Box`, `Rc`, `Arc` +/// * It makes sure to put `#[inline]` on all of these conversions since they are trivial +/// * It makes sure the reference cast is const +/// * It makes sure the `Arc` conversion is conditioned on `target_has_atomic = "ptr"` +/// +/// Usage: just type the struct inside the macro as you would implementing it manually except leave +/// `#[repr(transparent)]` out. Then add an impl block for the just-defined type containing function +/// declarations that take a reference/smart pointer to `_` (use literal underscore; e.g. `&_` for +/// shared references) and return `Self` behind the appropriate "pointer" type. Do not write the +/// body, just semicolon. +/// +/// The `alloc` types MUST NOT have import paths and don't need imports. +#[macro_export] +macro_rules! transparent_newtype { + ( + $(#[$($struct_attr:tt)*])* + $vis:vis struct $newtype:tt$(<$gen:ident $(= $default:ty)?>)?($($fields:tt)+) $(where $($where_ty:ty: $bound:path),* $(,)?)?; + + impl$(<$gen2:tt>)? $newtype2:ident$(<$gen3:tt>)? { + $( + $(#[$($fn_attr:tt)*])* + $fn_vis:vis $(const)? fn $fn:ident($fn_arg_name:ident: $($fn_arg_ty:tt)+) -> $fn_ret_ty:ty; + )* + } + ) => { + $crate::_check_tts_eq!($newtype2, $newtype, "the type name in the impl block doesn't match the struct name"); + $( + // WARNING: renaming has to be disabled for soundness! + // If it weren't it'd be possible to make the type inside struct not match the one passed + // to functions. In principle we could also omit the generics but that'd be confusing for + // readers. + $crate::_check_tts_eq!($gen2, $gen, "the name of the left generic parameter in impl block doesn't match the one on struct"); + $crate::_check_tts_eq!($gen3, $gen, "the name of the right generic parameter in impl block doesn't match the one on struct"); + )? + $(#[$($struct_attr)*])* + #[repr(transparent)] + $vis struct $newtype$(<$gen $(= $default)?>)?($($fields)+) $(where $($where_ty: $bound),*)?; + + impl$(<$gen2>)? $newtype$(<$gen3>)? $(where $($where_ty: $bound),*)? { + $crate::_transparent_ref_conversions! { + $crate::_transparent_newtype_inner_type!($($fields)+); + $( + $(#[$($fn_attr)*])* + $fn_vis fn $fn($fn_arg_name: $($fn_arg_ty)+) -> $fn_ret_ty; + )+ + } + } + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! _transparent_ref_conversions { + ( + $inner:ty; + $( + $(#[$($fn_attr:tt)*])* + $fn_vis:vis $(const)? fn $fn:ident($fn_arg_name:ident: $($fn_arg_ty:tt)+) -> $fn_ret_ty:ty; + )+ + ) => { + $( + $crate::_transparent_ref_conversion! { + $inner; + $(#[$($fn_attr)*])* + $fn_vis fn $fn($fn_arg_name: $($fn_arg_ty)+) -> $fn_ret_ty; + } + )+ + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! _transparent_ref_conversion { + ( + $inner:ty; + $(#[$($from_ref_attr:tt)*])* + $from_ref_vis:vis fn $from_ref:ident($from_ref_arg_name:ident: &_) -> $fn_ret_ty:ty; + ) => { + #[inline] + $(#[$($from_ref_attr)*])* + $from_ref_vis const fn $from_ref($from_ref_arg_name: &$inner) -> &Self { + // SAFETY: the pointer is created by casting a pointer that is pointing to an object + // with the same layout and validity invariants and the previous pointer was created + // directly from a reference. (Notice repr(transparent).) + // The lifetime of the input reference matches the lifetime of the returned reference. + unsafe { &*($from_ref_arg_name as *const $inner as *const Self) } + } + }; + ( + $inner:ty; + $(#[$($from_mut_attr:tt)*])* + $from_mut_vis:vis fn $from_mut:ident($from_mut_arg_name:ident: &mut _) -> $fn_ret_ty:ty; + ) => { + #[inline] + $(#[$($from_mut_attr)*])* + $from_mut_vis fn $from_mut($from_mut_arg_name: &mut $inner) -> &mut Self { + // SAFETY: the pointer is created by casting a pointer that is pointing to an object + // with the same layout and validity invariants and the previous pointer was created + // directly from a reference. (Notice repr(transparent).) + // The lifetime of the input reference matches the lifetime of the returned reference. + unsafe { &mut *($from_mut_arg_name as *mut $inner as *mut Self) } + } + }; + ( + $inner:ty; + $(#[$($from_box_attr:tt)*])* + $from_box_vis:vis fn $from_box:ident($from_box_arg_name:ident: Box<_>) -> $fn_ret_ty:ty; + ) => { + $crate::_emit_alloc! { + $(#[$($from_box_attr)*])* + #[inline] + $from_box_vis fn $from_box($from_box_arg_name: $crate::_export::alloc::boxed::Box<$inner>) -> $crate::_export::alloc::boxed::Box { + let ptr = $crate::_export::alloc::boxed::Box::into_raw($from_box_arg_name); + // SAFETY: the pointer is created by casting a pointer that is pointing to an object + // with the same layout and validity invariants and the previous pointer was created + // directly from box. (Notice repr(transparent).) + unsafe { $crate::_export::alloc::boxed::Box::from_raw(ptr as *mut Self) } + } + } + }; + + ( + $inner:ty; + $(#[$($from_rc_attr:tt)*])* + $from_rc_vis:vis fn $from_rc:ident($from_rc_arg_name:ident: Rc<_>) -> $fn_ret_ty:ty; + ) => { + $crate::_emit_alloc! { + $(#[$($from_rc_attr)*])* + #[inline] + $from_rc_vis fn $from_rc($from_rc_arg_name: $crate::_export::alloc::rc::Rc<$inner>) -> $crate::_export::alloc::rc::Rc { + let ptr = $crate::_export::alloc::rc::Rc::into_raw($from_rc_arg_name); + // SAFETY: the pointer is created by casting a pointer that is pointing to an object + // with the same layout and validity invariants and the previous pointer was created + // directly from box. (Notice repr(transparent).) + unsafe { $crate::_export::alloc::rc::Rc::from_raw(ptr as *mut Self) } + } + } + }; + + ( + $inner:ty; + $(#[$($from_arc_attr:tt)*])* + $from_arc_vis:vis fn $from_arc:ident($from_arc_arg_name:ident: Arc<_>) -> $fn_ret_ty:ty; + ) => { + $crate::_emit_alloc! { + $(#[$($from_arc_attr)*])* + #[cfg(target_has_atomic = "ptr")] + #[inline] + $from_arc_vis fn $from_arc($from_arc_arg_name: $crate::_export::alloc::sync::Arc<$inner>) -> $crate::_export::alloc::sync::Arc { + let ptr = $crate::_export::alloc::sync::Arc::into_raw($from_arc_arg_name); + // SAFETY: the pointer is created by casting a pointer that is pointing to an object + // with the same layout and validity invariants and the previous pointer was created + // directly from box. (Notice repr(transparent).) + unsafe { $crate::_export::alloc::sync::Arc::from_raw(ptr as *mut Self) } + } + } + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! _check_tts_eq { + ($left:tt, $right:tt, $message:literal) => { + macro_rules! token_eq { + ($right) => {}; + ($any:tt) => { compile_error!($message) }; + } + token_eq!($left); + } +} + +#[doc(hidden)] +#[macro_export] +macro_rules! _transparent_newtype_inner_type { + ($(#[$($field_attr:tt)*])* $inner:ty) => { + $inner + }; + ($(#[$($phantom_attr:tt)*])* PhantomData<$phantom:ty>, $(#[$($field_attr:tt)*])* $inner:ty) => { + $inner + }; +} + +/// Emits given tokens only if the `alloc` feature **in this crate** is enabled. +/// +/// (The feature is currently enabled.) +#[cfg(feature = "alloc")] +#[doc(hidden)] +#[macro_export] +macro_rules! _emit_alloc { + ($($tokens:tt)*) => { $($tokens)* }; +} + +/// Emits given tokens only if the `alloc` feature **in this crate** is enabled. +/// +/// (The feature is currently disabled.) +#[cfg(not(feature = "alloc"))] +#[doc(hidden)] +#[macro_export] +macro_rules! _emit_alloc { + ($($tokens:tt)*) => {}; +} diff --git a/io/src/bridge.rs b/io/src/bridge.rs index fc49a0771..816820a2a 100644 --- a/io/src/bridge.rs +++ b/io/src/bridge.rs @@ -1,35 +1,26 @@ // SPDX-License-Identifier: CC0-1.0 -#[cfg(feature = "alloc")] -use alloc::boxed::Box; - use internals::rust_version; -/// A bridging wrapper providing the I/O traits for types that already implement `std` I/O traits. -#[repr(transparent)] -#[derive(Debug)] -pub struct FromStd(T); +internals::transparent_newtype! { + /// A bridging wrapper providing the I/O traits for types that already implement `std` I/O traits. + #[derive(Debug)] + pub struct FromStd(T); + + impl FromStd { + /// Wraps a mutable reference to I/O type. + pub fn new_mut(inner: &mut _) -> &mut Self; + + /// Wraps a boxed I/O type. + pub fn new_boxed(inner: Box<_>) -> Box; + } +} impl FromStd { /// Wraps an I/O type. #[inline] pub const fn new(inner: T) -> Self { Self(inner) } - /// Wraps a mutable reference to I/O type. - #[inline] - pub fn new_mut(inner: &mut T) -> &mut Self { - // SAFETY: the type is repr(transparent) and the lifetimes match - unsafe { &mut *(inner as *mut _ as *mut Self) } - } - - /// Wraps a boxed I/O type. - #[cfg(feature = "alloc")] - #[inline] - pub fn new_boxed(inner: Box) -> Box { - // SAFETY: the type is repr(transparent) and the pointer is created from Box - unsafe { Box::from_raw(Box::into_raw(inner) as *mut Self) } - } - /// Returns the wrapped value. #[inline] pub fn into_inner(self) -> T { self.0 } @@ -117,31 +108,25 @@ impl std::io::Write for FromStd { fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> { self.0.write_all(buf) } } -/// A bridging wrapper providing the std traits for types that already implement our traits. -#[repr(transparent)] -#[derive(Debug)] -pub struct ToStd(T); +internals::transparent_newtype! { + /// A bridging wrapper providing the std traits for types that already implement our traits. + #[derive(Debug)] + pub struct ToStd(T); + + impl ToStd { + /// Wraps a mutable reference to I/O type. + pub fn new_mut(inner: &mut _) -> &mut Self; + + /// Wraps a boxed I/O type. + pub fn new_boxed(inner: Box<_>) -> Box; + } +} impl ToStd { /// Wraps an I/O type. #[inline] pub const fn new(inner: T) -> Self { Self(inner) } - /// Wraps a mutable reference to I/O type. - #[inline] - pub fn new_mut(inner: &mut T) -> &mut Self { - // SAFETY: the type is repr(transparent) and the lifetimes match - unsafe { &mut *(inner as *mut _ as *mut Self) } - } - - /// Wraps a boxed I/O type. - #[cfg(feature = "alloc")] - #[inline] - pub fn new_boxed(inner: Box) -> Box { - // SAFETY: the type is repr(transparent) and the pointer is created from Box - unsafe { Box::from_raw(Box::into_raw(inner) as *mut Self) } - } - /// Returns the wrapped value. #[inline] pub fn into_inner(self) -> T { self.0 } diff --git a/primitives/src/script/borrowed.rs b/primitives/src/script/borrowed.rs index ece38f6ee..4f3bca28c 100644 --- a/primitives/src/script/borrowed.rs +++ b/primitives/src/script/borrowed.rs @@ -10,54 +10,67 @@ use arbitrary::{Arbitrary, Unstructured}; use super::ScriptBuf; use crate::prelude::{Box, ToOwned, Vec}; -/// 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)] -#[repr(transparent)] -pub struct Script([u8]); +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] @@ -76,28 +89,6 @@ impl Script { #[inline] pub const fn new() -> &'static Self { Self::from_bytes(&[]) } - /// Treat byte slice as `Script` - #[inline] - pub const fn from_bytes(bytes: &[u8]) -> &Self { - // SAFETY: copied from `std` - // The pointer was just created from a reference which is still alive. - // Casting slice pointer to a transparent struct wrapping that slice is sound (same - // layout). - unsafe { &*(bytes as *const [u8] as *const Self) } - } - - /// Treat mutable byte slice as `Script` - #[inline] - pub fn from_bytes_mut(bytes: &mut [u8]) -> &mut Self { - // SAFETY: copied from `std` - // The pointer was just created from a reference which is still alive. - // Casting slice pointer to a transparent struct wrapping that slice is sound (same - // layout). - // Function signature prevents callers from accessing `bytes` while the returned reference - // is alive. - unsafe { &mut *(bytes as *mut [u8] as *mut Self) } - } - /// Returns the script data as a byte slice. #[inline] pub const fn as_bytes(&self) -> &[u8] { &self.0 } diff --git a/primitives/src/script/mod.rs b/primitives/src/script/mod.rs index c263b4d68..2ad34017c 100644 --- a/primitives/src/script/mod.rs +++ b/primitives/src/script/mod.rs @@ -277,24 +277,14 @@ impl<'a> From<&'a Script> for Cow<'a, Script> { impl<'a> From<&'a Script> for Arc