Merge rust-bitcoin/rust-bitcoin#2610: Add a validation variant to `ParseError`
a7a99e06bb
Add a validation variant to `ParseError` (Tobin C. Harding)d5c52618a9
Move NetworkValidationError within file (Tobin C. Harding) Pull request description: As requested, return `ParseError` from `Address<NetworkUnchecked>::require_network`. - Patch 1: Preparatory refactor - Patch 2: Add the variant. Replaces #2593. Close: #2507 ACKs for top commit: sanket1729: ACKa7a99e06bb
. apoelstra: ACKa7a99e06bb
Tree-SHA512: 08b290e5f11a5d787918a5b851f98efbeff5bd20a2838e00564f03bb242af3640da663ddc42473419255fff6f64280eaf2595706504676b3228ac81212ea7cf2
This commit is contained in:
commit
92d8f70544
|
@ -9,26 +9,6 @@ use crate::blockdata::script::{witness_program, witness_version};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::Network;
|
use crate::Network;
|
||||||
|
|
||||||
/// Address's network differs from required one.
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct NetworkValidationError {
|
|
||||||
/// Network that was required.
|
|
||||||
pub(crate) required: Network,
|
|
||||||
/// The address itself.
|
|
||||||
pub(crate) address: Address<NetworkUnchecked>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for NetworkValidationError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "address ")?;
|
|
||||||
fmt::Display::fmt(&self.address.0, f)?;
|
|
||||||
write!(f, " is not valid on {}", self.required)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl std::error::Error for NetworkValidationError {}
|
|
||||||
|
|
||||||
/// Error while generating address from script.
|
/// Error while generating address from script.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
@ -143,6 +123,8 @@ pub enum ParseError {
|
||||||
InvalidBase58PayloadLength(InvalidBase58PayloadLengthError),
|
InvalidBase58PayloadLength(InvalidBase58PayloadLengthError),
|
||||||
/// Invalid legacy address prefix in base58 data payload.
|
/// Invalid legacy address prefix in base58 data payload.
|
||||||
InvalidLegacyPrefix(InvalidLegacyPrefixError),
|
InvalidLegacyPrefix(InvalidLegacyPrefixError),
|
||||||
|
/// Address's network differs from required one.
|
||||||
|
NetworkValidation(NetworkValidationError),
|
||||||
}
|
}
|
||||||
|
|
||||||
internals::impl_from_infallible!(ParseError);
|
internals::impl_from_infallible!(ParseError);
|
||||||
|
@ -160,6 +142,7 @@ impl fmt::Display for ParseError {
|
||||||
LegacyAddressTooLong(ref e) => write_err!(f, "legacy address base58 string"; e),
|
LegacyAddressTooLong(ref e) => write_err!(f, "legacy address base58 string"; e),
|
||||||
InvalidBase58PayloadLength(ref e) => write_err!(f, "legacy address base58 data"; e),
|
InvalidBase58PayloadLength(ref e) => write_err!(f, "legacy address base58 data"; e),
|
||||||
InvalidLegacyPrefix(ref e) => write_err!(f, "legacy address base58 prefix"; e),
|
InvalidLegacyPrefix(ref e) => write_err!(f, "legacy address base58 prefix"; e),
|
||||||
|
NetworkValidation(ref e) => write_err!(f, "validation error"; e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,6 +161,7 @@ impl std::error::Error for ParseError {
|
||||||
LegacyAddressTooLong(ref e) => Some(e),
|
LegacyAddressTooLong(ref e) => Some(e),
|
||||||
InvalidBase58PayloadLength(ref e) => Some(e),
|
InvalidBase58PayloadLength(ref e) => Some(e),
|
||||||
InvalidLegacyPrefix(ref e) => Some(e),
|
InvalidLegacyPrefix(ref e) => Some(e),
|
||||||
|
NetworkValidation(ref e) => Some(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,6 +198,10 @@ impl From<InvalidLegacyPrefixError> for ParseError {
|
||||||
fn from(e: InvalidLegacyPrefixError) -> Self { Self::InvalidLegacyPrefix(e) }
|
fn from(e: InvalidLegacyPrefixError) -> Self { Self::InvalidLegacyPrefix(e) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<NetworkValidationError> for ParseError {
|
||||||
|
fn from(e: NetworkValidationError) -> Self { Self::NetworkValidation(e) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Unknown HRP error.
|
/// Unknown HRP error.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
|
@ -228,6 +216,26 @@ impl std::error::Error for UnknownHrpError {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Address's network differs from required one.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct NetworkValidationError {
|
||||||
|
/// Network that was required.
|
||||||
|
pub(crate) required: Network,
|
||||||
|
/// The address itself.
|
||||||
|
pub(crate) address: Address<NetworkUnchecked>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for NetworkValidationError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "address ")?;
|
||||||
|
fmt::Display::fmt(&self.address.0, f)?;
|
||||||
|
write!(f, " is not valid on {}", self.required)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for NetworkValidationError {}
|
||||||
|
|
||||||
/// Decoded base58 data was an invalid length.
|
/// Decoded base58 data was an invalid length.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct InvalidBase58PayloadLengthError {
|
pub struct InvalidBase58PayloadLengthError {
|
||||||
|
|
|
@ -667,12 +667,50 @@ impl Address<NetworkUnchecked> {
|
||||||
///
|
///
|
||||||
/// For details about this mechanism, see section [*Parsing addresses*](Address#parsing-addresses)
|
/// For details about this mechanism, see section [*Parsing addresses*](Address#parsing-addresses)
|
||||||
/// on [`Address`].
|
/// 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<Address, ParseError> {
|
||||||
|
/// let address = ADDR.parse::<Address<_>>()?
|
||||||
|
/// .require_network(network)?;
|
||||||
|
/// Ok(address)
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn parse_and_validate_address_combinator(network: Network) -> Result<Address, ParseError> {
|
||||||
|
/// let address = ADDR.parse::<Address<_>>()
|
||||||
|
/// .and_then(|a| a.require_network(network))?;
|
||||||
|
/// Ok(address)
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn parse_and_validate_address_show_types(network: Network) -> Result<Address, ParseError> {
|
||||||
|
/// let address: Address<NetworkChecked> = ADDR.parse::<Address<NetworkUnchecked>>()?
|
||||||
|
/// .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]
|
#[inline]
|
||||||
pub fn require_network(self, required: Network) -> Result<Address, NetworkValidationError> {
|
pub fn require_network(self, required: Network) -> Result<Address, ParseError> {
|
||||||
if self.is_valid_for_network(required) {
|
if self.is_valid_for_network(required) {
|
||||||
Ok(self.assume_checked())
|
Ok(self.assume_checked())
|
||||||
} else {
|
} else {
|
||||||
Err(NetworkValidationError { required, address: self })
|
Err(NetworkValidationError { required, address: self }.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue