Merge rust-bitcoin/rust-bitcoin#2101: Audit error types code base wide

10374af75c Make error types uniform (Tobin C. Harding)
43d3306822 Use explicit error::Error impl instead of the default (Tobin C. Harding)
2512dbafc2 Remove impl_std_error macro (Tobin C. Harding)
6933ca4fc2 Add suffix to HiddenNodes error type (Tobin C. Harding)
2b40ea24fb Add suffix to IncompleteBuilder error type (Tobin C. Harding)
f41416a0ea Add suffix to UnknownMagic error type (Tobin C. Harding)
5658dac024 Add suffix to UnknownChainHash error type (Tobin C. Harding)
2fb71dd943 Move p2p error types to bottom of file (Tobin C. Harding)
39314ad52f Move error code to match conventional layout (Tobin C. Harding)

Pull request description:

  PR aims to achieve two things:
  - Make error code brain dead easy to read
  - Get error code closer to being ready for v1.0

  The first 8 patches are pretty basic, and are broken up into really small changes. The last patch is much bigger, it has a long git log to explain it but reviewing should not take too much brain power.

  This PR does not introduce anything new, it just applies what we have been doing recently with errors. Before v1.0.0 others will likely want to re go over all the error types. As such I believe this PR can be merged under the one ack carve-out.

  ### TODOs (future PRs)

  We have a few errors that still need splitting up:

  - Split up `merkle_tree::block::MerkleBlockError`
  - Split up `psbt::error::Error`
  - Split up `IncompleteBuilderError`

  Also, all error From's should probably have `#[inline]`, I noticed late in the process and did not have the heart to visit every error again.

ACKs for top commit:
  apoelstra:
    ACK 10374af75c
  clarkmoody:
    ACK 10374af75c

Tree-SHA512: 4f4f3533f42dc11af8e7978f3272752bb56d12a68199752ed4af0c02a46a87892b55c695b7007bc3d0bdf389493068d068e2be1780e8c3008815efec3a02eedf
This commit is contained in:
Andrew Poelstra 2023-10-06 14:06:05 +00:00
commit 3743f2743b
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
35 changed files with 373 additions and 278 deletions

View File

