From 2384712364a0ba85c3ac50b025519b174b0cbb52 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 4 May 2022 15:02:18 +1000 Subject: [PATCH 1/4] Re-order Display match arms Put the match arms in the same order as the enum that defines them. --- src/util/base58.rs | 2 +- src/util/ecdsa.rs | 7 ++++--- src/util/psbt/error.rs | 16 ++++++++-------- src/util/taproot.rs | 6 +++--- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/util/base58.rs b/src/util/base58.rs index fc525d1b..eee0deb1 100644 --- a/src/util/base58.rs +++ b/src/util/base58.rs @@ -57,8 +57,8 @@ impl fmt::Display for Error { Error::BadByte(b) => write!(f, "invalid base58 character 0x{:x}", b), Error::BadChecksum(exp, actual) => write!(f, "base58ck checksum 0x{:x} does not match expected 0x{:x}", actual, exp), Error::InvalidLength(ell) => write!(f, "length {} invalid for this base58 type", ell), - Error::InvalidAddressVersion(ref v) => write!(f, "address version {} is invalid for this base58 type", v), Error::InvalidExtendedKeyVersion(ref v) => write!(f, "extended key version {:#04x?} is invalid for this base58 type", v), + Error::InvalidAddressVersion(ref 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"), Error::Secp256k1(ref e) => fmt::Display::fmt(&e, f), Error::Hex(ref e) => write!(f, "Hexadecimal decoding error: {}", e) diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index 86c738e7..0c6f3709 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -102,13 +102,14 @@ pub enum EcdsaSigError { impl fmt::Display for EcdsaSigError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { + EcdsaSigError::HexEncoding(e) => + write!(f, "EcdsaSig hex encoding error: {}", e), EcdsaSigError::NonStandardSighashType(hash_ty) => write!(f, "Non standard signature hash type {}", hash_ty), - EcdsaSigError::Secp256k1(ref e) => - write!(f, "Invalid Ecdsa signature: {}", e), EcdsaSigError::EmptySignature => write!(f, "Empty ECDSA signature"), - EcdsaSigError::HexEncoding(e) => write!(f, "EcdsaSig hex encoding error: {}", e) + EcdsaSigError::Secp256k1(ref e) => + write!(f, "Invalid Ecdsa signature: {}", e), } } } diff --git a/src/util/psbt/error.rs b/src/util/psbt/error.rs index 672872da..e9f6a0ed 100644 --- a/src/util/psbt/error.rs +++ b/src/util/psbt/error.rs @@ -88,27 +88,27 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { + Error::InvalidMagic => f.write_str("invalid magic"), + Error::MissingUtxo => f.write_str("UTXO information is not present in PSBT"), + Error::InvalidSeparator => f.write_str("invalid separator"), + Error::PsbtUtxoOutOfbounds => f.write_str("output index is out of bounds of non witness script output array"), Error::InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey), Error::InvalidProprietaryKey => write!(f, "non-proprietary key type found when proprietary key was expected"), Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey), - Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(f, "different unsigned transaction: expected {}, actual {}", e.txid(), a.txid()), - Error::NonStandardSighashType(ref sht) => write!(f, "non-standard sighash type: {}", sht), - Error::InvalidMagic => f.write_str("invalid magic"), - Error::InvalidSeparator => f.write_str("invalid separator"), Error::UnsignedTxHasScriptSigs => f.write_str("the unsigned transaction has script sigs"), Error::UnsignedTxHasScriptWitnesses => f.write_str("the unsigned transaction has script witnesses"), Error::MustHaveUnsignedTx => { 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"), + Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(f, "different unsigned transaction: expected {}, actual {}", e.txid(), a.txid()), + Error::NonStandardSighashType(ref sht) => write!(f, "non-standard sighash type: {}", sht), Error::HashParseError(e) => write!(f, "Hash Parse Error: {}", e), - Error::MissingUtxo => f.write_str("UTXO information is not present in PSBT"), - Error::PsbtUtxoOutOfbounds => f.write_str("output index is out of bounds of non witness script output array"), Error::InvalidPreimageHashPair{ref preimage, ref hash, ref hash_type} => { // directly using debug forms of psbthash enums write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash ) - } - Error::CombineInconsistentKeySources(ref s) => { write!(f, "combine conflict: {}", s) } + }, + Error::CombineInconsistentKeySources(ref s) => { write!(f, "combine conflict: {}", s) }, Error::ConsensusEncoding => f.write_str("bitcoin consensus or BIP-174 encoding error"), } } diff --git a/src/util/taproot.rs b/src/util/taproot.rs index 1b459665..eda988b6 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -1013,6 +1013,9 @@ pub enum TaprootBuilderError { impl fmt::Display for TaprootBuilderError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { + TaprootBuilderError::InvalidMerkleTreeDepth(d) => { + write!(f, "Merkle Tree depth({}) must be less than {}", d, TAPROOT_CONTROL_MAX_NODE_COUNT) + } TaprootBuilderError::NodeNotInDfsOrder => { write!(f, "add_leaf/add_hidden must be called in DFS walk order",) } @@ -1021,9 +1024,6 @@ impl fmt::Display for TaprootBuilderError { "Attempted to create a tree with two nodes at depth 0. There must\ only be a exactly one node at depth 0", ), - TaprootBuilderError::InvalidMerkleTreeDepth(d) => { - write!(f, "Merkle Tree depth({}) must be less than {}", d, TAPROOT_CONTROL_MAX_NODE_COUNT) - } TaprootBuilderError::InvalidInternalKey(e) => { write!(f, "Invalid Internal XOnly key : {}", e) } From 7cf8af2f865abcd24470ac656dc261d881345769 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 4 May 2022 15:08:33 +1000 Subject: [PATCH 2/4] Put Error impl block below Display In an effort to be uniform throughout the codebase; put the `std::error::Error` impl block below the `Display` impl block. --- src/util/bip158.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/util/bip158.rs b/src/util/bip158.rs index 4422bcc4..cdfb8f34 100644 --- a/src/util/bip158.rs +++ b/src/util/bip158.rs @@ -74,10 +74,6 @@ pub enum Error { Io(io::Error), } -#[cfg(feature = "std")] -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for Error {} - impl Display for Error { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { match *self { @@ -87,6 +83,10 @@ impl Display for Error { } } +#[cfg(feature = "std")] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl ::std::error::Error for Error {} + impl From for Error { fn from(io: io::Error) -> Self { Error::Io(io) From 0a9191b42924e195cb67915e156373e98aa6f2bf Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 4 May 2022 15:48:23 +1000 Subject: [PATCH 3/4] Add parenthesis around left hand side of companion Parenthesis are not needed around this expression but my editor is going mad and cannot format the code without them. Since it does not hurt readability add parenthesis around the expression. --- src/util/taproot.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/taproot.rs b/src/util/taproot.rs index eda988b6..1c8e735f 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -510,7 +510,7 @@ impl TaprootBuilder { // We cannot insert a leaf at a lower depth while a deeper branch is unfinished. Doing // so would mean the add_leaf/add_hidden invocations do not correspond to a DFS traversal of a // binary tree. - if depth as usize + 1 < self.branch.len() { + if (depth as usize + 1) < self.branch.len() { return Err(TaprootBuilderError::NodeNotInDfsOrder); } From 97a5bb1439fe78a121397f6a601ea4ab5e8f9de7 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 4 May 2022 15:56:24 +1000 Subject: [PATCH 4/4] Implement std::error::source codebase wide Audit ever error type we have and implement `source` for each. --- src/blockdata/block.rs | 11 ++++++++++- src/blockdata/script.rs | 15 ++++++++++++++- src/blockdata/transaction.rs | 29 +++++++++++++++++++---------- src/consensus/encode.rs | 27 ++++++++++++++------------- src/network/message.rs | 8 ++++++-- src/network/mod.rs | 13 +++++++------ src/util/address.rs | 24 ++++++++++++++++-------- src/util/amount.rs | 2 +- src/util/base58.rs | 17 ++++++++++++++++- src/util/bip158.rs | 12 +++++++++++- src/util/bip32.rs | 21 ++++++++++++++------- src/util/ecdsa.rs | 12 +++++++++++- src/util/key.rs | 24 ++++++++++++------------ src/util/misc.rs | 13 +++++++------ src/util/mod.rs | 17 ++++++++++------- src/util/psbt/error.rs | 27 ++++++++++++++++++++++++++- src/util/psbt/map/output.rs | 10 +++++++++- src/util/psbt/mod.rs | 11 ++++++++++- src/util/schnorr.rs | 11 ++++++++++- src/util/sighash.rs | 18 +++++++++++++++++- src/util/taproot.rs | 35 +++++++++++++++++++++++++++++++---- src/util/uint.rs | 6 +++++- 22 files changed, 276 insertions(+), 87 deletions(-) diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs index 85f0fc04..06a53298 100644 --- a/src/blockdata/block.rs +++ b/src/blockdata/block.rs @@ -355,7 +355,16 @@ impl fmt::Display for Bip34Error { } #[cfg(feature = "std")] -impl ::std::error::Error for Bip34Error {} +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for Bip34Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Bip34Error::*; + + match self { + Unsupported | NotPresent | UnexpectedPush(_) => None, + } + } +} #[cfg(test)] mod tests { diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs index 7f50ff04..839a7c29 100644 --- a/src/blockdata/script.rs +++ b/src/blockdata/script.rs @@ -188,7 +188,20 @@ impl fmt::Display for Error { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for Error {} +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + NonMinimalPush + | EarlyEndOfScript + | NumericOverflow + | BitcoinConsensus(_) // TODO: This should return `Some` but bitcoinconsensus::Error does not implement Error. + | UnknownSpentOutput(_) + | SerializationError => None, + } + } +} // Our internal error proves that we only return these two cases from `read_uint_iter`. // Since it's private we don't bother with trait impls besides From. diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 7beac35c..c35a1b65 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -27,7 +27,6 @@ use crate::prelude::*; use crate::io; use core::{fmt, str, default::Default}; -#[cfg(feature = "std")] use std::error; use crate::hashes::{self, Hash, sha256d}; use crate::hashes::hex::FromHex; @@ -142,12 +141,14 @@ impl fmt::Display for ParseOutPointError { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl error::Error for ParseOutPointError { - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - ParseOutPointError::Txid(ref e) => Some(e), - ParseOutPointError::Vout(ref e) => Some(e), - _ => None, +impl std::error::Error for ParseOutPointError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::ParseOutPointError::*; + + match self { + Txid(e) => Some(e), + Vout(e) => Some(e), + Format | TooLong | VoutNotCanonical => None, } } } @@ -733,7 +734,11 @@ impl fmt::Display for NonStandardSighashType { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl error::Error for NonStandardSighashType {} +impl std::error::Error for NonStandardSighashType { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} /// Legacy Hashtype of an input's signature #[deprecated(since = "0.28.0", note = "Please use [`EcdsaSighashType`] instead")] @@ -886,9 +891,13 @@ impl fmt::Display for SighashTypeParseError { } } -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg(feature = "std")] -impl ::std::error::Error for SighashTypeParseError {} +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for SighashTypeParseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} #[cfg(test)] mod tests { diff --git a/src/consensus/encode.rs b/src/consensus/encode.rs index fe7dff14..6505df37 100644 --- a/src/consensus/encode.rs +++ b/src/consensus/encode.rs @@ -30,7 +30,6 @@ use crate::prelude::*; use core::{fmt, mem, u32, convert::From}; -#[cfg(feature = "std")] use std::error; use crate::hashes::{sha256d, Hash, sha256}; use crate::hash_types::{BlockHash, FilterHash, TxMerkleNode, FilterHeader}; @@ -106,18 +105,20 @@ impl fmt::Display for Error { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for Error { - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - Error::Io(ref e) => Some(e), - Error::Psbt(ref e) => Some(e), - Error::UnexpectedNetworkMagic { .. } - | Error::OversizedVectorAllocation { .. } - | Error::InvalidChecksum { .. } - | Error::NonMinimalVarInt - | Error::UnknownNetworkMagic(..) - | Error::ParseFailed(..) - | Error::UnsupportedSegwitFlag(..) => None, +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + Io(e) => Some(e), + Psbt(e) => Some(e), + UnexpectedNetworkMagic { .. } + | OversizedVectorAllocation { .. } + | InvalidChecksum { .. } + | NonMinimalVarInt + | UnknownNetworkMagic(_) + | ParseFailed(_) + | UnsupportedSegwitFlag(_) => None, } } } diff --git a/src/network/message.rs b/src/network/message.rs index fe9bf4e8..ea676f6b 100644 --- a/src/network/message.rs +++ b/src/network/message.rs @@ -111,9 +111,13 @@ impl fmt::Display for CommandStringError { } } -#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg(feature = "std")] -impl ::std::error::Error for CommandStringError {} +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for CommandStringError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} /// A Network message #[derive(Clone, Debug, PartialEq, Eq)] diff --git a/src/network/mod.rs b/src/network/mod.rs index 362201d4..2686e0ef 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -20,7 +20,6 @@ use crate::io; use core::fmt; -#[cfg(feature = "std")] use std::error; pub mod constants; @@ -79,11 +78,13 @@ impl From for Error { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl error::Error for Error { - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - Error::Io(ref e) => Some(e), - Error::SocketMutexPoisoned | Error::SocketNotConnectedToPeer => None, +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + Io(e) => Some(e), + SocketMutexPoisoned | SocketNotConnectedToPeer => None, } } } diff --git a/src/util/address.rs b/src/util/address.rs index b2bb8597..906649f8 100644 --- a/src/util/address.rs +++ b/src/util/address.rs @@ -37,7 +37,6 @@ use crate::prelude::*; use core::fmt; use core::num::ParseIntError; use core::str::FromStr; -#[cfg(feature = "std")] use std::error; use secp256k1::{Secp256k1, Verification, XOnlyPublicKey}; use bech32; @@ -104,13 +103,22 @@ impl fmt::Display for Error { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for Error { - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - Error::Base58(ref e) => Some(e), - Error::Bech32(ref e) => Some(e), - Error::UnparsableWitnessVersion(ref e) => Some(e), - _ => None, +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + Base58(e) => Some(e), + Bech32(e) => Some(e), + UnparsableWitnessVersion(e) => Some(e), + EmptyBech32Payload + | InvalidBech32Variant { .. } + | InvalidWitnessVersion(_) + | MalformedWitnessVersion + | InvalidWitnessProgramLength(_) + | InvalidSegwitV0ProgramLength(_) + | UncompressedPubkey + | ExcessiveScriptSize => None, } } } diff --git a/src/util/amount.rs b/src/util/amount.rs index aa888f89..eebca346 100644 --- a/src/util/amount.rs +++ b/src/util/amount.rs @@ -192,7 +192,7 @@ impl fmt::Display for ParseAmountError { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for ParseAmountError {} +impl std::error::Error for ParseAmountError {} fn is_too_precise(s: &str, precision: usize) -> bool { s.contains('.') || precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0') diff --git a/src/util/base58.rs b/src/util/base58.rs index eee0deb1..70e8c5d4 100644 --- a/src/util/base58.rs +++ b/src/util/base58.rs @@ -68,7 +68,22 @@ impl fmt::Display for Error { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for Error {} +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + BadByte(_) + | BadChecksum(_, _) + | InvalidLength(_) + | InvalidExtendedKeyVersion(_) + | InvalidAddressVersion(_) + | TooShort(_) => None, + Secp256k1(e) => Some(e), + Hex(e) => Some(e), + } + } +} /// Vector-like object that holds the first 100 elements on the stack. If more space is needed it /// will be allocated on the heap. diff --git a/src/util/bip158.rs b/src/util/bip158.rs index cdfb8f34..4dda211b 100644 --- a/src/util/bip158.rs +++ b/src/util/bip158.rs @@ -85,7 +85,17 @@ impl Display for Error { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for Error {} +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + UtxoMissing(_) => None, + Io(e) => Some(e), + } + } +} + impl From for Error { fn from(io: io::Error) -> Self { diff --git a/src/util/bip32.rs b/src/util/bip32.rs index e268e1fc..0bc23c64 100644 --- a/src/util/bip32.rs +++ b/src/util/bip32.rs @@ -22,7 +22,6 @@ use crate::prelude::*; use crate::io::Write; use core::{fmt, str::FromStr, default::Default}; use core::ops::Index; -#[cfg(feature = "std")] use std::error; #[cfg(feature = "serde")] use serde; use crate::hash_types::XpubIdentifier; @@ -497,12 +496,20 @@ impl fmt::Display for Error { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl error::Error for Error { - fn cause(&self) -> Option<&dyn error::Error> { - if let Error::Secp256k1(ref e) = *self { - Some(e) - } else { - None +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + Secp256k1(e) => Some(e), + Base58(e) => Some(e), + Hex(e) => Some(e), + CannotDeriveFromHardenedKey + | InvalidChildNumber(_) + | InvalidChildNumberFormat + | InvalidDerivationPathFormat + | UnknownVersion(_) + | WrongExtendedKeyLength(_) => None, } } } diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index 0c6f3709..1f84e718 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -116,7 +116,17 @@ impl fmt::Display for EcdsaSigError { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for EcdsaSigError {} +impl std::error::Error for EcdsaSigError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::EcdsaSigError::*; + + match self { + HexEncoding(e) => Some(e), + Secp256k1(e) => Some(e), + NonStandardSighashType(_) | EmptySignature => None, + } + } +} impl From for EcdsaSigError { fn from(e: secp256k1::Error) -> EcdsaSigError { diff --git a/src/util/key.rs b/src/util/key.rs index 156dfc90..aab5e617 100644 --- a/src/util/key.rs +++ b/src/util/key.rs @@ -16,16 +16,14 @@ //! This module provides keys used in Bitcoin that can be roundtrip //! (de)serialized. -pub use secp256k1::{XOnlyPublicKey, KeyPair}; - use crate::prelude::*; use core::{ops, str::FromStr}; use core::fmt::{self, Write}; -use crate::io; -#[cfg(feature = "std")] use std::error; -use secp256k1::{self, Secp256k1}; +pub use secp256k1::{self, Secp256k1, XOnlyPublicKey, KeyPair}; + +use crate::io; use crate::network::constants::Network; use crate::hashes::{Hash, hash160, hex, hex::FromHex}; use crate::hash_types::{PubkeyHash, WPubkeyHash}; @@ -57,13 +55,15 @@ impl fmt::Display for Error { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for Error { - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - Error::Base58(ref e) => Some(e), - Error::Secp256k1(ref e) => Some(e), - Error::InvalidKeyPrefix(_) => None, - Error::Hex(ref e) => Some(e) +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + Base58(e) => Some(e), + Secp256k1(e) => Some(e), + InvalidKeyPrefix(_) => None, + Hex(e) => Some(e), } } } diff --git a/src/util/misc.rs b/src/util/misc.rs index 43659c5a..9f61f563 100644 --- a/src/util/misc.rs +++ b/src/util/misc.rs @@ -37,7 +37,6 @@ mod message_signing { #[cfg(feature = "base64")] use crate::prelude::*; use core::fmt; - #[cfg(feature = "std")] use std::error; use crate::hashes::sha256d; use secp256k1; @@ -73,11 +72,13 @@ mod message_signing { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] - impl error::Error for MessageSignatureError { - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - MessageSignatureError::InvalidEncoding(ref e) => Some(e), - _ => None, + impl std::error::Error for MessageSignatureError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::MessageSignatureError::*; + + match self { + InvalidEncoding(e) => Some(e), + InvalidLength | InvalidBase64 | UnsupportedAddressType(_) => None, } } } diff --git a/src/util/mod.rs b/src/util/mod.rs index e15210fa..2d3d8a23 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -39,7 +39,6 @@ pub(crate) mod endian; use crate::prelude::*; use crate::io; use core::fmt; -#[cfg(feature = "std")] use std::error; use crate::network; use crate::consensus::encode; @@ -91,12 +90,16 @@ impl fmt::Display for Error { } #[cfg(feature = "std")] -impl ::std::error::Error for Error { - fn cause(&self) -> Option<&dyn error::Error> { - match *self { - Error::Encode(ref e) => Some(e), - Error::Network(ref e) => Some(e), - Error::BlockBadProofOfWork | Error::BlockBadTarget => None +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + Encode(e) => Some(e), + Network(e) => Some(e), + BlockBadProofOfWork + | BlockBadTarget => None } } } diff --git a/src/util/psbt/error.rs b/src/util/psbt/error.rs index e9f6a0ed..aa69d1a4 100644 --- a/src/util/psbt/error.rs +++ b/src/util/psbt/error.rs @@ -115,7 +115,32 @@ impl fmt::Display for Error { } #[cfg(feature = "std")] -impl ::std::error::Error for Error {} +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + HashParseError(e) => Some(e), + | InvalidMagic + | MissingUtxo + | InvalidSeparator + | PsbtUtxoOutOfbounds + | InvalidKey(_) + | InvalidProprietaryKey + | DuplicateKey(_) + | UnsignedTxHasScriptSigs + | UnsignedTxHasScriptWitnesses + | MustHaveUnsignedTx + | NoMorePairs + | UnexpectedUnsignedTx { .. } + | NonStandardSighashType(_) + | InvalidPreimageHashPair{ .. } + | CombineInconsistentKeySources(_) + | ConsensusEncoding => None, + } + } +} #[doc(hidden)] impl From for Error { diff --git a/src/util/psbt/map/output.rs b/src/util/psbt/map/output.rs index 75024551..6ebd7874 100644 --- a/src/util/psbt/map/output.rs +++ b/src/util/psbt/map/output.rs @@ -110,7 +110,15 @@ impl core::fmt::Display for IncompleteTapTree { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for IncompleteTapTree {} +impl std::error::Error for IncompleteTapTree { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::IncompleteTapTree::*; + + match self { + NotFinalized(_) | HiddenParts(_) => None, + } + } +} /// Taproot Tree representing a finalized [`TaprootBuilder`] (a complete binary tree). #[derive(Clone, Debug)] diff --git a/src/util/psbt/mod.rs b/src/util/psbt/mod.rs index 677bc4c3..9702ca1b 100644 --- a/src/util/psbt/mod.rs +++ b/src/util/psbt/mod.rs @@ -243,7 +243,16 @@ mod display_from_str { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] - impl ::std::error::Error for PsbtParseError {} + impl std::error::Error for PsbtParseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::PsbtParseError::*; + + match self { + PsbtEncoding(e) => Some(e), + Base64Encoding(e) => Some(e), + } + } + } #[cfg_attr(docsrs, doc(cfg(feature = "base64")))] impl Display for PartiallySignedTransaction { diff --git a/src/util/schnorr.rs b/src/util/schnorr.rs index cb5f59f3..8d679120 100644 --- a/src/util/schnorr.rs +++ b/src/util/schnorr.rs @@ -286,7 +286,16 @@ impl fmt::Display for SchnorrSigError { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for SchnorrSigError {} +impl std::error::Error for SchnorrSigError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::SchnorrSigError::*; + + match self { + Secp256k1(e) => Some(e), + InvalidSighashType(_) | InvalidSchnorrSigSize(_) => None, + } + } +} impl From for SchnorrSigError { diff --git a/src/util/sighash.rs b/src/util/sighash.rs index ebcd43a9..515f6cf1 100644 --- a/src/util/sighash.rs +++ b/src/util/sighash.rs @@ -223,7 +223,23 @@ impl fmt::Display for Error { } #[cfg(feature = "std")] -impl ::std::error::Error for Error {} +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::Error::*; + + match self { + Io(_) + | IndexOutOfInputsBounds { .. } + | SingleWithoutCorrespondingOutput { .. } + | PrevoutsSize + | PrevoutIndex + | PrevoutKind + | WrongAnnex + | InvalidSighashType(_) => None, + } + } +} impl<'u, T> Prevouts<'u, T> where T: Borrow { fn check_all(&self, tx: &Transaction) -> Result<(), Error> { diff --git a/src/util/taproot.rs b/src/util/taproot.rs index 1c8e735f..cd28683a 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -22,8 +22,6 @@ use secp256k1::{self, Secp256k1}; use core::fmt; use core::cmp::Reverse; -#[cfg(feature = "std")] -use std::error; use crate::hashes::{sha256, sha256t, Hash, HashEngine}; use crate::schnorr::{TweakedPublicKey, UntweakedPublicKey, TapTweak}; @@ -1039,7 +1037,20 @@ impl fmt::Display for TaprootBuilderError { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl error::Error for TaprootBuilderError {} +impl std::error::Error for TaprootBuilderError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::TaprootBuilderError::*; + + match self { + InvalidInternalKey(e) => Some(e), + InvalidMerkleTreeDepth(_) + | NodeNotInDfsOrder + | OverCompleteTree + | IncompleteTree + | EmptyTree => None + } + } +} /// Detailed error type for taproot utilities. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -1093,7 +1104,23 @@ impl fmt::Display for TaprootError { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl error::Error for TaprootError {} +impl std::error::Error for TaprootError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + use self::TaprootError::*; + + match self { + InvalidInternalKey(e) => Some(e), + InvalidMerkleBranchSize(_) + | InvalidMerkleTreeDepth(_) + | InvalidTaprootLeafVersion(_) + | InvalidControlBlockSize(_) + | InvalidParity(_) + | EmptyTree => None, + } + } +} + + #[cfg(test)] mod test { use crate::{Address, Network}; diff --git a/src/util/uint.rs b/src/util/uint.rs index f19db23f..ccb702e7 100644 --- a/src/util/uint.rs +++ b/src/util/uint.rs @@ -528,7 +528,11 @@ impl ::core::fmt::Display for ParseLengthError { #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] -impl ::std::error::Error for ParseLengthError {} +impl std::error::Error for ParseLengthError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} impl Uint256 { /// Decay to a uint128