2023-10-10 04:08:50 +00:00
|
|
|
//! Error code for the address module.
|
|
|
|
|
2023-08-04 00:07:59 +00:00
|
|
|
use core::fmt;
|
|
|
|
|
|
|
|
use internals::write_err;
|
|
|
|
|
|
|
|
use crate::address::{Address, NetworkUnchecked};
|
|
|
|
use crate::blockdata::script::{witness_program, witness_version};
|
2024-02-20 05:11:14 +00:00
|
|
|
use crate::prelude::*;
|
2024-02-25 21:45:58 +00:00
|
|
|
use crate::Network;
|
2023-08-04 00:07:59 +00:00
|
|
|
|
2024-02-22 20:18:59 +00:00
|
|
|
/// Error while generating address from script.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2024-02-22 22:14:12 +00:00
|
|
|
#[non_exhaustive]
|
2024-02-22 20:18:59 +00:00
|
|
|
pub enum FromScriptError {
|
|
|
|
/// Script is not a p2pkh, p2sh or witness program.
|
|
|
|
UnrecognizedScript,
|
|
|
|
/// A witness program error.
|
|
|
|
WitnessProgram(witness_program::Error),
|
|
|
|
/// A witness version construction error.
|
|
|
|
WitnessVersion(witness_version::TryFromError),
|
|
|
|
}
|
|
|
|
|
2024-02-28 23:21:50 +00:00
|
|
|
internals::impl_from_infallible!(FromScriptError);
|
|
|
|
|
2024-02-22 20:18:59 +00:00
|
|
|
impl fmt::Display for FromScriptError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
use FromScriptError::*;
|
|
|
|
|
|
|
|
match *self {
|
|
|
|
WitnessVersion(ref e) => write_err!(f, "witness version construction error"; e),
|
|
|
|
WitnessProgram(ref e) => write_err!(f, "witness program error"; e),
|
|
|
|
UnrecognizedScript => write!(f, "script is not a p2pkh, p2sh or witness program"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
impl std::error::Error for FromScriptError {
|
|
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
|
|
use FromScriptError::*;
|
|
|
|
|
2024-02-22 22:14:12 +00:00
|
|
|
match *self {
|
2024-02-22 20:18:59 +00:00
|
|
|
UnrecognizedScript => None,
|
2024-02-22 22:14:12 +00:00
|
|
|
WitnessVersion(ref e) => Some(e),
|
|
|
|
WitnessProgram(ref e) => Some(e),
|
2024-02-22 20:18:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<witness_program::Error> for FromScriptError {
|
2024-02-22 22:14:12 +00:00
|
|
|
fn from(e : witness_program::Error) -> Self { Self::WitnessProgram(e) }
|
2024-02-22 20:18:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<witness_version::TryFromError> for FromScriptError {
|
2024-02-22 22:14:12 +00:00
|
|
|
fn from(e: witness_version::TryFromError) -> Self { Self::WitnessVersion(e) }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Error while generating address from a p2sh script.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub enum P2shError {
|
|
|
|
/// Address size more than 520 bytes is not allowed.
|
|
|
|
ExcessiveScriptSize,
|
|
|
|
}
|
|
|
|
|
2024-02-28 23:21:50 +00:00
|
|
|
internals::impl_from_infallible!(P2shError);
|
|
|
|
|
2024-02-22 22:14:12 +00:00
|
|
|
impl fmt::Display for P2shError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
use P2shError::*;
|
|
|
|
|
|
|
|
match *self {
|
|
|
|
ExcessiveScriptSize => write!(f, "script size exceed 520 bytes"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
impl std::error::Error for P2shError {
|
|
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
|
|
use P2shError::*;
|
|
|
|
|
|
|
|
match self {
|
|
|
|
ExcessiveScriptSize => None,
|
|
|
|
}
|
|
|
|
}
|
2024-02-22 20:18:59 +00:00
|
|
|
}
|
|
|
|
|
2023-08-04 00:29:27 +00:00
|
|
|
/// Address type is either invalid or not supported in rust-bitcoin.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
Make error types uniform
On our way to v1.0.0 we are defining a standard for our error types,
this includes:
- Uses the following derives (unless not possible, usually because of `io::Error`)
`#[derive(Debug, Clone, PartialEq, Eq)]`
- Has `non_exhaustive` unless we really know we can commit to not adding
anything.
Furthermore, we are trying to make the codebase easy to read. Error code
is write-once-read-many (well it should be) so if we make all the error
code super uniform the users can flick to an error and quickly see what
it includes. In an effort to achieve this I have made up a style and
over recent times have change much of the error code to that new style,
this PR audits _all_ error types in the code base and enforces the
style, specifically:
- Is layed out: definition, [impl block], Display impl, error::Error impl, From impls
- `error::Error` impl matches on enum even if it returns `None` for all variants
- Display/Error impls import enum variants locally
- match uses *self and `ref e`
- error::Error variants that return `Some` come first, `None` after
Re: non_exhaustive
To make dev and review easier I have added `non_exhaustive` to _every_
error type. We can then remove it error by error as we see fit. This is
because it takes a bit of thinking to do and review where as this patch
should not take much brain power to review.
2023-10-04 02:55:45 +00:00
|
|
|
#[non_exhaustive]
|
2023-08-04 00:29:27 +00:00
|
|
|
pub struct UnknownAddressTypeError(pub String);
|
|
|
|
|
|
|
|
impl fmt::Display for UnknownAddressTypeError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write_err!(f, "failed to parse {} as address type", self.0; self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-04 01:35:01 +00:00
|
|
|
#[cfg(feature = "std")]
|
|
|
|
impl std::error::Error for UnknownAddressTypeError {
|
|
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
|
|
|
|
}
|
2023-08-04 00:36:48 +00:00
|
|
|
|
|
|
|
/// Address parsing error.
|
Make error types uniform
On our way to v1.0.0 we are defining a standard for our error types,
this includes:
- Uses the following derives (unless not possible, usually because of `io::Error`)
`#[derive(Debug, Clone, PartialEq, Eq)]`
- Has `non_exhaustive` unless we really know we can commit to not adding
anything.
Furthermore, we are trying to make the codebase easy to read. Error code
is write-once-read-many (well it should be) so if we make all the error
code super uniform the users can flick to an error and quickly see what
it includes. In an effort to achieve this I have made up a style and
over recent times have change much of the error code to that new style,
this PR audits _all_ error types in the code base and enforces the
style, specifically:
- Is layed out: definition, [impl block], Display impl, error::Error impl, From impls
- `error::Error` impl matches on enum even if it returns `None` for all variants
- Display/Error impls import enum variants locally
- match uses *self and `ref e`
- error::Error variants that return `Some` come first, `None` after
Re: non_exhaustive
To make dev and review easier I have added `non_exhaustive` to _every_
error type. We can then remove it error by error as we see fit. This is
because it takes a bit of thinking to do and review where as this patch
should not take much brain power to review.
2023-10-04 02:55:45 +00:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
2023-08-04 00:36:48 +00:00
|
|
|
#[non_exhaustive]
|
|
|
|
pub enum ParseError {
|
|
|
|
/// Base58 error.
|
|
|
|
Base58(base58::Error),
|
2023-08-04 01:05:15 +00:00
|
|
|
/// Bech32 segwit decoding error.
|
2023-10-09 18:17:26 +00:00
|
|
|
Bech32(bech32::segwit::DecodeError),
|
2023-08-04 00:36:48 +00:00
|
|
|
/// A witness version conversion/parsing error.
|
|
|
|
WitnessVersion(witness_version::TryFromError),
|
|
|
|
/// A witness program error.
|
|
|
|
WitnessProgram(witness_program::Error),
|
2023-05-04 02:03:25 +00:00
|
|
|
/// Tried to parse an unknown HRP.
|
|
|
|
UnknownHrp(UnknownHrpError),
|
2024-02-15 05:26:55 +00:00
|
|
|
/// Legacy address is too long.
|
|
|
|
LegacyAddressTooLong(LegacyAddressTooLongError),
|
|
|
|
/// Invalid base58 payload data length for legacy address.
|
|
|
|
InvalidBase58PayloadLength(InvalidBase58PayloadLengthError),
|
|
|
|
/// Invalid legacy address prefix in base58 data payload.
|
|
|
|
InvalidLegacyPrefix(InvalidLegacyPrefixError),
|
2023-08-04 00:36:48 +00:00
|
|
|
}
|
|
|
|
|
2024-02-28 23:21:50 +00:00
|
|
|
internals::impl_from_infallible!(ParseError);
|
|
|
|
|
2023-08-04 00:36:48 +00:00
|
|
|
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),
|
2023-08-04 01:05:15 +00:00
|
|
|
Bech32(ref e) => write_err!(f, "bech32 segwit decoding error"; e),
|
2023-08-04 00:36:48 +00:00
|
|
|
WitnessVersion(ref e) => write_err!(f, "witness version conversion/parsing error"; e),
|
|
|
|
WitnessProgram(ref e) => write_err!(f, "witness program error"; e),
|
2023-05-04 02:03:25 +00:00
|
|
|
UnknownHrp(ref e) => write_err!(f, "tried to parse an unknown hrp"; e),
|
2024-02-15 05:26:55 +00:00
|
|
|
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),
|
2023-08-04 00:36:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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),
|
2023-05-04 02:03:25 +00:00
|
|
|
UnknownHrp(ref e) => Some(e),
|
2024-02-15 05:26:55 +00:00
|
|
|
LegacyAddressTooLong(ref e) => Some(e),
|
|
|
|
InvalidBase58PayloadLength(ref e) => Some(e),
|
|
|
|
InvalidLegacyPrefix(ref e) => Some(e),
|
2023-08-04 00:36:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<base58::Error> for ParseError {
|
|
|
|
fn from(e: base58::Error) -> Self { Self::Base58(e) }
|
|
|
|
}
|
|
|
|
|
2023-10-09 18:17:26 +00:00
|
|
|
impl From<bech32::segwit::DecodeError> for ParseError {
|
|
|
|
fn from(e: bech32::segwit::DecodeError) -> Self { Self::Bech32(e) }
|
2023-08-04 00:36:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl From<witness_version::TryFromError> for ParseError {
|
|
|
|
fn from(e: witness_version::TryFromError) -> Self { Self::WitnessVersion(e) }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<witness_program::Error> for ParseError {
|
|
|
|
fn from(e: witness_program::Error) -> Self { Self::WitnessProgram(e) }
|
|
|
|
}
|
2023-05-04 02:03:25 +00:00
|
|
|
|
|
|
|
impl From<UnknownHrpError> for ParseError {
|
|
|
|
fn from(e: UnknownHrpError) -> Self { Self::UnknownHrp(e) }
|
|
|
|
}
|
|
|
|
|
2024-02-15 05:26:55 +00:00
|
|
|
impl From<LegacyAddressTooLongError> for ParseError {
|
|
|
|
fn from(e: LegacyAddressTooLongError) -> Self { Self::LegacyAddressTooLong(e) }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<InvalidBase58PayloadLengthError> for ParseError {
|
|
|
|
fn from(e: InvalidBase58PayloadLengthError) -> Self { Self::InvalidBase58PayloadLength(e) }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<InvalidLegacyPrefixError> for ParseError {
|
|
|
|
fn from(e: InvalidLegacyPrefixError) -> Self { Self::InvalidLegacyPrefix(e) }
|
|
|
|
}
|
|
|
|
|
2023-05-04 02:03:25 +00:00
|
|
|
/// Unknown HRP error.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub struct UnknownHrpError(pub String);
|
|
|
|
|
|
|
|
impl fmt::Display for UnknownHrpError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "unknown hrp: {}", self.0) }
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
impl std::error::Error for UnknownHrpError {
|
|
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
|
|
|
|
}
|
2024-02-15 05:26:55 +00:00
|
|
|
|
2024-03-18 22:08:54 +00:00
|
|
|
/// 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 {}
|
|
|
|
|
2024-02-15 05:26:55 +00:00
|
|
|
/// Decoded base58 data was an invalid length.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub struct InvalidBase58PayloadLengthError {
|
|
|
|
/// The base58 payload length we got after decoding address string.
|
|
|
|
pub(crate) length: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvalidBase58PayloadLengthError {
|
|
|
|
/// Returns the invalid payload length.
|
|
|
|
pub fn invalid_base58_payload_length(&self) -> usize { self.length }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for InvalidBase58PayloadLengthError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "decoded base58 data was an invalid length: {} (expected 21)", self.length)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
impl std::error::Error for InvalidBase58PayloadLengthError {}
|
|
|
|
|
|
|
|
/// Legacy base58 address was too long, max 50 characters.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub struct LegacyAddressTooLongError {
|
|
|
|
/// The length of the legacy address.
|
|
|
|
pub(crate) length: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl LegacyAddressTooLongError {
|
|
|
|
/// Returns the invalid legacy address length.
|
|
|
|
pub fn invalid_legcay_address_length(&self) -> usize { self.length }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for LegacyAddressTooLongError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "legacy address is too long: {} (max 50 characters)", self.length)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
impl std::error::Error for LegacyAddressTooLongError {}
|
|
|
|
|
|
|
|
/// Invalid legacy address prefix in decoded base58 data.
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
|
|
pub struct InvalidLegacyPrefixError {
|
|
|
|
/// The invalid prefix byte.
|
|
|
|
pub(crate) invalid: u8,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InvalidLegacyPrefixError {
|
|
|
|
/// Returns the invalid prefix.
|
|
|
|
pub fn invalid_legacy_address_prefix(&self) -> u8 { self.invalid }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for InvalidLegacyPrefixError {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "invalid legacy address prefix in decoded base58 data {}", self.invalid)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "std")]
|
|
|
|
impl std::error::Error for InvalidLegacyPrefixError {}
|