Implement std::error::source codebase wide

Audit ever error type we have and implement `source` for each.
This commit is contained in:
Tobin C. Harding 2022-05-04 15:56:24 +10:00
parent 0a9191b429
commit 97a5bb1439
22 changed files with 276 additions and 87 deletions

View File

@ -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 {

View File

@ -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.

View File

@ -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 {

View File

@ -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,
}
}
}

View File

@ -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)]

View File

@ -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<io::Error> 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,
}
}
}

View File

@ -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,
}
}
}

View File

@ -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')

View File

@ -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.

View File

@ -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<io::Error> for Error {
fn from(io: io::Error) -> Self {

View File

@ -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,
}
}
}

View File

@ -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<secp256k1::Error> for EcdsaSigError {
fn from(e: secp256k1::Error) -> EcdsaSigError {

View File

@ -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),
}
}
}

View File

@ -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,
}
}
}

View File

@ -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
}
}
}

View File

@ -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<hashes::Error> for Error {

View File

@ -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)]

View File

@ -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 {

View File

@ -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<secp256k1::Error> for SchnorrSigError {

View File

@ -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<TxOut> {
fn check_all(&self, tx: &Transaction) -> Result<(), Error> {

View File

@ -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};

View File

@ -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