diff --git a/bitcoin/src/address/error.rs b/bitcoin/src/address/error.rs index 4f4f1f1e..51d137bb 100644 --- a/bitcoin/src/address/error.rs +++ b/bitcoin/src/address/error.rs @@ -12,19 +12,6 @@ use crate::{base58, Network}; #[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] pub enum Error { - /// Base58 encoding error. - Base58(base58::Error), - /// Bech32 encoding error. - Bech32(bech32::Error), - /// The bech32 payload was empty. - EmptyBech32Payload, - /// The wrong checksum algorithm was used. See BIP-0350. - InvalidBech32Variant { - /// Bech32 variant that is required by the used Witness version. - expected: bech32::Variant, - /// The actual Bech32 variant encoded in the address representation. - found: bech32::Variant, - }, /// A witness version construction error. WitnessVersion(witness_version::TryFromError), /// A witness program error. @@ -51,14 +38,6 @@ impl fmt::Display for Error { use Error::*; match *self { - Base58(ref e) => write_err!(f, "base58 address encoding error"; e), - Bech32(ref e) => write_err!(f, "bech32 address encoding error"; e), - EmptyBech32Payload => write!(f, "the bech32 payload was empty"), - InvalidBech32Variant { expected, found } => write!( - f, - "invalid bech32 checksum variant found {:?} when {:?} was expected", - found, expected - ), WitnessVersion(ref e) => write_err!(f, "witness version construction error"; e), WitnessProgram(ref e) => write_err!(f, "witness program error"; e), UncompressedPubkey => @@ -84,13 +63,9 @@ impl std::error::Error for Error { use Error::*; match self { - Base58(e) => Some(e), - Bech32(e) => Some(e), WitnessVersion(e) => Some(e), WitnessProgram(e) => Some(e), - EmptyBech32Payload - | InvalidBech32Variant { .. } - | UncompressedPubkey + UncompressedPubkey | ExcessiveScriptSize | UnrecognizedScript | NetworkValidation { .. } => None, @@ -98,14 +73,6 @@ impl std::error::Error for Error { } } -impl From for Error { - fn from(e: base58::Error) -> Error { Error::Base58(e) } -} - -impl From for Error { - fn from(e: bech32::Error) -> Error { Error::Bech32(e) } -} - impl From for Error { fn from(e: witness_version::TryFromError) -> Error { Error::WitnessVersion(e) } } @@ -125,3 +92,76 @@ impl fmt::Display for UnknownAddressTypeError { } impl_std_error!(UnknownAddressTypeError); + +/// Address parsing error. +#[derive(Debug, PartialEq, Eq, Clone)] +#[non_exhaustive] +pub enum ParseError { + /// Base58 error. + Base58(base58::Error), + /// Bech32 error. + Bech32(bech32::Error), + /// The bech32 payload was empty. + EmptyBech32Payload, + /// The wrong checksum algorithm was used. See BIP-0350. + InvalidBech32Variant { + /// Bech32 variant that is required by the used Witness version. + expected: bech32::Variant, + /// The actual Bech32 variant encoded in the address representation. + found: bech32::Variant, + }, + /// A witness version conversion/parsing error. + WitnessVersion(witness_version::TryFromError), + /// A witness program error. + WitnessProgram(witness_program::Error), +} + +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use ParseError::*; + + match *self { + Base58(ref e) => write_err!(f, "base58 error"; e), + Bech32(ref e) => write_err!(f, "bech32 error"; e), + EmptyBech32Payload => write!(f, "the bech32 payload was empty"), + InvalidBech32Variant { expected, found } => write!( + f, + "invalid bech32 checksum variant found {:?} when {:?} was expected", + found, expected + ), + WitnessVersion(ref e) => write_err!(f, "witness version conversion/parsing error"; e), + WitnessProgram(ref e) => write_err!(f, "witness program error"; e), + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ParseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use ParseError::*; + + match *self { + Base58(ref e) => Some(e), + Bech32(ref e) => Some(e), + WitnessVersion(ref e) => Some(e), + WitnessProgram(ref e) => Some(e), + EmptyBech32Payload | InvalidBech32Variant { .. } => None, + } + } +} + +impl From for ParseError { + fn from(e: base58::Error) -> Self { Self::Base58(e) } +} + +impl From for ParseError { + fn from(e: bech32::Error) -> Self { Self::Bech32(e) } +} + +impl From for ParseError { + fn from(e: witness_version::TryFromError) -> Self { Self::WitnessVersion(e) } +} + +impl From for ParseError { + fn from(e: witness_program::Error) -> Self { Self::WitnessProgram(e) } +} diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs index 81f650d3..3d19d06a 100644 --- a/bitcoin/src/address/mod.rs +++ b/bitcoin/src/address/mod.rs @@ -50,7 +50,7 @@ use crate::taproot::TapNodeHash; /// Error code for the address module. pub mod error; -pub use self::error::{Error, UnknownAddressTypeError}; +pub use self::error::{Error, ParseError, UnknownAddressTypeError}; /// The different types of addresses. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -800,9 +800,9 @@ fn find_bech32_prefix(bech32: &str) -> &str { /// Address can be parsed only with `NetworkUnchecked`. impl FromStr for Address { - type Err = Error; + type Err = ParseError; - fn from_str(s: &str) -> Result, Error> { + fn from_str(s: &str) -> Result { // try bech32 let bech32_network = match find_bech32_prefix(s) { // note that upper or lowercase is allowed but NOT mixed case @@ -815,7 +815,7 @@ impl FromStr for Address { // decode as bech32 let (_, payload, variant) = bech32::decode(s)?; if payload.is_empty() { - return Err(Error::EmptyBech32Payload); + return Err(ParseError::EmptyBech32Payload); } // Get the script version and program (converted from 5-bit to 8-bit) @@ -829,7 +829,7 @@ impl FromStr for Address { // Encoding check let expected = version.bech32_variant(); if expected != variant { - return Err(Error::InvalidBech32Variant { expected, found: variant }); + return Err(ParseError::InvalidBech32Variant { expected, found: variant }); } return Ok(Address::new(network, Payload::WitnessProgram(witness_program))); @@ -837,11 +837,11 @@ impl FromStr for Address { // Base58 if s.len() > 50 { - return Err(Error::Base58(base58::Error::InvalidLength(s.len() * 11 / 15))); + return Err(ParseError::Base58(base58::Error::InvalidLength(s.len() * 11 / 15))); } let data = base58::decode_check(s)?; if data.len() != 21 { - return Err(Error::Base58(base58::Error::InvalidLength(data.len()))); + return Err(ParseError::Base58(base58::Error::InvalidLength(data.len()))); } let (network, payload) = match data[0] { @@ -853,7 +853,7 @@ impl FromStr for Address { (Network::Testnet, Payload::PubkeyHash(PubkeyHash::from_slice(&data[1..]).unwrap())), SCRIPT_ADDRESS_PREFIX_TEST => (Network::Testnet, Payload::ScriptHash(ScriptHash::from_slice(&data[1..]).unwrap())), - x => return Err(Error::Base58(base58::Error::InvalidAddressVersion(x))), + x => return Err(ParseError::Base58(base58::Error::InvalidAddressVersion(x))), }; Ok(Address::new(network, payload))