diff --git a/bitcoin/src/address/error.rs b/bitcoin/src/address/error.rs index c17471099..f1479425c 100644 --- a/bitcoin/src/address/error.rs +++ b/bitcoin/src/address/error.rs @@ -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) } } diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs index 93bc290d8..0200b108b 100644 --- a/bitcoin/src/address/mod.rs +++ b/bitcoin/src/address/mod.rs @@ -404,7 +404,7 @@ struct DisplayUnchecked<'a, N: NetworkValidation>(&'a Address); #[cfg(feature = "serde")] impl 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 +433,7 @@ impl<'de, U: NetworkValidationUnchecked> serde::Deserialize<'de> for Address { // We know that `U` is only ever `NetworkUnchecked` but the compiler does not. let address = v.parse::>().map_err(E::custom)?; - Ok(Address(address.0, PhantomData::)) + Ok(Address::from_inner(address.into_inner())) } } @@ -454,18 +454,30 @@ impl serde::Serialize for Address { /// Methods on [`Address`] that can be called on both `Address` and /// `Address`. impl Address { + fn from_inner(inner: AddressInner) -> Self { + Address(inner, PhantomData) + } + + fn into_inner(self) -> AddressInner { + self.0 + } + + fn inner(&self) -> &AddressInner { + &self.0 + } + /// 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) } } /// Marks the network of this address as unchecked. - pub fn into_unchecked(self) -> Address { Address(self.0, PhantomData) } + pub fn into_unchecked(self) -> Address { 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 +493,7 @@ impl Address { #[inline] pub fn p2pkh(pk: impl Into, network: impl Into) -> 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 +516,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) -> 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 +589,7 @@ impl Address { /// then you likely do not need this constructor. pub fn from_witness_program(program: WitnessProgram, hrp: impl Into) -> 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 +599,7 @@ impl Address { /// None if unknown, non-standard or related to the future witness version. #[inline] pub fn address_type(&self) -> Option { - match self.0 { + match *self.inner() { AddressInner::P2pkh { .. } => Some(AddressType::P2pkh), AddressInner::P2sh { .. } => Some(AddressType::P2sh), AddressInner::Segwit { ref program, hrp: _ } => @@ -609,7 +621,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 +632,7 @@ impl Address { pub fn pubkey_hash(&self) -> Option { use AddressInner::*; - match self.0 { + match *self.inner() { P2pkh { ref hash, network: _ } => Some(*hash), _ => None, } @@ -630,7 +642,7 @@ impl Address { pub fn script_hash(&self) -> Option { use AddressInner::*; - match self.0 { + match *self.inner() { P2sh { ref hash, network: _ } => Some(*hash), _ => None, } @@ -640,7 +652,7 @@ impl Address { pub fn witness_program(&self) -> Option { use AddressInner::*; - match self.0 { + match *self.inner() { Segwit { ref program, hrp: _ } => Some(*program), _ => None, } @@ -689,7 +701,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 +768,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] == >::as_ref(hash), P2sh { ref hash, network: _ } if script.is_p2sh() => @@ -777,7 +789,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(), @@ -817,7 +829,7 @@ impl Address { /// ``` 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 +894,7 @@ impl Address { /// 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, Bech32Error> { @@ -894,7 +906,7 @@ impl Address { 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 +939,7 @@ impl Address { invalid => return Err(InvalidLegacyPrefixError { invalid }.into()), }; - Ok(Address(inner, PhantomData)) + Ok(Address::from_inner(inner)) } } @@ -938,16 +950,16 @@ impl From
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 fmt::Debug for Address { 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(")?; - fmt::Display::fmt(&self.0, f)?; + fmt::Display::fmt(&self.inner(), f)?; write!(f, ")") } } @@ -975,10 +987,10 @@ impl FromStr for Address { 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::)) + 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::)) + Ok(Address::from_inner(address.into_inner())) } else { let hrp = match s.rfind('1') { Some(pos) => &s[..pos],