Merge rust-bitcoin/rust-bitcoin#4281: Return `ControlBlock` from `Witness::taproot_control_block`
492073f288
Strengthen the type of `taproot_control_block()` (Martin Habovstiak)e8a42d5851
Unify/reduce usage of `unsafe` (Martin Habovstiak)d42364bd9d
Swap around the fields in `Address` (Martin Habovstiak)7a115e3cf1
Make `Address` obey sanity rules (Martin Habovstiak)bc6da1fe07
Swap around the fields in `sha256t::Hash` (Martin Habovstiak)8ee088df74
Make `sha256t` obey sanity rules (Martin Habovstiak) Pull request description: Well, I thought this PR will be just the last commit... 😅 Anyway, this implements a bunch of changes to allow returning `ControlBlock` from `Witness` method(s). One cool side effect is that this PR also reduces the number of `unsafe` blocks. ACKs for top commit: apoelstra: ACK 492073f28876406f8fe5a07a8a2495c8e0ba1fb3; successfully ran local tests Tree-SHA512: 11979517cc310abf25644fc93a75deccacae66af8ba2d9b4011fdc3f414b15fac7e748399c7eef492ca850c11b7aacc3f24ec46fccf95e6d57a400212979637e
This commit is contained in:
commit
a2408e9b0c
|
@ -158,7 +158,7 @@ pub struct NetworkValidationError {
|
|||
impl fmt::Display for NetworkValidationError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "address ")?;
|
||||
fmt::Display::fmt(&self.address.0, f)?;
|
||||
fmt::Display::fmt(&self.address.inner(), f)?;
|
||||
write!(f, " is not valid on {}", self.required)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -308,103 +308,108 @@ 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<NetworkUnchecked>::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<NetworkUnchecked>` suggesting that network of the parsed address
|
||||
/// has not yet been verified. To perform this verification, method [`require_network`](Address<NetworkUnchecked>::require_network)
|
||||
/// can be called, providing network on which the address is supposed to be valid. If the verification succeeds,
|
||||
/// `Address<NetworkChecked>` is returned.
|
||||
///
|
||||
/// The types `Address` and `Address<NetworkChecked>` 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<NetworkUnchecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap();
|
||||
/// let _address: Address<NetworkChecked> = 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<NetworkChecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse::<Address<_>>()
|
||||
/// .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<NetworkChecked>`:
|
||||
///
|
||||
/// ```
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkChecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap().assume_checked();
|
||||
/// assert_eq!(address.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
|
||||
/// ```
|
||||
///
|
||||
/// ```ignore
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkUnchecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap();
|
||||
/// let s = address.to_string(); // does not compile
|
||||
/// ```
|
||||
///
|
||||
/// 2. `Debug` on `Address<NetworkUnchecked>` 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<NetworkUnchecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap();
|
||||
/// assert_eq!(format!("{:?}", address), "Address<NetworkUnchecked>(132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM)");
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkChecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .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<V = NetworkChecked>(AddressInner, PhantomData<V>)
|
||||
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<NetworkUnchecked>::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<NetworkUnchecked>` suggesting that network of the parsed address
|
||||
/// has not yet been verified. To perform this verification, method [`require_network`](Address<NetworkUnchecked>::require_network)
|
||||
/// can be called, providing network on which the address is supposed to be valid. If the verification succeeds,
|
||||
/// `Address<NetworkChecked>` is returned.
|
||||
///
|
||||
/// The types `Address` and `Address<NetworkChecked>` 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<NetworkUnchecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse().unwrap();
|
||||
/// let _address: Address<NetworkChecked> = 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<NetworkChecked> = "32iVBEu4dxkUQk9dJbZUiBiQdmypcEyJRf".parse::<Address<_>>()
|
||||
/// .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<NetworkChecked>`:
|
||||
///
|
||||
/// ```
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkChecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap().assume_checked();
|
||||
/// assert_eq!(address.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
|
||||
/// ```
|
||||
///
|
||||
/// ```ignore
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkUnchecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap();
|
||||
/// let s = address.to_string(); // does not compile
|
||||
/// ```
|
||||
///
|
||||
/// 2. `Debug` on `Address<NetworkUnchecked>` 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<NetworkUnchecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .unwrap();
|
||||
/// assert_eq!(format!("{:?}", address), "Address<NetworkUnchecked>(132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM)");
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// # use bitcoin::address::{Address, NetworkChecked};
|
||||
/// let address: Address<NetworkChecked> = "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".parse::<Address<_>>()
|
||||
/// .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<V = NetworkChecked>(PhantomData<V>, AddressInner)
|
||||
where
|
||||
V: NetworkValidation;
|
||||
|
||||
impl<V> Address<V> {
|
||||
fn from_inner_ref(inner: &_) -> &Self;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
struct DisplayUnchecked<'a, N: NetworkValidation>(&'a Address<N>);
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
impl<N: NetworkValidation> fmt::Display for DisplayUnchecked<'_, N> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0 .0, fmt) }
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0.inner(), fmt) }
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
|
@ -433,7 +438,7 @@ impl<'de, U: NetworkValidationUnchecked> serde::Deserialize<'de> for Address<U>
|
|||
{
|
||||
// We know that `U` is only ever `NetworkUnchecked` but the compiler does not.
|
||||
let address = v.parse::<Address<NetworkUnchecked>>().map_err(E::custom)?;
|
||||
Ok(Address(address.0, PhantomData::<U>))
|
||||
Ok(Address::from_inner(address.into_inner()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,18 +459,30 @@ impl<V: NetworkValidation> serde::Serialize for Address<V> {
|
|||
/// Methods on [`Address`] that can be called on both `Address<NetworkChecked>` and
|
||||
/// `Address<NetworkUnchecked>`.
|
||||
impl<V: NetworkValidation> Address<V> {
|
||||
fn from_inner(inner: AddressInner) -> Self {
|
||||
Address(PhantomData, inner)
|
||||
}
|
||||
|
||||
fn into_inner(self) -> AddressInner {
|
||||
self.1
|
||||
}
|
||||
|
||||
fn inner(&self) -> &AddressInner {
|
||||
&self.1
|
||||
}
|
||||
|
||||
/// Returns a reference to the address as if it was unchecked.
|
||||
pub fn as_unchecked(&self) -> &Address<NetworkUnchecked> {
|
||||
unsafe { &*(self as *const Address<V> as *const Address<NetworkUnchecked>) }
|
||||
Address::from_inner_ref(self.inner())
|
||||
}
|
||||
|
||||
/// Marks the network of this address as unchecked.
|
||||
pub fn into_unchecked(self) -> Address<NetworkUnchecked> { Address(self.0, PhantomData) }
|
||||
pub fn into_unchecked(self) -> Address<NetworkUnchecked> { Address::from_inner(self.into_inner()) }
|
||||
|
||||
/// Returns the [`NetworkKind`] of this address.
|
||||
pub fn network_kind(&self) -> NetworkKind {
|
||||
use AddressInner::*;
|
||||
match self.0 {
|
||||
match *self.inner() {
|
||||
P2pkh { hash: _, ref network } => *network,
|
||||
P2sh { hash: _, ref network } => *network,
|
||||
Segwit { program: _, ref hrp } => NetworkKind::from(*hrp),
|
||||
|
@ -481,7 +498,7 @@ impl Address {
|
|||
#[inline]
|
||||
pub fn p2pkh(pk: impl Into<PubkeyHash>, network: impl Into<NetworkKind>) -> Address {
|
||||
let hash = pk.into();
|
||||
Self(AddressInner::P2pkh { hash, network: network.into() }, PhantomData)
|
||||
Self::from_inner(AddressInner::P2pkh { hash, network: network.into() })
|
||||
}
|
||||
|
||||
/// Constructs a new pay-to-script-hash (P2SH) [`Address`] from a script.
|
||||
|
@ -504,7 +521,7 @@ impl Address {
|
|||
/// The `hash` pre-image (redeem script) must not exceed 520 bytes in length
|
||||
/// otherwise outputs created from the returned address will be un-spendable.
|
||||
pub fn p2sh_from_hash(hash: ScriptHash, network: impl Into<NetworkKind>) -> Address {
|
||||
Self(AddressInner::P2sh { hash, network: network.into() }, PhantomData)
|
||||
Self::from_inner(AddressInner::P2sh { hash, network: network.into() })
|
||||
}
|
||||
|
||||
/// Constructs a new pay-to-witness-public-key-hash (P2WPKH) [`Address`] from a public key.
|
||||
|
@ -577,7 +594,7 @@ impl Address {
|
|||
/// then you likely do not need this constructor.
|
||||
pub fn from_witness_program(program: WitnessProgram, hrp: impl Into<KnownHrp>) -> Address {
|
||||
let inner = AddressInner::Segwit { program, hrp: hrp.into() };
|
||||
Address(inner, PhantomData)
|
||||
Address::from_inner(inner)
|
||||
}
|
||||
|
||||
/// Gets the address type of the [`Address`].
|
||||
|
@ -587,7 +604,7 @@ impl Address {
|
|||
/// None if unknown, non-standard or related to the future witness version.
|
||||
#[inline]
|
||||
pub fn address_type(&self) -> Option<AddressType> {
|
||||
match self.0 {
|
||||
match *self.inner() {
|
||||
AddressInner::P2pkh { .. } => Some(AddressType::P2pkh),
|
||||
AddressInner::P2sh { .. } => Some(AddressType::P2sh),
|
||||
AddressInner::Segwit { ref program, hrp: _ } =>
|
||||
|
@ -609,7 +626,7 @@ impl Address {
|
|||
pub fn to_address_data(&self) -> AddressData {
|
||||
use AddressData::*;
|
||||
|
||||
match self.0 {
|
||||
match *self.inner() {
|
||||
AddressInner::P2pkh { hash, network: _ } => P2pkh { pubkey_hash: hash },
|
||||
AddressInner::P2sh { hash, network: _ } => P2sh { script_hash: hash },
|
||||
AddressInner::Segwit { program, hrp: _ } => Segwit { witness_program: program },
|
||||
|
@ -620,7 +637,7 @@ impl Address {
|
|||
pub fn pubkey_hash(&self) -> Option<PubkeyHash> {
|
||||
use AddressInner::*;
|
||||
|
||||
match self.0 {
|
||||
match *self.inner() {
|
||||
P2pkh { ref hash, network: _ } => Some(*hash),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -630,7 +647,7 @@ impl Address {
|
|||
pub fn script_hash(&self) -> Option<ScriptHash> {
|
||||
use AddressInner::*;
|
||||
|
||||
match self.0 {
|
||||
match *self.inner() {
|
||||
P2sh { ref hash, network: _ } => Some(*hash),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -640,7 +657,7 @@ impl Address {
|
|||
pub fn witness_program(&self) -> Option<WitnessProgram> {
|
||||
use AddressInner::*;
|
||||
|
||||
match self.0 {
|
||||
match *self.inner() {
|
||||
Segwit { ref program, hrp: _ } => Some(*program),
|
||||
_ => None,
|
||||
}
|
||||
|
@ -689,7 +706,7 @@ impl Address {
|
|||
/// Generates a script pubkey spending to this address.
|
||||
pub fn script_pubkey(&self) -> ScriptBuf {
|
||||
use AddressInner::*;
|
||||
match self.0 {
|
||||
match *self.inner() {
|
||||
P2pkh { hash, network: _ } => ScriptBuf::new_p2pkh(hash),
|
||||
P2sh { hash, network: _ } => ScriptBuf::new_p2sh(hash),
|
||||
Segwit { ref program, hrp: _ } => {
|
||||
|
@ -756,7 +773,7 @@ impl Address {
|
|||
/// This function doesn't make any allocations.
|
||||
pub fn matches_script_pubkey(&self, script: &Script) -> bool {
|
||||
use AddressInner::*;
|
||||
match self.0 {
|
||||
match *self.inner() {
|
||||
P2pkh { ref hash, network: _ } if script.is_p2pkh() =>
|
||||
&script.as_bytes()[3..23] == <PubkeyHash as AsRef<[u8; 20]>>::as_ref(hash),
|
||||
P2sh { ref hash, network: _ } if script.is_p2sh() =>
|
||||
|
@ -777,7 +794,7 @@ impl Address {
|
|||
/// - For SegWit addresses, the payload is the witness program.
|
||||
fn payload_as_bytes(&self) -> &[u8] {
|
||||
use AddressInner::*;
|
||||
match self.0 {
|
||||
match *self.inner() {
|
||||
P2sh { ref hash, network: _ } => hash.as_ref(),
|
||||
P2pkh { ref hash, network: _ } => hash.as_ref(),
|
||||
Segwit { ref program, hrp: _ } => program.program().as_bytes(),
|
||||
|
@ -791,7 +808,7 @@ impl Address<NetworkUnchecked> {
|
|||
///
|
||||
/// 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<NetworkUnchecked> as *const Address) }
|
||||
Address::from_inner_ref(self.inner())
|
||||
}
|
||||
|
||||
/// Parsed addresses do not always have *one* network. The problem is that legacy testnet,
|
||||
|
@ -817,7 +834,7 @@ impl Address<NetworkUnchecked> {
|
|||
/// ```
|
||||
pub fn is_valid_for_network(&self, n: Network) -> bool {
|
||||
use AddressInner::*;
|
||||
match self.0 {
|
||||
match *self.inner() {
|
||||
P2pkh { hash: _, ref network } => *network == NetworkKind::from(n),
|
||||
P2sh { hash: _, ref network } => *network == NetworkKind::from(n),
|
||||
Segwit { program: _, ref hrp } => *hrp == KnownHrp::from_network(n),
|
||||
|
@ -882,7 +899,7 @@ impl Address<NetworkUnchecked> {
|
|||
/// For details about this mechanism, see section [*Parsing addresses*](Address#parsing-addresses)
|
||||
/// on [`Address`].
|
||||
#[inline]
|
||||
pub fn assume_checked(self) -> Address { Address(self.0, PhantomData) }
|
||||
pub fn assume_checked(self) -> Address { Address::from_inner(self.into_inner()) }
|
||||
|
||||
/// Parse a bech32 Address string
|
||||
pub fn from_bech32_str(s: &str) -> Result<Address<NetworkUnchecked>, Bech32Error> {
|
||||
|
@ -894,7 +911,7 @@ impl Address<NetworkUnchecked> {
|
|||
|
||||
let hrp = KnownHrp::from_hrp(hrp)?;
|
||||
let inner = AddressInner::Segwit { program, hrp };
|
||||
Ok(Address(inner, PhantomData))
|
||||
Ok(Address::from_inner(inner))
|
||||
}
|
||||
|
||||
/// Parse a base58 Address string
|
||||
|
@ -927,7 +944,7 @@ impl Address<NetworkUnchecked> {
|
|||
invalid => return Err(InvalidLegacyPrefixError { invalid }.into()),
|
||||
};
|
||||
|
||||
Ok(Address(inner, PhantomData))
|
||||
Ok(Address::from_inner(inner))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -938,16 +955,16 @@ impl From<Address> for ScriptBuf {
|
|||
// Alternate formatting `{:#}` is used to return uppercase version of bech32 addresses which should
|
||||
// be used in QR codes, see [`Address::to_qr_uri`].
|
||||
impl fmt::Display for Address {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, fmt) }
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.inner(), fmt) }
|
||||
}
|
||||
|
||||
impl<V: NetworkValidation> fmt::Debug for Address<V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
if V::IS_CHECKED {
|
||||
fmt::Display::fmt(&self.0, f)
|
||||
fmt::Display::fmt(&self.inner(), f)
|
||||
} else {
|
||||
write!(f, "Address<NetworkUnchecked>(")?;
|
||||
fmt::Display::fmt(&self.0, f)?;
|
||||
fmt::Display::fmt(&self.inner(), f)?;
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
@ -975,10 +992,10 @@ impl<U: NetworkValidationUnchecked> FromStr for Address<U> {
|
|||
if ["bc1", "bcrt1", "tb1"].iter().any(|&prefix| s.to_lowercase().starts_with(prefix)) {
|
||||
let address = Address::from_bech32_str(s)?;
|
||||
// We know that `U` is only ever `NetworkUnchecked` but the compiler does not.
|
||||
Ok(Address(address.0, PhantomData::<U>))
|
||||
Ok(Address::from_inner(address.into_inner()))
|
||||
} else if ["1", "2", "3", "m", "n"].iter().any(|&prefix| s.starts_with(prefix)) {
|
||||
let address = Address::from_base58_str(s)?;
|
||||
Ok(Address(address.0, PhantomData::<U>))
|
||||
Ok(Address::from_inner(address.into_inner()))
|
||||
} else {
|
||||
let hrp = match s.rfind('1') {
|
||||
Some(pos) => &s[..pos],
|
||||
|
|
|
@ -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(&[]) }
|
||||
|
|
|
@ -10,15 +10,15 @@ use io::{BufRead, Write};
|
|||
use crate::consensus::encode::{self, Error, ReadExt, WriteExt, MAX_VEC_SIZE};
|
||||
use crate::consensus::{Decodable, Encodable};
|
||||
use crate::crypto::ecdsa;
|
||||
use crate::crypto::key::SerializedXOnlyPublicKey;
|
||||
use crate::prelude::Vec;
|
||||
#[cfg(doc)]
|
||||
use crate::script::ScriptExt as _;
|
||||
use crate::taproot::{
|
||||
self, ControlBlock, LeafScript, LeafVersion, TAPROOT_ANNEX_PREFIX, TAPROOT_CONTROL_BASE_SIZE,
|
||||
TAPROOT_LEAF_MASK, TaprootMerkleBranch,
|
||||
};
|
||||
use crate::taproot::{self, ControlBlock, LeafScript, TAPROOT_ANNEX_PREFIX, TaprootMerkleBranch};
|
||||
use crate::Script;
|
||||
|
||||
type BorrowedControlBlock<'a> = ControlBlock<&'a TaprootMerkleBranch, &'a SerializedXOnlyPublicKey>;
|
||||
|
||||
#[rustfmt::skip] // Keep public re-exports separate.
|
||||
#[doc(inline)]
|
||||
pub use primitives::witness::{Iter, Witness};
|
||||
|
@ -176,9 +176,8 @@ crate::internal_macros::define_extension_trait! {
|
|||
/// version.
|
||||
fn taproot_leaf_script(&self) -> Option<LeafScript<&Script>> {
|
||||
match P2TrSpend::from_witness(self) {
|
||||
Some(P2TrSpend::Script { leaf_script, control_block, .. }) if control_block.len() >= TAPROOT_CONTROL_BASE_SIZE => {
|
||||
let version = LeafVersion::from_consensus(control_block[0] & TAPROOT_LEAF_MASK).ok()?;
|
||||
Some(LeafScript { version, script: leaf_script, })
|
||||
Some(P2TrSpend::Script { leaf_script, control_block, .. }) => {
|
||||
Some(LeafScript { version: control_block.leaf_version, script: leaf_script, })
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
|
@ -191,7 +190,7 @@ crate::internal_macros::define_extension_trait! {
|
|||
/// byte of the last element being equal to 0x50.
|
||||
///
|
||||
/// See [`Script::is_p2tr`] to check whether this is actually a Taproot witness.
|
||||
fn taproot_control_block(&self) -> Option<&[u8]> {
|
||||
fn taproot_control_block(&self) -> Option<BorrowedControlBlock<'_>> {
|
||||
match P2TrSpend::from_witness(self) {
|
||||
Some(P2TrSpend::Script { control_block, .. }) => Some(control_block),
|
||||
_ => None,
|
||||
|
@ -236,7 +235,7 @@ enum P2TrSpend<'a> {
|
|||
},
|
||||
Script {
|
||||
leaf_script: &'a Script,
|
||||
control_block: &'a [u8],
|
||||
control_block: BorrowedControlBlock<'a>,
|
||||
annex: Option<&'a [u8]>,
|
||||
},
|
||||
}
|
||||
|
@ -275,17 +274,21 @@ impl<'a> P2TrSpend<'a> {
|
|||
// last one does NOT start with TAPROOT_ANNEX_PREFIX. This is handled in the catchall
|
||||
// arm.
|
||||
3.. if witness.last().expect("len > 0").starts_with(&[TAPROOT_ANNEX_PREFIX]) => {
|
||||
let control_block = witness.get_back(1).expect("len > 1");
|
||||
let control_block = BorrowedControlBlock::decode_borrowed(control_block).ok()?;
|
||||
let spend = P2TrSpend::Script {
|
||||
leaf_script: Script::from_bytes(witness.get_back(2).expect("len > 2")),
|
||||
control_block: witness.get_back(1).expect("len > 1"),
|
||||
control_block,
|
||||
annex: witness.last(),
|
||||
};
|
||||
Some(spend)
|
||||
}
|
||||
_ => {
|
||||
let control_block = witness.last().expect("len > 0");
|
||||
let control_block = BorrowedControlBlock::decode_borrowed(control_block).ok()?;
|
||||
let spend = P2TrSpend::Script {
|
||||
leaf_script: Script::from_bytes(witness.get_back(1).expect("len > 1")),
|
||||
control_block: witness.last().expect("len > 0"),
|
||||
control_block,
|
||||
annex: None,
|
||||
};
|
||||
Some(spend)
|
||||
|
@ -324,6 +327,7 @@ mod test {
|
|||
use crate::consensus::{deserialize, encode, serialize};
|
||||
use crate::hex::DisplayHex;
|
||||
use crate::sighash::EcdsaSighashType;
|
||||
use crate::taproot::LeafVersion;
|
||||
use crate::Transaction;
|
||||
|
||||
#[test]
|
||||
|
@ -383,7 +387,7 @@ mod test {
|
|||
#[test]
|
||||
fn get_tapscript() {
|
||||
let tapscript = hex!("deadbeef");
|
||||
let control_block = hex!("02");
|
||||
let control_block = hex!("c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
// annex starting with 0x50 causes the branching logic.
|
||||
let annex = hex!("50");
|
||||
|
||||
|
@ -431,7 +435,8 @@ mod test {
|
|||
#[test]
|
||||
fn get_control_block() {
|
||||
let tapscript = hex!("deadbeef");
|
||||
let control_block = hex!("02");
|
||||
let control_block = hex!("c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
let expected_control_block = BorrowedControlBlock::decode_borrowed(&control_block).unwrap();
|
||||
// annex starting with 0x50 causes the branching logic.
|
||||
let annex = hex!("50");
|
||||
let signature = vec![0xff; 64];
|
||||
|
@ -441,15 +446,15 @@ mod test {
|
|||
let witness_key_spend_annex = Witness::from([&*signature, &annex]);
|
||||
|
||||
// With or without annex, the tapscript should be returned.
|
||||
assert_eq!(witness.taproot_control_block(), Some(&control_block[..]));
|
||||
assert_eq!(witness_annex.taproot_control_block(), Some(&control_block[..]));
|
||||
assert_eq!(witness.taproot_control_block().unwrap(), expected_control_block);
|
||||
assert_eq!(witness_annex.taproot_control_block().unwrap(), expected_control_block);
|
||||
assert!(witness_key_spend_annex.taproot_control_block().is_none())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_annex() {
|
||||
let tapscript = hex!("deadbeef");
|
||||
let control_block = hex!("02");
|
||||
let control_block = hex!("c0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||
// annex starting with 0x50 causes the branching logic.
|
||||
let annex = hex!("50");
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ use crate::taproot::{TapNodeHash, TapTweakHash};
|
|||
|
||||
#[rustfmt::skip] // Keep public re-exports separate.
|
||||
pub use secp256k1::{constants, Keypair, Parity, Secp256k1, Verification, XOnlyPublicKey};
|
||||
pub use serialized_x_only::SerializedXOnlyPublicKey;
|
||||
|
||||
#[cfg(feature = "rand-std")]
|
||||
pub use secp256k1::rand;
|
||||
|
@ -1222,6 +1223,63 @@ impl fmt::Display for InvalidWifCompressionFlagError {
|
|||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for InvalidWifCompressionFlagError {}
|
||||
|
||||
mod serialized_x_only {
|
||||
internals::transparent_newtype! {
|
||||
/// An array of bytes that's semantically an x-only public but was **not** validated.
|
||||
///
|
||||
/// This can be useful when validation is not desired but semantics of the bytes should be
|
||||
/// preserved. The validation can still happen using `to_validated()` method.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub struct SerializedXOnlyPublicKey([u8; 32]);
|
||||
|
||||
impl SerializedXOnlyPublicKey {
|
||||
pub(crate) fn from_bytes_ref(bytes: &_) -> Self;
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializedXOnlyPublicKey {
|
||||
/// Marks the supplied bytes as a serialized x-only public key.
|
||||
pub const fn from_byte_array(bytes: [u8; 32]) -> Self {
|
||||
Self(bytes)
|
||||
}
|
||||
|
||||
/// Returns the raw bytes.
|
||||
pub const fn to_byte_array(self) -> [u8; 32] {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Returns a reference to the raw bytes.
|
||||
pub const fn as_byte_array(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializedXOnlyPublicKey {
|
||||
/// Returns `XOnlyPublicKey` if the bytes are valid.
|
||||
pub fn to_validated(self) -> Result<XOnlyPublicKey, secp256k1::Error> {
|
||||
XOnlyPublicKey::from_byte_array(self.as_byte_array())
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8; 32]> for SerializedXOnlyPublicKey {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
self.as_byte_array()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&SerializedXOnlyPublicKey> for SerializedXOnlyPublicKey {
|
||||
fn from(borrowed: &SerializedXOnlyPublicKey) -> Self {
|
||||
*borrowed
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SerializedXOnlyPublicKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.as_byte_array().as_hex(), f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use io::Write;
|
|||
use secp256k1::{Scalar, Secp256k1};
|
||||
|
||||
use crate::consensus::Encodable;
|
||||
use crate::crypto::key::{TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey};
|
||||
use crate::crypto::key::{SerializedXOnlyPublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey, XOnlyPublicKey};
|
||||
use crate::prelude::{BTreeMap, BTreeSet, BinaryHeap, Vec};
|
||||
use crate::{Script, ScriptBuf};
|
||||
|
||||
|
@ -1141,13 +1141,13 @@ impl<'leaf> ScriptLeaf<'leaf> {
|
|||
/// Control block data structure used in Tapscript satisfaction.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct ControlBlock<Branch = TaprootMerkleBranchBuf> where Branch: ?Sized {
|
||||
pub struct ControlBlock<Branch = TaprootMerkleBranchBuf, Key = UntweakedPublicKey> where Branch: ?Sized {
|
||||
/// The tapleaf version.
|
||||
pub leaf_version: LeafVersion,
|
||||
/// The parity of the output key (NOT THE INTERNAL KEY WHICH IS ALWAYS XONLY).
|
||||
pub output_key_parity: secp256k1::Parity,
|
||||
/// The internal key.
|
||||
pub internal_key: UntweakedPublicKey,
|
||||
pub internal_key: Key,
|
||||
/// The Merkle proof of a script associated with this leaf.
|
||||
pub merkle_branch: Branch,
|
||||
}
|
||||
|
@ -1166,6 +1166,24 @@ impl ControlBlock {
|
|||
/// - [`TaprootError::InvalidInternalKey`] if internal key is invalid (first 32 bytes after the parity byte).
|
||||
/// - [`TaprootError::InvalidMerkleTreeDepth`] if Merkle tree is too deep (more than 128 levels).
|
||||
pub fn decode(sl: &[u8]) -> Result<ControlBlock, TaprootError> {
|
||||
use alloc::borrow::ToOwned;
|
||||
|
||||
let ControlBlock {
|
||||
leaf_version,
|
||||
output_key_parity,
|
||||
internal_key,
|
||||
merkle_branch,
|
||||
} = ControlBlock::<&TaprootMerkleBranch, &SerializedXOnlyPublicKey>::decode_borrowed(sl)?;
|
||||
|
||||
let internal_key = internal_key.to_validated().map_err(TaprootError::InvalidInternalKey)?;
|
||||
let merkle_branch = merkle_branch.to_owned();
|
||||
|
||||
Ok(ControlBlock { leaf_version, output_key_parity, internal_key, merkle_branch })
|
||||
}
|
||||
}
|
||||
|
||||
impl<B, K> ControlBlock<B, K> {
|
||||
pub(crate) fn decode_borrowed<'a>(sl: &'a [u8]) -> Result<Self, TaprootError> where B: From<&'a TaprootMerkleBranch>, K: From<&'a SerializedXOnlyPublicKey> {
|
||||
let (base, merkle_branch) = sl.split_first_chunk::<TAPROOT_CONTROL_BASE_SIZE>()
|
||||
.ok_or(InvalidControlBlockSizeError(sl.len()))?;
|
||||
|
||||
|
@ -1177,9 +1195,8 @@ impl ControlBlock {
|
|||
};
|
||||
|
||||
let leaf_version = LeafVersion::from_consensus(first & TAPROOT_LEAF_MASK)?;
|
||||
let internal_key = UntweakedPublicKey::from_byte_array(internal_key)
|
||||
.map_err(TaprootError::InvalidInternalKey)?;
|
||||
let merkle_branch = TaprootMerkleBranchBuf::decode(merkle_branch)?;
|
||||
let internal_key = SerializedXOnlyPublicKey::from_bytes_ref(internal_key).into();
|
||||
let merkle_branch = TaprootMerkleBranch::decode(merkle_branch)?.into();
|
||||
Ok(ControlBlock { leaf_version, output_key_parity, internal_key, merkle_branch })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -43,33 +43,30 @@ pub trait Tag {
|
|||
const MIDSTATE: sha256::Midstate;
|
||||
}
|
||||
|
||||
/// Output of the SHA256t hash function.
|
||||
#[repr(transparent)]
|
||||
pub struct Hash<T>([u8; 32], PhantomData<T>);
|
||||
internals::transparent_newtype! {
|
||||
/// Output of the SHA256t hash function.
|
||||
pub struct Hash<T>(PhantomData<T>, [u8; 32]);
|
||||
|
||||
impl<T> Hash<T> {
|
||||
/// 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<T> Hash<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
const fn internal_new(arr: [u8; 32]) -> Self { Hash(arr, PhantomData) }
|
||||
const fn internal_new(arr: [u8; 32]) -> Self { Hash(PhantomData, arr) }
|
||||
|
||||
/// 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`.
|
||||
|
@ -117,10 +114,10 @@ where
|
|||
}
|
||||
|
||||
/// Returns the underlying byte array.
|
||||
pub const fn to_byte_array(self) -> [u8; 32] { self.0 }
|
||||
pub const fn to_byte_array(self) -> [u8; 32] { self.1 }
|
||||
|
||||
/// Returns a reference to the underlying byte array.
|
||||
pub const fn as_byte_array(&self) -> &[u8; 32] { &self.0 }
|
||||
pub const fn as_byte_array(&self) -> &[u8; 32] { &self.1 }
|
||||
}
|
||||
|
||||
impl<T: Tag> Copy for Hash<T> {}
|
||||
|
@ -128,7 +125,7 @@ impl<T: Tag> Clone for Hash<T> {
|
|||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
impl<T: Tag> PartialEq for Hash<T> {
|
||||
fn eq(&self, other: &Hash<T>) -> bool { self.0 == other.0 }
|
||||
fn eq(&self, other: &Hash<T>) -> bool { self.as_byte_array() == other.as_byte_array() }
|
||||
}
|
||||
impl<T: Tag> Eq for Hash<T> {}
|
||||
impl<T: Tag> PartialOrd for Hash<T> {
|
||||
|
@ -137,10 +134,10 @@ impl<T: Tag> PartialOrd for Hash<T> {
|
|||
}
|
||||
}
|
||||
impl<T: Tag> Ord for Hash<T> {
|
||||
fn cmp(&self, other: &Hash<T>) -> cmp::Ordering { cmp::Ord::cmp(&self.0, &other.0) }
|
||||
fn cmp(&self, other: &Hash<T>) -> cmp::Ordering { cmp::Ord::cmp(&self.as_byte_array(), &other.as_byte_array()) }
|
||||
}
|
||||
impl<T: Tag> core::hash::Hash for Hash<T> {
|
||||
fn hash<H: core::hash::Hasher>(&self, h: &mut H) { self.0.hash(h) }
|
||||
fn hash<H: core::hash::Hasher>(&self, h: &mut H) { self.as_byte_array().hash(h) }
|
||||
}
|
||||
|
||||
crate::internal_macros::hash_trait_impls!(256, false, T: Tag);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<Self> {
|
||||
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<Self> {
|
||||
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<Self> {
|
||||
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)*) => {};
|
||||
}
|
||||
|
|
|
@ -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>(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>(T);
|
||||
|
||||
impl<T> FromStd<T> {
|
||||
/// 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<Self>;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromStd<T> {
|
||||
/// 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<T>) -> Box<Self> {
|
||||
// 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<T: std::io::Write> std::io::Write for FromStd<T> {
|
|||
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>(T);
|
||||
internals::transparent_newtype! {
|
||||
/// A bridging wrapper providing the std traits for types that already implement our traits.
|
||||
#[derive(Debug)]
|
||||
pub struct ToStd<T>(T);
|
||||
|
||||
impl<T> ToStd<T> {
|
||||
/// 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<Self>;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ToStd<T> {
|
||||
/// 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<T>) -> Box<Self> {
|
||||
// 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 }
|
||||
|
|
|
@ -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<Self>;
|
||||
pub(crate) fn from_rc_bytes(bytes: Rc<_>) -> Rc<Self>;
|
||||
pub(crate) fn from_arc_bytes(bytes: Arc<_>) -> Arc<Self>;
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
|
|
|
@ -277,24 +277,14 @@ impl<'a> From<&'a Script> for Cow<'a, Script> {
|
|||
impl<'a> From<&'a Script> for Arc<Script> {
|
||||
#[inline]
|
||||
fn from(value: &'a Script) -> Self {
|
||||
let rw: *const [u8] = Arc::into_raw(Arc::from(value.as_bytes()));
|
||||
// SAFETY: copied from `std`
|
||||
// The pointer was just created from an Arc without deallocating
|
||||
// Casting a slice to a transparent struct wrapping that slice is sound (same
|
||||
// layout).
|
||||
unsafe { Arc::from_raw(rw as *const Script) }
|
||||
Script::from_arc_bytes(Arc::from(value.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Script> for Rc<Script> {
|
||||
#[inline]
|
||||
fn from(value: &'a Script) -> Self {
|
||||
let rw: *const [u8] = Rc::into_raw(Rc::from(value.as_bytes()));
|
||||
// SAFETY: copied from `std`
|
||||
// The pointer was just created from an Rc without deallocating
|
||||
// Casting a slice to a transparent struct wrapping that slice is sound (same
|
||||
// layout).
|
||||
unsafe { Rc::from_raw(rw as *const Script) }
|
||||
Script::from_rc_bytes(Rc::from(value.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,9 +54,7 @@ impl ScriptBuf {
|
|||
#[must_use]
|
||||
#[inline]
|
||||
pub fn into_boxed_script(self) -> Box<Script> {
|
||||
// Copied from PathBuf::into_boxed_path
|
||||
let rw = Box::into_raw(self.into_bytes().into_boxed_slice()) as *mut Script;
|
||||
unsafe { Box::from_raw(rw) }
|
||||
Script::from_boxed_bytes(self.into_bytes().into_boxed_slice())
|
||||
}
|
||||
|
||||
/// Constructs a new empty script with pre-allocated capacity.
|
||||
|
|
Loading…
Reference in New Issue