From 9a7b1c232b494dccdce091a46d916cc411a612a1 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Sun, 27 Oct 2024 08:29:22 +1100 Subject: [PATCH] Wrap the bech32 decoding error We do not want `bech32` to appear in the public API of the `address` module in case `bech32` does not stabalize before the soon-to-be-created `address` crates does. We already had a go at removing it but forgot one error variant - wrap the variant in a new type with a private inner bech32 error field. --- bitcoin/src/address/error.rs | 24 +++++++++++++++++++----- bitcoin/src/address/mod.rs | 5 +++-- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/bitcoin/src/address/error.rs b/bitcoin/src/address/error.rs index 58d0cd1e5..b972f7b12 100644 --- a/bitcoin/src/address/error.rs +++ b/bitcoin/src/address/error.rs @@ -166,7 +166,7 @@ impl std::error::Error for NetworkValidationError {} #[non_exhaustive] pub enum Bech32Error { /// Parse segwit Bech32 error. - ParseBech32(bech32::segwit::DecodeError), + ParseBech32(ParseBech32Error), /// A witness version conversion/parsing error. WitnessVersion(witness_version::TryFromError), /// A witness program error. @@ -204,10 +204,6 @@ impl std::error::Error for Bech32Error { } } -impl From for Bech32Error { - fn from(e: bech32::segwit::DecodeError) -> Self { Self::ParseBech32(e) } -} - impl From for Bech32Error { fn from(e: witness_version::TryFromError) -> Self { Self::WitnessVersion(e) } } @@ -220,6 +216,24 @@ impl From for Bech32Error { fn from(e: UnknownHrpError) -> Self { Self::UnknownHrp(e) } } +/// Bech32 parsing related error. +// This wrapper exists because we do not want to expose the `bech32` crate in our public API. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ParseBech32Error(pub(crate) bech32::segwit::DecodeError); + +internals::impl_from_infallible!(ParseBech32Error); + +impl fmt::Display for ParseBech32Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write_err!(f, "bech32 parsing error"; self.0) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ParseBech32Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.0) } +} + /// Base58 related error. #[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs index 87744113b..9eac89094 100644 --- a/bitcoin/src/address/mod.rs +++ b/bitcoin/src/address/mod.rs @@ -61,7 +61,7 @@ use crate::taproot::TapNodeHash; pub use self::error::{ Base58Error, Bech32Error, FromScriptError, InvalidBase58PayloadLengthError, InvalidLegacyPrefixError, LegacyAddressTooLongError, NetworkValidationError, - ParseError, UnknownAddressTypeError, UnknownHrpError + ParseError, UnknownAddressTypeError, UnknownHrpError, ParseBech32Error, }; /// The different types of addresses. @@ -803,7 +803,8 @@ impl Address { /// Parse a bech32 Address string pub fn from_bech32_str(s: &str) -> Result, Bech32Error> { - let (hrp, witness_version, data) = bech32::segwit::decode(s)?; + let (hrp, witness_version, data) = bech32::segwit::decode(s) + .map_err(|e| Bech32Error::ParseBech32(ParseBech32Error(e)))?; let version = WitnessVersion::try_from(witness_version.to_u8())?; let program = WitnessProgram::new(version, &data) .expect("bech32 guarantees valid program length for witness");