@ -4,7 +4,6 @@ use internals::write_err;
use crate::address::{Address, NetworkUnchecked}; use crate::address::{Address, NetworkUnchecked};
use crate::blockdata::script::{witness_program, witness_version}; use crate::blockdata::script::{witness_program, witness_version};
use crate::error::impl_std_error;
use crate::prelude::String; use crate::prelude::String;
use crate::{base58, Network}; use crate::{base58, Network};
@ -83,6 +82,7 @@ impl From<witness_program::Error> for Error {
/// Address type is either invalid or not supported in rust-bitcoin. /// Address type is either invalid or not supported in rust-bitcoin.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct UnknownAddressTypeError(pub String); pub struct UnknownAddressTypeError(pub String);
impl fmt::Display for UnknownAddressTypeError { impl fmt::Display for UnknownAddressTypeError {
@ -91,10 +91,13 @@ impl fmt::Display for UnknownAddressTypeError {
} }
} }
impl_std_error!(UnknownAddressTypeError); #[cfg(feature = "std")]
impl std::error::Error for UnknownAddressTypeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
/// Address parsing error. /// Address parsing error.
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
pub enum ParseError { pub enum ParseError {
/// Base58 error. /// Base58 error.

View File

@ -160,16 +160,17 @@ pub enum ParseAmountError {
impl fmt::Display for ParseAmountError { impl fmt::Display for ParseAmountError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use ParseAmountError::*;
match *self { match *self {
ParseAmountError::Negative => f.write_str("amount is negative"), Negative => f.write_str("amount is negative"),
ParseAmountError::TooBig => f.write_str("amount is too big"), TooBig => f.write_str("amount is too big"),
ParseAmountError::TooPrecise => f.write_str("amount has a too high precision"), TooPrecise => f.write_str("amount has a too high precision"),
ParseAmountError::InvalidFormat => f.write_str("invalid number format"), InvalidFormat => f.write_str("invalid number format"),
ParseAmountError::InputTooLarge => f.write_str("input string was too large"), InputTooLarge => f.write_str("input string was too large"),
ParseAmountError::InvalidCharacter(c) => write!(f, "invalid character in input: {}", c), InvalidCharacter(c) => write!(f, "invalid character in input: {}", c),
ParseAmountError::UnknownDenomination(ref d) => UnknownDenomination(ref d) => write!(f, "unknown denomination: {}", d),
write!(f, "unknown denomination: {}", d), PossiblyConfusingDenomination(ref d) => {
ParseAmountError::PossiblyConfusingDenomination(ref d) => {
let (letter, upper, lower) = match d.chars().next() { let (letter, upper, lower) = match d.chars().next() {
Some('M') => ('M', "Mega", "milli"), Some('M') => ('M', "Mega", "milli"),
Some('P') => ('P', "Peta", "pico"), Some('P') => ('P', "Peta", "pico"),
@ -185,7 +186,7 @@ impl fmt::Display for ParseAmountError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for ParseAmountError { impl std::error::Error for ParseAmountError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::ParseAmountError::*; use ParseAmountError::*;
match *self { match *self {
Negative Negative

View File

@ -213,16 +213,18 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match *self { match *self {
Error::BadByte(b) => write!(f, "invalid base58 character {:#x}", b), BadByte(b) => write!(f, "invalid base58 character {:#x}", b),
Error::BadChecksum(exp, actual) => BadChecksum(exp, actual) =>
write!(f, "base58ck checksum {:#x} does not match expected {:#x}", actual, exp), write!(f, "base58ck checksum {:#x} does not match expected {:#x}", actual, exp),
Error::InvalidLength(ell) => write!(f, "length {} invalid for this base58 type", ell), InvalidLength(ell) => write!(f, "length {} invalid for this base58 type", ell),
Error::InvalidExtendedKeyVersion(ref v) => InvalidExtendedKeyVersion(ref v) =>
write!(f, "extended key version {:#04x?} is invalid for this base58 type", v), write!(f, "extended key version {:#04x?} is invalid for this base58 type", v),
Error::InvalidAddressVersion(ref v) => InvalidAddressVersion(ref v) =>
write!(f, "address version {} is invalid for this base58 type", v), write!(f, "address version {} is invalid for this base58 type", v),
Error::TooShort(_) => write!(f, "base58ck data not even long enough for a checksum"), TooShort(_) => write!(f, "base58ck data not even long enough for a checksum"),
} }
} }
} }
@ -230,7 +232,7 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match self { match self {
BadByte(_) BadByte(_)

View File

@ -314,7 +314,8 @@ impl Decodable for BlockTransactionsRequest {
/// A transaction index is requested that is out of range from the /// A transaction index is requested that is out of range from the
/// corresponding block. /// corresponding block.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct TxIndexOutOfRangeError(u64); pub struct TxIndexOutOfRangeError(u64);
impl fmt::Display for TxIndexOutOfRangeError { impl fmt::Display for TxIndexOutOfRangeError {
@ -329,7 +330,9 @@ impl fmt::Display for TxIndexOutOfRangeError {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl error::Error for TxIndexOutOfRangeError {} impl error::Error for TxIndexOutOfRangeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
/// A [BlockTransactions] structure is used to provide some of the transactions /// A [BlockTransactions] structure is used to provide some of the transactions
/// in a block, as requested. /// in a block, as requested.

View File

@ -70,9 +70,11 @@ pub enum Error {
impl Display for Error { impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
use Error::*;
match *self { match *self {
Error::UtxoMissing(ref coin) => write!(f, "unresolved UTXO {}", coin), UtxoMissing(ref coin) => write!(f, "unresolved UTXO {}", coin),
Error::Io(ref e) => write_err!(f, "IO error"; e), Io(ref e) => write_err!(f, "IO error"; e),
} }
} }
} }
@ -80,11 +82,11 @@ impl Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match self { match *self {
UtxoMissing(_) => None, UtxoMissing(_) => None,
Io(e) => Some(e), Io(ref e) => Some(e),
} }
} }
} }

View File

@ -494,21 +494,22 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match *self { match *self {
Error::CannotDeriveFromHardenedKey => CannotDeriveFromHardenedKey =>
f.write_str("cannot derive hardened key from public key"), f.write_str("cannot derive hardened key from public key"),
Error::Secp256k1(ref e) => write_err!(f, "secp256k1 error"; e), Secp256k1(ref e) => write_err!(f, "secp256k1 error"; e),
Error::InvalidChildNumber(ref n) => InvalidChildNumber(ref n) =>
write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n), write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n),
Error::InvalidChildNumberFormat => f.write_str("invalid child number format"), InvalidChildNumberFormat => f.write_str("invalid child number format"),
Error::InvalidDerivationPathFormat => f.write_str("invalid derivation path format"), InvalidDerivationPathFormat => f.write_str("invalid derivation path format"),
Error::UnknownVersion(ref bytes) => UnknownVersion(ref bytes) => write!(f, "unknown version magic bytes: {:?}", bytes),
write!(f, "unknown version magic bytes: {:?}", bytes), WrongExtendedKeyLength(ref len) =>
Error::WrongExtendedKeyLength(ref len) =>
write!(f, "encoded extended key data has wrong length {}", len), write!(f, "encoded extended key data has wrong length {}", len),
Error::Base58(ref e) => write_err!(f, "base58 encoding error"; e), Base58(ref e) => write_err!(f, "base58 encoding error"; e),
Error::Hex(ref e) => write_err!(f, "Hexadecimal decoding error"; e), Hex(ref e) => write_err!(f, "Hexadecimal decoding error"; e),
Error::InvalidPublicKeyHexLength(got) => InvalidPublicKeyHexLength(got) =>
write!(f, "PublicKey hex should be 66 or 130 digits long, got: {}", got), write!(f, "PublicKey hex should be 66 or 130 digits long, got: {}", got),
} }
} }
@ -517,12 +518,12 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match self { match *self {
Secp256k1(e) => Some(e), Secp256k1(ref e) => Some(e),
Base58(e) => Some(e), Base58(ref e) => Some(e),
Hex(e) => Some(e), Hex(ref e) => Some(e),
CannotDeriveFromHardenedKey CannotDeriveFromHardenedKey
| InvalidChildNumber(_) | InvalidChildNumber(_)
| InvalidChildNumberFormat | InvalidChildNumberFormat

View File

@ -387,13 +387,15 @@ pub enum Bip34Error {
impl fmt::Display for Bip34Error { impl fmt::Display for Bip34Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Bip34Error::*;
match *self { match *self {
Bip34Error::Unsupported => write!(f, "block doesn't support BIP34"), Unsupported => write!(f, "block doesn't support BIP34"),
Bip34Error::NotPresent => write!(f, "BIP34 push not present in block's coinbase"), NotPresent => write!(f, "BIP34 push not present in block's coinbase"),
Bip34Error::UnexpectedPush(ref p) => { UnexpectedPush(ref p) => {
write!(f, "unexpected byte push of > 8 bytes: {:?}", p) write!(f, "unexpected byte push of > 8 bytes: {:?}", p)
} }
Bip34Error::NegativeHeight => write!(f, "negative BIP34 height"), NegativeHeight => write!(f, "negative BIP34 height"),
} }
} }
} }
@ -401,16 +403,17 @@ impl fmt::Display for Bip34Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Bip34Error { impl std::error::Error for Bip34Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Bip34Error::*; use Bip34Error::*;
match self { match *self {
Unsupported | NotPresent | UnexpectedPush(_) | NegativeHeight => None, Unsupported | NotPresent | UnexpectedPush(_) | NegativeHeight => None,
} }
} }
} }
/// A block validation error. /// A block validation error.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ValidationError { pub enum ValidationError {
/// The header hash is not below the target. /// The header hash is not below the target.
BadProofOfWork, BadProofOfWork,

View File

@ -575,7 +575,7 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*; use Error::*;
match *self { match *self {
Conversion(ref e) => write_err!(f, "error converting lock time value"; e), Conversion(ref e) => write_err!(f, "error converting lock time value"; e),
@ -588,7 +588,7 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match *self { match *self {
Conversion(ref e) => Some(e), Conversion(ref e) => Some(e),
@ -614,7 +614,8 @@ impl From<ParseIntError> for Error {
} }
/// An error that occurs when converting a `u32` to a lock time variant. /// An error that occurs when converting a `u32` to a lock time variant.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct ConversionError { pub struct ConversionError {
/// The expected timelock unit, height (blocks) or time (seconds). /// The expected timelock unit, height (blocks) or time (seconds).
unit: LockTimeUnit, unit: LockTimeUnit,
@ -637,7 +638,9 @@ impl fmt::Display for ConversionError {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for ConversionError {} impl std::error::Error for ConversionError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
/// Describes the two types of locking, lock-by-blockheight and lock-by-blocktime. /// Describes the two types of locking, lock-by-blockheight and lock-by-blocktime.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
@ -669,7 +672,7 @@ pub enum OperationError {
impl fmt::Display for OperationError { impl fmt::Display for OperationError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::OperationError::*; use OperationError::*;
match *self { match *self {
InvalidComparison => InvalidComparison =>
@ -679,7 +682,15 @@ impl fmt::Display for OperationError {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for OperationError {} impl std::error::Error for OperationError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use OperationError::*;
match *self {
InvalidComparison => None,
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -311,15 +311,17 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match *self { match *self {
Self::IntegerOverflow(val) => write!( IntegerOverflow(val) => write!(
f, f,
"{} seconds is too large to be encoded to a 16 bit 512 second interval", "{} seconds is too large to be encoded to a 16 bit 512 second interval",
val val
), ),
Self::IncompatibleHeight(lock, height) => IncompatibleHeight(lock, height) =>
write!(f, "tried to satisfy lock {} with height: {}", lock, height), write!(f, "tried to satisfy lock {} with height: {}", lock, height),
Self::IncompatibleTime(lock, time) => IncompatibleTime(lock, time) =>
write!(f, "tried to satisfy lock {} with time: {}", lock, time), write!(f, "tried to satisfy lock {} with time: {}", lock, time),
} }
} }
@ -328,7 +330,7 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match *self { match *self {
IntegerOverflow(_) | IncompatibleHeight(_, _) | IncompatibleTime(_, _) => None, IntegerOverflow(_) | IncompatibleHeight(_, _) | IncompatibleTime(_, _) => None,

View File

@ -698,13 +698,15 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match *self { match *self {
Error::NonMinimalPush => f.write_str("non-minimal datapush"), NonMinimalPush => f.write_str("non-minimal datapush"),
Error::EarlyEndOfScript => f.write_str("unexpected end of script"), EarlyEndOfScript => f.write_str("unexpected end of script"),
Error::NumericOverflow => NumericOverflow =>
f.write_str("numeric overflow (number on stack larger than 4 bytes)"), f.write_str("numeric overflow (number on stack larger than 4 bytes)"),
Error::UnknownSpentOutput(ref point) => write!(f, "unknown spent output: {}", point), UnknownSpentOutput(ref point) => write!(f, "unknown spent output: {}", point),
Error::Serialization => Serialization =>
f.write_str("can not serialize the spending transaction in Transaction::verify()"), f.write_str("can not serialize the spending transaction in Transaction::verify()"),
} }
} }
@ -713,7 +715,7 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match *self { match *self {
NonMinimalPush NonMinimalPush

View File

@ -413,4 +413,7 @@ mod error {
} }
} }
crate::error::impl_std_error!(PushBytesError); #[cfg(feature = "std")]
impl std::error::Error for PushBytesError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}

View File

@ -66,7 +66,7 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*; use Error::*;
match *self { match *self {
InvalidLength(len) => InvalidLength(len) =>
@ -80,9 +80,9 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match self { match *self {
InvalidLength(_) | InvalidSegwitV0Length(_) => None, InvalidLength(_) | InvalidSegwitV0Length(_) => None,
} }
} }

View File

@ -168,6 +168,7 @@ impl From<WitnessVersion> for Opcode {
/// Error parsing [`WitnessVersion`] from a string. /// Error parsing [`WitnessVersion`] from a string.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum FromStrError { pub enum FromStrError {
/// Unable to parse integer from string. /// Unable to parse integer from string.
Unparsable(ParseIntError), Unparsable(ParseIntError),
@ -204,6 +205,7 @@ impl From<TryFromError> for FromStrError {
/// Error attempting to create a [`WitnessVersion`] from an [`Instruction`] /// Error attempting to create a [`WitnessVersion`] from an [`Instruction`]
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum TryFromInstructionError { pub enum TryFromInstructionError {
/// Cannot not convert OP to a witness version. /// Cannot not convert OP to a witness version.
TryFrom(TryFromError), TryFrom(TryFromError),
@ -240,6 +242,7 @@ impl From<TryFromError> for TryFromInstructionError {
/// Error attempting to create a [`WitnessVersion`] from an integer. /// Error attempting to create a [`WitnessVersion`] from an integer.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub struct TryFromError { pub struct TryFromError {
/// The invalid non-witness version integer. /// The invalid non-witness version integer.
pub invalid: u8, pub invalid: u8,

View File

@ -116,13 +116,14 @@ pub enum ParseOutPointError {
impl fmt::Display for ParseOutPointError { impl fmt::Display for ParseOutPointError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use ParseOutPointError::*;
match *self { match *self {
ParseOutPointError::Txid(ref e) => write_err!(f, "error parsing TXID"; e), Txid(ref e) => write_err!(f, "error parsing TXID"; e),
ParseOutPointError::Vout(ref e) => write_err!(f, "error parsing vout"; e), Vout(ref e) => write_err!(f, "error parsing vout"; e),
ParseOutPointError::Format => write!(f, "OutPoint not in <txid>:<vout> format"), Format => write!(f, "OutPoint not in <txid>:<vout> format"),
ParseOutPointError::TooLong => write!(f, "vout should be at most 10 digits"), TooLong => write!(f, "vout should be at most 10 digits"),
ParseOutPointError::VoutNotCanonical => VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"),
write!(f, "no leading zeroes or + allowed in vout part"),
} }
} }
} }
@ -130,7 +131,7 @@ impl fmt::Display for ParseOutPointError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for ParseOutPointError { impl std::error::Error for ParseOutPointError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::ParseOutPointError::*; use ParseOutPointError::*;
match self { match self {
Txid(e) => Some(e), Txid(e) => Some(e),

View File

@ -63,15 +63,17 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match *self { match *self {
Error::Io(ref e) => write_err!(f, "IO error"; e), Io(ref e) => write_err!(f, "IO error"; e),
Error::OversizedVectorAllocation { requested: ref r, max: ref m } => OversizedVectorAllocation { requested: ref r, max: ref m } =>
write!(f, "allocation of oversized vector: requested {}, maximum {}", r, m), write!(f, "allocation of oversized vector: requested {}, maximum {}", r, m),
Error::InvalidChecksum { expected: ref e, actual: ref a } => InvalidChecksum { expected: ref e, actual: ref a } =>
write!(f, "invalid checksum: expected {:x}, actual {:x}", e.as_hex(), a.as_hex()), write!(f, "invalid checksum: expected {:x}, actual {:x}", e.as_hex(), a.as_hex()),
Error::NonMinimalVarInt => write!(f, "non-minimal varint"), NonMinimalVarInt => write!(f, "non-minimal varint"),
Error::ParseFailed(ref s) => write!(f, "parse failed: {}", s), ParseFailed(ref s) => write!(f, "parse failed: {}", s),
Error::UnsupportedSegwitFlag(ref swflag) => UnsupportedSegwitFlag(ref swflag) =>
write!(f, "unsupported segwit version: {}", swflag), write!(f, "unsupported segwit version: {}", swflag),
} }
} }
@ -80,7 +82,7 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match self { match self {
Io(e) => Some(e), Io(e) => Some(e),

View File

@ -179,6 +179,7 @@ impl Transaction {
// 2. We want to implement `std::error::Error` if the "std" feature is enabled in `rust-bitcoin` but // 2. We want to implement `std::error::Error` if the "std" feature is enabled in `rust-bitcoin` but
// not in `bitcoinconsensus`. // not in `bitcoinconsensus`.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct BitcoinconsensusError(bitcoinconsensus::Error); pub struct BitcoinconsensusError(bitcoinconsensus::Error);
impl fmt::Display for BitcoinconsensusError { impl fmt::Display for BitcoinconsensusError {
@ -203,6 +204,7 @@ impl From<bitcoinconsensus::Error> for BitcoinconsensusError {
/// An error during transaction validation. /// An error during transaction validation.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum TxVerifyError { pub enum TxVerifyError {
/// Error validating the script with bitcoinconsensus library. /// Error validating the script with bitcoinconsensus library.
ScriptVerification(BitcoinconsensusError), ScriptVerification(BitcoinconsensusError),

View File

@ -212,12 +212,12 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match self { match *self {
Hex(e) => Some(e), Hex(ref e) => Some(e),
Secp256k1(e) => Some(e), Secp256k1(ref e) => Some(e),
SighashType(e) => Some(e), SighashType(ref e) => Some(e),
EmptySignature => None, EmptySignature => None,
} }
} }

View File

@ -720,12 +720,12 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match self { match *self {
Base58(e) => Some(e), Base58(ref e) => Some(e),
Secp256k1(e) => Some(e), Secp256k1(ref e) => Some(e),
Hex(e) => Some(e), Hex(ref e) => Some(e),
InvalidKeyPrefix(_) | InvalidHexLength(_) => None, InvalidKeyPrefix(_) | InvalidHexLength(_) => None,
} }
} }

View File

@ -18,7 +18,6 @@ use hashes::{hash_newtype, sha256, sha256d, sha256t_hash_newtype, Hash};
use crate::blockdata::witness::Witness; use crate::blockdata::witness::Witness;
use crate::consensus::{encode, Encodable}; use crate::consensus::{encode, Encodable};
use crate::error::impl_std_error;
use crate::prelude::*; use crate::prelude::*;
use crate::taproot::{LeafVersion, TapLeafHash, TAPROOT_ANNEX_PREFIX}; use crate::taproot::{LeafVersion, TapLeafHash, TAPROOT_ANNEX_PREFIX};
use crate::{io, Amount, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut}; use crate::{io, Amount, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut};
@ -248,7 +247,7 @@ impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use Error::*; use Error::*;
match self { match *self {
Io(error_kind) => write!(f, "writer errored: {:?}", error_kind), Io(error_kind) => write!(f, "writer errored: {:?}", error_kind),
IndexOutOfInputsBounds { index, inputs_size } => write!(f, "requested index ({}) is greater or equal than the number of transaction inputs ({})", index, inputs_size), IndexOutOfInputsBounds { index, inputs_size } => write!(f, "requested index ({}) is greater or equal than the number of transaction inputs ({})", index, inputs_size),
SingleWithoutCorrespondingOutput { index, outputs_size } => write!(f, "SIGHASH_SINGLE for input ({}) haven't a corresponding output (#outputs:{})", index, outputs_size), SingleWithoutCorrespondingOutput { index, outputs_size } => write!(f, "SIGHASH_SINGLE for input ({}) haven't a corresponding output (#outputs:{})", index, outputs_size),
@ -267,7 +266,7 @@ impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use Error::*; use Error::*;
match self { match *self {
Io(_) Io(_)
| IndexOutOfInputsBounds { .. } | IndexOutOfInputsBounds { .. }
| SingleWithoutCorrespondingOutput { .. } | SingleWithoutCorrespondingOutput { .. }
@ -524,7 +523,8 @@ impl TapSighashType {
} }
/// Integer is not a consensus valid sighash type. /// Integer is not a consensus valid sighash type.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct InvalidSighashTypeError(pub u32); pub struct InvalidSighashTypeError(pub u32);
impl fmt::Display for InvalidSighashTypeError { impl fmt::Display for InvalidSighashTypeError {
@ -533,11 +533,15 @@ impl fmt::Display for InvalidSighashTypeError {
} }
} }
impl_std_error!(InvalidSighashTypeError); #[cfg(feature = "std")]
impl std::error::Error for InvalidSighashTypeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
/// This type is consensus valid but an input including it would prevent the transaction from /// This type is consensus valid but an input including it would prevent the transaction from
/// being relayed on today's Bitcoin network. /// being relayed on today's Bitcoin network.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct NonStandardSighashTypeError(pub u32); pub struct NonStandardSighashTypeError(pub u32);
impl fmt::Display for NonStandardSighashTypeError { impl fmt::Display for NonStandardSighashTypeError {
@ -546,12 +550,16 @@ impl fmt::Display for NonStandardSighashTypeError {
} }
} }
impl_std_error!(NonStandardSighashTypeError); #[cfg(feature = "std")]
impl std::error::Error for NonStandardSighashTypeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
/// Error returned for failure during parsing one of the sighash types. /// Error returned for failure during parsing one of the sighash types.
/// ///
/// This is currently returned for unrecognized sighash strings. /// This is currently returned for unrecognized sighash strings.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct SighashTypeParseError { pub struct SighashTypeParseError {
/// The unrecognized string we attempted to parse. /// The unrecognized string we attempted to parse.
pub unrecognized: String, pub unrecognized: String,
@ -563,7 +571,10 @@ impl fmt::Display for SighashTypeParseError {
} }
} }
impl_std_error!(SighashTypeParseError); #[cfg(feature = "std")]
impl std::error::Error for SighashTypeParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
impl<R: Borrow<Transaction>> SighashCache<R> { impl<R: Borrow<Transaction>> SighashCache<R> {
/// Constructs a new `SighashCache` from an unsigned transaction. /// Constructs a new `SighashCache` from an unsigned transaction.

View File

@ -87,9 +87,9 @@ impl std::error::Error for SigFromSliceError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use SigFromSliceError::*; use SigFromSliceError::*;
match self { match *self {
Secp256k1(e) => Some(e), Secp256k1(ref e) => Some(e),
SighashType(e) => Some(e), SighashType(ref e) => Some(e),
InvalidSignatureSize(_) => None, InvalidSignatureSize(_) => None,
} }
} }

View File

@ -2,6 +2,4 @@
//! Contains error types and other error handling tools. //! Contains error types and other error handling tools.
pub(crate) use internals::impl_std_error;
pub use crate::parse::ParseIntError; pub use crate::parse::ParseIntError;

View File

@ -501,7 +501,7 @@ pub enum MerkleBlockError {
impl fmt::Display for MerkleBlockError { impl fmt::Display for MerkleBlockError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::MerkleBlockError::*; use MerkleBlockError::*;
match *self { match *self {
MerkleRootMismatch => write!(f, "merkle header root doesn't match to the root calculated from the partial merkle tree"), MerkleRootMismatch => write!(f, "merkle header root doesn't match to the root calculated from the partial merkle tree"),
@ -521,7 +521,7 @@ impl fmt::Display for MerkleBlockError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for MerkleBlockError { impl std::error::Error for MerkleBlockError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::MerkleBlockError::*; use MerkleBlockError::*;
match *self { match *self {
MerkleRootMismatch | NoTransactions | TooManyTransactions | TooManyHashes MerkleRootMismatch | NoTransactions | TooManyTransactions | TooManyHashes

View File

@ -28,7 +28,6 @@ use internals::write_err;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::constants::ChainHash; use crate::constants::ChainHash;
use crate::error::impl_std_error;
use crate::p2p::Magic; use crate::p2p::Magic;
use crate::prelude::{String, ToOwned}; use crate::prelude::{String, ToOwned};
@ -195,6 +194,7 @@ pub mod as_core_arg {
/// An error in parsing network string. /// An error in parsing network string.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct ParseNetworkError(String); pub struct ParseNetworkError(String);
impl fmt::Display for ParseNetworkError { impl fmt::Display for ParseNetworkError {
@ -202,7 +202,11 @@ impl fmt::Display for ParseNetworkError {
write_err!(f, "failed to parse {} as network", self.0; self) write_err!(f, "failed to parse {} as network", self.0; self)
} }
} }
impl_std_error!(ParseNetworkError);
#[cfg(feature = "std")]
impl std::error::Error for ParseNetworkError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
impl FromStr for Network { impl FromStr for Network {
type Err = ParseNetworkError; type Err = ParseNetworkError;
@ -238,18 +242,22 @@ impl fmt::Display for Network {
/// Error in parsing network from chain hash. /// Error in parsing network from chain hash.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnknownChainHash(ChainHash); #[non_exhaustive]
pub struct UnknownChainHashError(ChainHash);
impl Display for UnknownChainHash { impl Display for UnknownChainHashError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "unknown chain hash: {}", self.0) write!(f, "unknown chain hash: {}", self.0)
} }
} }
impl_std_error!(UnknownChainHash); #[cfg(feature = "std")]
impl std::error::Error for UnknownChainHashError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
impl TryFrom<ChainHash> for Network { impl TryFrom<ChainHash> for Network {
type Error = UnknownChainHash; type Error = UnknownChainHashError;
fn try_from(chain_hash: ChainHash) -> Result<Self, Self::Error> { fn try_from(chain_hash: ChainHash) -> Result<Self, Self::Error> {
match chain_hash { match chain_hash {
@ -258,7 +266,7 @@ impl TryFrom<ChainHash> for Network {
ChainHash::TESTNET => Ok(Network::Testnet), ChainHash::TESTNET => Ok(Network::Testnet),
ChainHash::SIGNET => Ok(Network::Signet), ChainHash::SIGNET => Ok(Network::Signet),
ChainHash::REGTEST => Ok(Network::Regtest), ChainHash::REGTEST => Ok(Network::Regtest),
_ => Err(UnknownChainHash(chain_hash)), _ => Err(UnknownChainHashError(chain_hash)),
} }
} }
} }

View File

@ -129,6 +129,7 @@ impl Decodable for CommandString {
/// ///
/// This is currently returned for command strings longer than 12. /// This is currently returned for command strings longer than 12.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct CommandStringError { pub struct CommandStringError {
cow: Cow<'static, str>, cow: Cow<'static, str>,
} }
@ -144,7 +145,10 @@ impl fmt::Display for CommandStringError {
} }
} }
crate::error::impl_std_error!(CommandStringError); #[cfg(feature = "std")]
impl std::error::Error for CommandStringError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
/// A Network message /// A Network message
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]

View File

@ -30,7 +30,6 @@ use hex::FromHex;
use internals::{debug_from_display, write_err}; use internals::{debug_from_display, write_err};
use crate::consensus::encode::{self, Decodable, Encodable}; use crate::consensus::encode::{self, Decodable, Encodable};
use crate::error::impl_std_error;
use crate::prelude::{Borrow, BorrowMut, String, ToOwned}; use crate::prelude::{Borrow, BorrowMut, String, ToOwned};
use crate::{io, Network}; use crate::{io, Network};
@ -221,15 +220,6 @@ impl Magic {
pub fn to_bytes(self) -> [u8; 4] { self.0 } pub fn to_bytes(self) -> [u8; 4] { self.0 }
} }
/// An error in parsing magic bytes.
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ParseMagicError {
/// The error that occurred when parsing the string.
error: hex::HexToArrayError,
/// The byte string that failed to parse.
magic: String,
}
impl FromStr for Magic { impl FromStr for Magic {
type Err = ParseMagicError; type Err = ParseMagicError;
@ -253,12 +243,8 @@ impl From<Network> for Magic {
} }
} }
/// Error in creating a Network from Magic bytes.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UnknownMagic(Magic);
impl TryFrom<Magic> for Network { impl TryFrom<Magic> for Network {
type Error = UnknownMagic; type Error = UnknownMagicError;
fn try_from(magic: Magic) -> Result<Self, Self::Error> { fn try_from(magic: Magic) -> Result<Self, Self::Error> {
match magic { match magic {
@ -267,7 +253,7 @@ impl TryFrom<Magic> for Network {
Magic::TESTNET => Ok(Network::Testnet), Magic::TESTNET => Ok(Network::Testnet),
Magic::SIGNET => Ok(Network::Signet), Magic::SIGNET => Ok(Network::Signet),
Magic::REGTEST => Ok(Network::Regtest), Magic::REGTEST => Ok(Network::Regtest),
_ => Err(UnknownMagic(magic)), _ => Err(UnknownMagicError(magic)),
} }
} }
} }
@ -338,19 +324,42 @@ impl BorrowMut<[u8; 4]> for Magic {
fn borrow_mut(&mut self) -> &mut [u8; 4] { &mut self.0 } fn borrow_mut(&mut self) -> &mut [u8; 4] { &mut self.0 }
} }
/// An error in parsing magic bytes.
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct ParseMagicError {
/// The error that occurred when parsing the string.
error: hex::HexToArrayError,
/// The byte string that failed to parse.
magic: String,
}
impl fmt::Display for ParseMagicError { impl fmt::Display for ParseMagicError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write_err!(f, "failed to parse {} as network magic", self.magic; self.error) write_err!(f, "failed to parse {} as network magic", self.magic; self.error)
} }
} }
impl_std_error!(ParseMagicError, error);
impl fmt::Display for UnknownMagic { #[cfg(feature = "std")]
impl std::error::Error for ParseMagicError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.error) }
}
/// Error in creating a Network from Magic bytes.
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct UnknownMagicError(Magic);
impl fmt::Display for UnknownMagicError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "unknown network magic {}", self.0) write!(f, "unknown network magic {}", self.0)
} }
} }
impl_std_error!(UnknownMagic);
#[cfg(feature = "std")]
impl std::error::Error for UnknownMagicError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -6,7 +6,6 @@ use core::str::FromStr;
use internals::write_err; use internals::write_err;
use crate::error::impl_std_error;
use crate::prelude::*; use crate::prelude::*;
/// Error with rich context returned when a string can't be parsed as an integer. /// Error with rich context returned when a string can't be parsed as an integer.
@ -19,6 +18,7 @@ use crate::prelude::*;
/// in a performance-critical application you may want to box it or throw away the context by /// in a performance-critical application you may want to box it or throw away the context by
/// converting to `core` type. /// converting to `core` type.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct ParseIntError { pub struct ParseIntError {
input: String, input: String,
// for displaying - see Display impl with nice error message below // for displaying - see Display impl with nice error message below
@ -35,14 +35,6 @@ impl ParseIntError {
pub fn input(&self) -> &str { &self.input } pub fn input(&self) -> &str { &self.input }
} }
impl From<ParseIntError> for core::num::ParseIntError {
fn from(value: ParseIntError) -> Self { value.source }
}
impl AsRef<core::num::ParseIntError> for ParseIntError {
fn as_ref(&self) -> &core::num::ParseIntError { &self.source }
}
impl fmt::Display for ParseIntError { impl fmt::Display for ParseIntError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let signed = if self.is_signed { "signed" } else { "unsigned" }; let signed = if self.is_signed { "signed" } else { "unsigned" };
@ -51,6 +43,19 @@ impl fmt::Display for ParseIntError {
} }
} }
#[cfg(feature = "std")]
impl std::error::Error for ParseIntError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.source) }
}
impl From<ParseIntError> for core::num::ParseIntError {
fn from(value: ParseIntError) -> Self { value.source }
}
impl AsRef<core::num::ParseIntError> for ParseIntError {
fn as_ref(&self) -> &core::num::ParseIntError { &self.source }
}
/// Not strictly neccessary but serves as a lint - avoids weird behavior if someone accidentally /// Not strictly neccessary but serves as a lint - avoids weird behavior if someone accidentally
/// passes non-integer to the `parse()` function. /// passes non-integer to the `parse()` function.
pub(crate) trait Integer: pub(crate) trait Integer:
@ -95,8 +100,6 @@ pub(crate) fn hex_u32<S: AsRef<str> + Into<String>>(s: S) -> Result<u32, ParseIn
}) })
} }
impl_std_error!(ParseIntError, source);
/// Implements `TryFrom<$from> for $to` using `parse::int`, mapping the output using infallible /// Implements `TryFrom<$from> for $to` using `parse::int`, mapping the output using infallible
/// conversion function `fn`. /// conversion function `fn`.
macro_rules! impl_tryfrom_str_from_int_infallible { macro_rules! impl_tryfrom_str_from_int_infallible {

View File

@ -705,7 +705,8 @@ impl<T: Into<u128>> From<T> for U256 {
} }
/// Error from `TryFrom<signed type>` implementations, occurs when input is negative. /// Error from `TryFrom<signed type>` implementations, occurs when input is negative.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct TryFromError(i128); pub struct TryFromError(i128);
impl fmt::Display for TryFromError { impl fmt::Display for TryFromError {
@ -715,7 +716,9 @@ impl fmt::Display for TryFromError {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for TryFromError {} impl std::error::Error for TryFromError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
}
impl Add for U256 { impl Add for U256 {
type Output = Self; type Output = Self;

View File

@ -93,7 +93,7 @@ pub enum Error {
/// Parsing error indicating a taproot error /// Parsing error indicating a taproot error
Taproot(&'static str), Taproot(&'static str),
/// Taproot tree deserilaization error /// Taproot tree deserilaization error
TapTree(crate::taproot::IncompleteBuilder), TapTree(crate::taproot::IncompleteBuilderError),
/// Error related to an xpub key /// Error related to an xpub key
XPubKey(&'static str), XPubKey(&'static str),
/// Error related to PSBT version /// Error related to PSBT version
@ -106,57 +106,56 @@ pub enum Error {
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Error::*;
match *self { match *self {
Error::InvalidMagic => f.write_str("invalid magic"), InvalidMagic => f.write_str("invalid magic"),
Error::MissingUtxo => f.write_str("UTXO information is not present in PSBT"), MissingUtxo => f.write_str("UTXO information is not present in PSBT"),
Error::InvalidSeparator => f.write_str("invalid separator"), InvalidSeparator => f.write_str("invalid separator"),
Error::PsbtUtxoOutOfbounds => PsbtUtxoOutOfbounds =>
f.write_str("output index is out of bounds of non witness script output array"), f.write_str("output index is out of bounds of non witness script output array"),
Error::InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey), InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey),
Error::InvalidProprietaryKey => InvalidProprietaryKey =>
write!(f, "non-proprietary key type found when proprietary key was expected"), write!(f, "non-proprietary key type found when proprietary key was expected"),
Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey), DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey),
Error::UnsignedTxHasScriptSigs => UnsignedTxHasScriptSigs => f.write_str("the unsigned transaction has script sigs"),
f.write_str("the unsigned transaction has script sigs"), UnsignedTxHasScriptWitnesses =>
Error::UnsignedTxHasScriptWitnesses =>
f.write_str("the unsigned transaction has script witnesses"), f.write_str("the unsigned transaction has script witnesses"),
Error::MustHaveUnsignedTx => MustHaveUnsignedTx =>
f.write_str("partially signed transactions must have an unsigned transaction"), f.write_str("partially signed transactions must have an unsigned transaction"),
Error::NoMorePairs => f.write_str("no more key-value pairs for this psbt map"), NoMorePairs => f.write_str("no more key-value pairs for this psbt map"),
Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!( UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(
f, f,
"different unsigned transaction: expected {}, actual {}", "different unsigned transaction: expected {}, actual {}",
e.txid(), e.txid(),
a.txid() a.txid()
), ),
Error::NonStandardSighashType(ref sht) => NonStandardSighashType(ref sht) => write!(f, "non-standard sighash type: {}", sht),
write!(f, "non-standard sighash type: {}", sht), InvalidHash(ref e) => write_err!(f, "invalid hash when parsing slice"; e),
Error::InvalidHash(ref e) => write_err!(f, "invalid hash when parsing slice"; e), InvalidPreimageHashPair { ref preimage, ref hash, ref hash_type } => {
Error::InvalidPreimageHashPair { ref preimage, ref hash, ref hash_type } => {
// directly using debug forms of psbthash enums // directly using debug forms of psbthash enums
write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash) write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash)
} }
Error::CombineInconsistentKeySources(ref s) => { CombineInconsistentKeySources(ref s) => {
write!(f, "combine conflict: {}", s) write!(f, "combine conflict: {}", s)
} }
Error::ConsensusEncoding(ref e) => write_err!(f, "bitcoin consensus encoding error"; e), ConsensusEncoding(ref e) => write_err!(f, "bitcoin consensus encoding error"; e),
Error::NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"), NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"),
Error::FeeOverflow => f.write_str("integer overflow in fee calculation"), FeeOverflow => f.write_str("integer overflow in fee calculation"),
Error::InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e), InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e),
Error::InvalidSecp256k1PublicKey(ref e) => InvalidSecp256k1PublicKey(ref e) => write_err!(f, "invalid secp256k1 public key"; e),
write_err!(f, "invalid secp256k1 public key"; e), InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"),
Error::InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"), InvalidEcdsaSignature(ref e) => write_err!(f, "invalid ECDSA signature"; e),
Error::InvalidEcdsaSignature(ref e) => write_err!(f, "invalid ECDSA signature"; e), InvalidTaprootSignature(ref e) => write_err!(f, "invalid taproot signature"; e),
Error::InvalidTaprootSignature(ref e) => write_err!(f, "invalid taproot signature"; e), InvalidControlBlock => f.write_str("invalid control block"),
Error::InvalidControlBlock => f.write_str("invalid control block"), InvalidLeafVersion => f.write_str("invalid leaf version"),
Error::InvalidLeafVersion => f.write_str("invalid leaf version"), Taproot(s) => write!(f, "taproot error - {}", s),
Error::Taproot(s) => write!(f, "taproot error - {}", s), TapTree(ref e) => write_err!(f, "taproot tree error"; e),
Error::TapTree(ref e) => write_err!(f, "taproot tree error"; e), XPubKey(s) => write!(f, "xpub key error - {}", s),
Error::XPubKey(s) => write!(f, "xpub key error - {}", s), Version(s) => write!(f, "version error {}", s),
Error::Version(s) => write!(f, "version error {}", s), PartialDataConsumption =>
Error::PartialDataConsumption =>
f.write_str("data not consumed entirely when explicitly deserializing"), f.write_str("data not consumed entirely when explicitly deserializing"),
Error::Io(ref e) => write_err!(f, "I/O error"; e), Io(ref e) => write_err!(f, "I/O error"; e),
} }
} }
} }
@ -164,12 +163,12 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for Error { impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::Error::*; use Error::*;
match self { match *self {
InvalidHash(e) => Some(e), InvalidHash(ref e) => Some(e),
ConsensusEncoding(e) => Some(e), ConsensusEncoding(ref e) => Some(e),
Io(e) => Some(e), Io(ref e) => Some(e),
InvalidMagic InvalidMagic
| MissingUtxo | MissingUtxo
| InvalidSeparator | InvalidSeparator

View File

@ -796,7 +796,7 @@ pub enum SignError {
impl fmt::Display for SignError { impl fmt::Display for SignError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use self::SignError::*; use SignError::*;
match *self { match *self {
IndexOutOfBounds(ref e) => write_err!(f, "index out of bounds"; e), IndexOutOfBounds(ref e) => write_err!(f, "index out of bounds"; e),
@ -821,9 +821,11 @@ impl fmt::Display for SignError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for SignError { impl std::error::Error for SignError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::SignError::*; use SignError::*;
match *self { match *self {
SighashComputation(ref e) => Some(e),
IndexOutOfBounds(ref e) => Some(e),
InvalidSighashType InvalidSighashType
| MissingInputUtxo | MissingInputUtxo
| MissingRedeemScript | MissingRedeemScript
@ -836,8 +838,6 @@ impl std::error::Error for SignError {
| KeyNotFound | KeyNotFound
| WrongSigningAlgorithm | WrongSigningAlgorithm
| Unsupported => None, | Unsupported => None,
SighashComputation(ref e) => Some(e),
IndexOutOfBounds(ref e) => Some(e),
} }
} }
} }
@ -850,8 +850,9 @@ impl From<IndexOutOfBoundsError> for SignError {
fn from(e: IndexOutOfBoundsError) -> Self { SignError::IndexOutOfBounds(e) } fn from(e: IndexOutOfBoundsError) -> Self { SignError::IndexOutOfBounds(e) }
} }
#[derive(Debug, Clone, PartialEq, Eq)]
/// This error is returned when extracting a [`Transaction`] from a [`Psbt`]. /// This error is returned when extracting a [`Transaction`] from a [`Psbt`].
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum ExtractTxError { pub enum ExtractTxError {
/// The [`FeeRate`] is too high /// The [`FeeRate`] is too high
AbsurdFeeRate { AbsurdFeeRate {
@ -874,14 +875,16 @@ pub enum ExtractTxError {
impl fmt::Display for ExtractTxError { impl fmt::Display for ExtractTxError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { use ExtractTxError::*;
ExtractTxError::AbsurdFeeRate { fee_rate, .. } =>
match *self {
AbsurdFeeRate { fee_rate, .. } =>
write!(f, "An absurdly high fee rate of {}", fee_rate), write!(f, "An absurdly high fee rate of {}", fee_rate),
ExtractTxError::MissingInputValue { .. } => write!( MissingInputValue { .. } => write!(
f, f,
"One of the inputs lacked value information (witness_utxo or non_witness_utxo)" "One of the inputs lacked value information (witness_utxo or non_witness_utxo)"
), ),
ExtractTxError::SendingTooMuch { .. } => write!( SendingTooMuch { .. } => write!(
f, f,
"Transaction would be invalid due to output value being greater than input value." "Transaction would be invalid due to output value being greater than input value."
), ),
@ -890,10 +893,19 @@ impl fmt::Display for ExtractTxError {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for ExtractTxError {} impl std::error::Error for ExtractTxError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use ExtractTxError::*;
match *self {
AbsurdFeeRate { .. } | MissingInputValue { .. } | SendingTooMuch { .. } => None,
}
}
}
/// Input index out of bounds (actual index, maximum index allowed). /// Input index out of bounds (actual index, maximum index allowed).
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum IndexOutOfBoundsError { pub enum IndexOutOfBoundsError {
/// The index is out of bounds for the `psbt.inputs` vector. /// The index is out of bounds for the `psbt.inputs` vector.
Inputs { Inputs {
@ -931,7 +943,15 @@ impl fmt::Display for IndexOutOfBoundsError {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for IndexOutOfBoundsError {} impl std::error::Error for IndexOutOfBoundsError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use IndexOutOfBoundsError::*;
match *self {
Inputs { .. } | TxInput { .. } => None,
}
}
}
#[cfg(feature = "base64")] #[cfg(feature = "base64")]
mod display_from_str { mod display_from_str {

View File

@ -43,12 +43,13 @@ mod message_signing {
impl fmt::Display for MessageSignatureError { impl fmt::Display for MessageSignatureError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use MessageSignatureError::*;
match *self { match *self {
MessageSignatureError::InvalidLength => write!(f, "length not 65 bytes"), InvalidLength => write!(f, "length not 65 bytes"),
MessageSignatureError::InvalidEncoding(ref e) => InvalidEncoding(ref e) => write_err!(f, "invalid encoding"; e),
write_err!(f, "invalid encoding"; e), InvalidBase64 => write!(f, "invalid base64"),
MessageSignatureError::InvalidBase64 => write!(f, "invalid base64"), UnsupportedAddressType(ref address_type) =>
MessageSignatureError::UnsupportedAddressType(ref address_type) =>
write!(f, "unsupported address type: {}", address_type), write!(f, "unsupported address type: {}", address_type),
} }
} }
@ -57,10 +58,10 @@ mod message_signing {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for MessageSignatureError { impl std::error::Error for MessageSignatureError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::MessageSignatureError::*; use MessageSignatureError::*;
match self { match *self {
InvalidEncoding(e) => Some(e), InvalidEncoding(ref e) => Some(e),
InvalidLength | InvalidBase64 | UnsupportedAddressType(_) => None, InvalidLength | InvalidBase64 | UnsupportedAddressType(_) => None,
} }
} }

View File

@ -36,6 +36,7 @@ pub trait FromHexStr: Sized {
/// Hex parsing error /// Hex parsing error
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum FromHexError<E> { pub enum FromHexError<E> {
/// The input was not a valid hex string, contains the error that occurred while parsing. /// The input was not a valid hex string, contains the error that occurred while parsing.
ParseHex(E), ParseHex(E),
@ -49,7 +50,7 @@ impl<E> From<E> for FromHexError<E> {
impl<E: fmt::Display> fmt::Display for FromHexError<E> { impl<E: fmt::Display> fmt::Display for FromHexError<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::FromHexError::*; use FromHexError::*;
match *self { match *self {
ParseHex(ref e) => write_err!(f, "failed to parse hex string"; e), ParseHex(ref e) => write_err!(f, "failed to parse hex string"; e),
@ -65,7 +66,7 @@ where
E: std::error::Error + 'static, E: std::error::Error + 'static,
{ {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::FromHexError::*; use FromHexError::*;
match *self { match *self {
ParseHex(ref e) => Some(e), ParseHex(ref e) => Some(e),

View File

@ -468,11 +468,11 @@ impl TaprootBuilder {
/// ///
/// # Errors: /// # Errors:
/// ///
/// [`IncompleteBuilder::NotFinalized`] if the builder is not finalized. The builder /// [`IncompleteBuilderError::NotFinalized`] if the builder is not finalized. The builder
/// can be restored by calling [`IncompleteBuilder::into_builder`] /// can be restored by calling [`IncompleteBuilderError::into_builder`]
pub fn try_into_node_info(mut self) -> Result<NodeInfo, IncompleteBuilder> { pub fn try_into_node_info(mut self) -> Result<NodeInfo, IncompleteBuilderError> {
if self.branch().len() != 1 { if self.branch().len() != 1 {
return Err(IncompleteBuilder::NotFinalized(self)); return Err(IncompleteBuilderError::NotFinalized(self));
} }
Ok(self Ok(self
.branch .branch
@ -483,11 +483,11 @@ impl TaprootBuilder {
/// Converts the builder into a [`TapTree`] if the builder is a full tree and /// Converts the builder into a [`TapTree`] if the builder is a full tree and
/// does not contain any hidden nodes /// does not contain any hidden nodes
pub fn try_into_taptree(self) -> Result<TapTree, IncompleteBuilder> { pub fn try_into_taptree(self) -> Result<TapTree, IncompleteBuilderError> {
let node = self.try_into_node_info()?; let node = self.try_into_node_info()?;
if node.has_hidden_nodes { if node.has_hidden_nodes {
// Reconstruct the builder as it was if it has hidden nodes // Reconstruct the builder as it was if it has hidden nodes
return Err(IncompleteBuilder::HiddenParts(TaprootBuilder { return Err(IncompleteBuilderError::HiddenParts(TaprootBuilder {
branch: vec![Some(node)], branch: vec![Some(node)],
})); }));
} }
@ -574,42 +574,45 @@ impl Default for TaprootBuilder {
/// Error happening when [`TapTree`] is constructed from a [`TaprootBuilder`] /// Error happening when [`TapTree`] is constructed from a [`TaprootBuilder`]
/// having hidden branches or not being finalized. /// having hidden branches or not being finalized.
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
pub enum IncompleteBuilder { pub enum IncompleteBuilderError {
/// Indicates an attempt to construct a tap tree from a builder containing incomplete branches. /// Indicates an attempt to construct a tap tree from a builder containing incomplete branches.
NotFinalized(TaprootBuilder), NotFinalized(TaprootBuilder),
/// Indicates an attempt to construct a tap tree from a builder containing hidden parts. /// Indicates an attempt to construct a tap tree from a builder containing hidden parts.
HiddenParts(TaprootBuilder), HiddenParts(TaprootBuilder),
} }
impl IncompleteBuilder { impl IncompleteBuilderError {
/// Converts error into the original incomplete [`TaprootBuilder`] instance. /// Converts error into the original incomplete [`TaprootBuilder`] instance.
pub fn into_builder(self) -> TaprootBuilder { pub fn into_builder(self) -> TaprootBuilder {
use IncompleteBuilderError::*;
match self { match self {
IncompleteBuilder::NotFinalized(builder) | IncompleteBuilder::HiddenParts(builder) => NotFinalized(builder) | HiddenParts(builder) => builder,
builder,
} }
} }
} }
impl core::fmt::Display for IncompleteBuilder { impl core::fmt::Display for IncompleteBuilderError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use IncompleteBuilderError::*;
f.write_str(match self { f.write_str(match self {
IncompleteBuilder::NotFinalized(_) => NotFinalized(_) =>
"an attempt to construct a tap tree from a builder containing incomplete branches.", "an attempt to construct a tap tree from a builder containing incomplete branches.",
IncompleteBuilder::HiddenParts(_) => HiddenParts(_) =>
"an attempt to construct a tap tree from a builder containing hidden parts.", "an attempt to construct a tap tree from a builder containing hidden parts.",
}) })
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for IncompleteBuilder { impl std::error::Error for IncompleteBuilderError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::IncompleteBuilder::*; use IncompleteBuilderError::*;
match self { match *self {
NotFinalized(_) | HiddenParts(_) => None, NotFinalized(_) | HiddenParts(_) => None,
} }
} }
@ -617,35 +620,39 @@ impl std::error::Error for IncompleteBuilder {
/// Error happening when [`TapTree`] is constructed from a [`NodeInfo`] /// Error happening when [`TapTree`] is constructed from a [`NodeInfo`]
/// having hidden branches. /// having hidden branches.
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive] #[non_exhaustive]
pub enum HiddenNodes { pub enum HiddenNodesError {
/// Indicates an attempt to construct a tap tree from a builder containing hidden parts. /// Indicates an attempt to construct a tap tree from a builder containing hidden parts.
HiddenParts(NodeInfo), HiddenParts(NodeInfo),
} }
impl HiddenNodes { impl HiddenNodesError {
/// Converts error into the original incomplete [`NodeInfo`] instance. /// Converts error into the original incomplete [`NodeInfo`] instance.
pub fn into_node_info(self) -> NodeInfo { pub fn into_node_info(self) -> NodeInfo {
use HiddenNodesError::*;
match self { match self {
HiddenNodes::HiddenParts(node_info) => node_info, HiddenParts(node_info) => node_info,
} }
} }
} }
impl core::fmt::Display for HiddenNodes { impl core::fmt::Display for HiddenNodesError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use HiddenNodesError::*;
f.write_str(match self { f.write_str(match self {
HiddenNodes::HiddenParts(_) => HiddenParts(_) =>
"an attempt to construct a tap tree from a node_info containing hidden parts.", "an attempt to construct a tap tree from a node_info containing hidden parts.",
}) })
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for HiddenNodes { impl std::error::Error for HiddenNodesError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::HiddenNodes::*; use HiddenNodesError::*;
match self { match self {
HiddenParts(_) => None, HiddenParts(_) => None,
@ -685,29 +692,29 @@ impl TapTree {
} }
impl TryFrom<TaprootBuilder> for TapTree { impl TryFrom<TaprootBuilder> for TapTree {
type Error = IncompleteBuilder; type Error = IncompleteBuilderError;
/// Constructs [`TapTree`] from a [`TaprootBuilder`] if it is complete binary tree. /// Constructs [`TapTree`] from a [`TaprootBuilder`] if it is complete binary tree.
/// ///
/// # Returns /// # Returns
/// ///
/// A [`TapTree`] iff the `builder` is complete, otherwise return [`IncompleteBuilder`] /// A [`TapTree`] iff the `builder` is complete, otherwise return [`IncompleteBuilderError`]
/// error with the content of incomplete `builder` instance. /// error with the content of incomplete `builder` instance.
fn try_from(builder: TaprootBuilder) -> Result<Self, Self::Error> { builder.try_into_taptree() } fn try_from(builder: TaprootBuilder) -> Result<Self, Self::Error> { builder.try_into_taptree() }
} }
impl TryFrom<NodeInfo> for TapTree { impl TryFrom<NodeInfo> for TapTree {
type Error = HiddenNodes; type Error = HiddenNodesError;
/// Constructs [`TapTree`] from a [`NodeInfo`] if it is complete binary tree. /// Constructs [`TapTree`] from a [`NodeInfo`] if it is complete binary tree.
/// ///
/// # Returns /// # Returns
/// ///
/// A [`TapTree`] iff the [`NodeInfo`] has no hidden nodes, otherwise return [`HiddenNodes`] /// A [`TapTree`] iff the [`NodeInfo`] has no hidden nodes, otherwise return
/// error with the content of incomplete [`NodeInfo`] instance. /// [`HiddenNodesError`] error with the content of incomplete [`NodeInfo`] instance.
fn try_from(node_info: NodeInfo) -> Result<Self, Self::Error> { fn try_from(node_info: NodeInfo) -> Result<Self, Self::Error> {
if node_info.has_hidden_nodes { if node_info.has_hidden_nodes {
Err(HiddenNodes::HiddenParts(node_info)) Err(HiddenNodesError::HiddenParts(node_info))
} else { } else {
Ok(TapTree(node_info)) Ok(TapTree(node_info))
} }
@ -834,7 +841,7 @@ impl NodeInfo {
} }
impl TryFrom<TaprootBuilder> for NodeInfo { impl TryFrom<TaprootBuilder> for NodeInfo {
type Error = IncompleteBuilder; type Error = IncompleteBuilderError;
fn try_from(builder: TaprootBuilder) -> Result<Self, Self::Error> { fn try_from(builder: TaprootBuilder) -> Result<Self, Self::Error> {
builder.try_into_node_info() builder.try_into_node_info()
@ -1444,26 +1451,28 @@ pub enum TaprootBuilderError {
impl fmt::Display for TaprootBuilderError { impl fmt::Display for TaprootBuilderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use TaprootBuilderError::*;
match *self { match *self {
TaprootBuilderError::InvalidMerkleTreeDepth(d) => { InvalidMerkleTreeDepth(d) => {
write!( write!(
f, f,
"Merkle Tree depth({}) must be less than {}", "Merkle Tree depth({}) must be less than {}",
d, TAPROOT_CONTROL_MAX_NODE_COUNT d, TAPROOT_CONTROL_MAX_NODE_COUNT
) )
} }
TaprootBuilderError::NodeNotInDfsOrder => { NodeNotInDfsOrder => {
write!(f, "add_leaf/add_hidden must be called in DFS walk order",) write!(f, "add_leaf/add_hidden must be called in DFS walk order",)
} }
TaprootBuilderError::OverCompleteTree => write!( OverCompleteTree => write!(
f, f,
"Attempted to create a tree with two nodes at depth 0. There must\ "Attempted to create a tree with two nodes at depth 0. There must\
only be a exactly one node at depth 0", only be a exactly one node at depth 0",
), ),
TaprootBuilderError::InvalidInternalKey(ref e) => { InvalidInternalKey(ref e) => {
write_err!(f, "invalid internal x-only key"; e) write_err!(f, "invalid internal x-only key"; e)
} }
TaprootBuilderError::EmptyTree => { EmptyTree => {
write!(f, "Called finalize on an empty tree") write!(f, "Called finalize on an empty tree")
} }
} }
@ -1473,7 +1482,7 @@ impl fmt::Display for TaprootBuilderError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for TaprootBuilderError { impl std::error::Error for TaprootBuilderError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::TaprootBuilderError::*; use TaprootBuilderError::*;
match self { match self {
InvalidInternalKey(e) => Some(e), InvalidInternalKey(e) => Some(e),
@ -1504,30 +1513,32 @@ pub enum TaprootError {
impl fmt::Display for TaprootError { impl fmt::Display for TaprootError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use TaprootError::*;
match *self { match *self {
TaprootError::InvalidMerkleBranchSize(sz) => write!( InvalidMerkleBranchSize(sz) => write!(
f, f,
"Merkle branch size({}) must be a multiple of {}", "Merkle branch size({}) must be a multiple of {}",
sz, TAPROOT_CONTROL_NODE_SIZE sz, TAPROOT_CONTROL_NODE_SIZE
), ),
TaprootError::InvalidMerkleTreeDepth(d) => write!( InvalidMerkleTreeDepth(d) => write!(
f, f,
"Merkle Tree depth({}) must be less than {}", "Merkle Tree depth({}) must be less than {}",
d, TAPROOT_CONTROL_MAX_NODE_COUNT d, TAPROOT_CONTROL_MAX_NODE_COUNT
), ),
TaprootError::InvalidTaprootLeafVersion(v) => { InvalidTaprootLeafVersion(v) => {
write!(f, "Leaf version({}) must have the least significant bit 0", v) write!(f, "Leaf version({}) must have the least significant bit 0", v)
} }
TaprootError::InvalidControlBlockSize(sz) => write!( InvalidControlBlockSize(sz) => write!(
f, f,
"Control Block size({}) must be of the form 33 + 32*m where 0 <= m <= {} ", "Control Block size({}) must be of the form 33 + 32*m where 0 <= m <= {} ",
sz, TAPROOT_CONTROL_MAX_NODE_COUNT sz, TAPROOT_CONTROL_MAX_NODE_COUNT
), ),
TaprootError::InvalidInternalKey(ref e) => { InvalidInternalKey(ref e) => {
write_err!(f, "invalid internal x-only key"; e) write_err!(f, "invalid internal x-only key"; e)
} }
TaprootError::InvalidParity(_) => write!(f, "invalid parity value for internal key"), InvalidParity(_) => write!(f, "invalid parity value for internal key"),
TaprootError::EmptyTree => write!(f, "Taproot Tree must contain at least one script"), EmptyTree => write!(f, "Taproot Tree must contain at least one script"),
} }
} }
} }
@ -1535,7 +1546,7 @@ impl fmt::Display for TaprootError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl std::error::Error for TaprootError { impl std::error::Error for TaprootError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use self::TaprootError::*; use TaprootError::*;
match self { match self {
InvalidInternalKey(e) => Some(e), InvalidInternalKey(e) => Some(e),

View File

@ -225,7 +225,8 @@ pub trait Hash:
} }
/// Attempted to create a hash from an invalid length slice. /// Attempted to create a hash from an invalid length slice.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct FromSliceError { pub struct FromSliceError {
expected: usize, expected: usize,
got: usize, got: usize,

View File

@ -31,21 +31,3 @@ macro_rules! write_err {
} }
} }
} }
/// Impls std::error::Error for the specified type with appropriate attributes, possibly returning
/// source.
#[macro_export]
macro_rules! impl_std_error {
// No source available
($type:ty) => {
#[cfg(feature = "std")]
impl std::error::Error for $type {}
};
// Struct with $field as source
($type:ty, $field:ident) => {
#[cfg(feature = "std")]
impl std::error::Error for $type {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.$field) }
}
};
}

View File

@ -40,6 +40,9 @@ macro_rules! parse_error_type {
} }
} }
$crate::error::impl_std_error!($name, source); #[cfg(feature = "std")]
impl std::error::Error for $name {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.source) }
}
} }
} }