diff --git a/bitcoin/src/address/error.rs b/bitcoin/src/address/error.rs index 14cac051..be0a573d 100644 --- a/bitcoin/src/address/error.rs +++ b/bitcoin/src/address/error.rs @@ -123,6 +123,8 @@ pub enum ParseError { InvalidBase58PayloadLength(InvalidBase58PayloadLengthError), /// Invalid legacy address prefix in base58 data payload. InvalidLegacyPrefix(InvalidLegacyPrefixError), + /// Address's network differs from required one. + NetworkValidation(NetworkValidationError), } internals::impl_from_infallible!(ParseError); @@ -140,6 +142,7 @@ impl fmt::Display for ParseError { LegacyAddressTooLong(ref e) => write_err!(f, "legacy address base58 string"; e), InvalidBase58PayloadLength(ref e) => write_err!(f, "legacy address base58 data"; e), InvalidLegacyPrefix(ref e) => write_err!(f, "legacy address base58 prefix"; e), + NetworkValidation(ref e) => write_err!(f, "validation error"; e), } } } @@ -158,6 +161,7 @@ impl std::error::Error for ParseError { LegacyAddressTooLong(ref e) => Some(e), InvalidBase58PayloadLength(ref e) => Some(e), InvalidLegacyPrefix(ref e) => Some(e), + NetworkValidation(ref e) => Some(e), } } } @@ -194,6 +198,10 @@ impl From for ParseError { fn from(e: InvalidLegacyPrefixError) -> Self { Self::InvalidLegacyPrefix(e) } } +impl From for ParseError { + fn from(e: NetworkValidationError) -> Self { Self::NetworkValidation(e) } +} + /// Unknown HRP error. #[derive(Debug, Clone, PartialEq, Eq)] #[non_exhaustive] diff --git a/bitcoin/src/address/mod.rs b/bitcoin/src/address/mod.rs index df1c7906..1af1580c 100644 --- a/bitcoin/src/address/mod.rs +++ b/bitcoin/src/address/mod.rs @@ -667,12 +667,50 @@ impl Address { /// /// For details about this mechanism, see section [*Parsing addresses*](Address#parsing-addresses) /// on [`Address`]. + /// + /// # Errors + /// + /// This function only ever returns the [`ParseError::NetworkValidation`] variant of + /// `ParseError`. This is not how we normally implement errors in this library but + /// `require_network` is not a typical function, it is conceptually part of string parsing. + /// + /// # Examples + /// + /// ``` + /// use bitcoin::address::{NetworkChecked, NetworkUnchecked, ParseError}; + /// use bitcoin::{Address, Network}; + /// + /// const ADDR: &str = "bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs"; + /// + /// fn parse_and_validate_address(network: Network) -> Result { + /// let address = ADDR.parse::>()? + /// .require_network(network)?; + /// Ok(address) + /// } + /// + /// fn parse_and_validate_address_combinator(network: Network) -> Result { + /// let address = ADDR.parse::>() + /// .and_then(|a| a.require_network(network))?; + /// Ok(address) + /// } + /// + /// fn parse_and_validate_address_show_types(network: Network) -> Result { + /// let address: Address = ADDR.parse::>()? + /// .require_network(network)?; + /// Ok(address) + /// } + /// + /// let network = Network::Bitcoin; // Don't hard code network in applications. + /// let _ = parse_and_validate_address(network).unwrap(); + /// let _ = parse_and_validate_address_combinator(network).unwrap(); + /// let _ = parse_and_validate_address_show_types(network).unwrap(); + /// ``` #[inline] - pub fn require_network(self, required: Network) -> Result { + pub fn require_network(self, required: Network) -> Result { if self.is_valid_for_network(required) { Ok(self.assume_checked()) } else { - Err(NetworkValidationError { required, address: self }) + Err(NetworkValidationError { required, address: self }.into()) } }