Merge rust-bitcoin/rust-bitcoin#987: Implement `std::error::Error` for the new MSRV

97a5bb1439 Implement std::error::source codebase wide (Tobin C. Harding)
0a9191b429 Add parenthesis around left hand side of companion (Tobin C. Harding)
7cf8af2f86 Put Error impl block below Display (Tobin C. Harding)
2384712364 Re-order Display match arms (Tobin C. Harding)

Pull request description:

  Now that we have MSRV of 1.41.1 we should use `source` instead of `cause`. Audit the whole codebase and implement `source` for _every_ error type we have.

  The first three patches are preparatory cleanup, patch 3 is particularly shameful (adds parenthesis to make my editor work).

  CC @Kixunil because he is championing the error stuff.

ACKs for top commit:
  apoelstra:
    ACK 97a5bb1439

Tree-SHA512: 46313a28929445f32e01e30ca3b0246b30bc9d5e43db5754d4b441e9c30d3e427efaf247100eb6b452f98beec5a4fcde1daba7943a772114aa34f78ab52cbc60
This commit is contained in:
Andrew Poelstra 2022-05-21 14:08:28 +00:00
commit 0e82376bf8
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
22 changed files with 296 additions and 106 deletions

View File

@ -355,7 +355,16 @@ impl fmt::Display for Bip34Error {
} }
#[cfg(feature = "std")] #[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)] #[cfg(test)]
mod tests { mod tests {

View File

@ -188,7 +188,20 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(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`. // 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. // 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 crate::io;
use core::{fmt, str, default::Default}; use core::{fmt, str, default::Default};
#[cfg(feature = "std")] use std::error;
use crate::hashes::{self, Hash, sha256d}; use crate::hashes::{self, Hash, sha256d};
use crate::hashes::hex::FromHex; use crate::hashes::hex::FromHex;
@ -142,12 +141,14 @@ impl fmt::Display for ParseOutPointError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl error::Error for ParseOutPointError { impl std::error::Error for ParseOutPointError {
fn cause(&self) -> Option<&dyn error::Error> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self { use self::ParseOutPointError::*;
ParseOutPointError::Txid(ref e) => Some(e),
ParseOutPointError::Vout(ref e) => Some(e), match self {
_ => None, 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(feature = "std")]
#[cfg_attr(docsrs, doc(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 /// Legacy Hashtype of an input's signature
#[deprecated(since = "0.28.0", note = "Please use [`EcdsaSighashType`] instead")] #[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")] #[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)] #[cfg(test)]
mod tests { mod tests {

View File

@ -30,7 +30,6 @@
use crate::prelude::*; use crate::prelude::*;
use core::{fmt, mem, u32, convert::From}; use core::{fmt, mem, u32, convert::From};
#[cfg(feature = "std")] use std::error;
use crate::hashes::{sha256d, Hash, sha256}; use crate::hashes::{sha256d, Hash, sha256};
use crate::hash_types::{BlockHash, FilterHash, TxMerkleNode, FilterHeader}; use crate::hash_types::{BlockHash, FilterHash, TxMerkleNode, FilterHeader};
@ -106,18 +105,20 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl ::std::error::Error for Error { impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self { use self::Error::*;
Error::Io(ref e) => Some(e),
Error::Psbt(ref e) => Some(e), match self {
Error::UnexpectedNetworkMagic { .. } Io(e) => Some(e),
| Error::OversizedVectorAllocation { .. } Psbt(e) => Some(e),
| Error::InvalidChecksum { .. } UnexpectedNetworkMagic { .. }
| Error::NonMinimalVarInt | OversizedVectorAllocation { .. }
| Error::UnknownNetworkMagic(..) | InvalidChecksum { .. }
| Error::ParseFailed(..) | NonMinimalVarInt
| Error::UnsupportedSegwitFlag(..) => None, | 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")] #[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 /// A Network message
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]

View File

@ -20,7 +20,6 @@
use crate::io; use crate::io;
use core::fmt; use core::fmt;
#[cfg(feature = "std")] use std::error;
pub mod constants; pub mod constants;
@ -79,11 +78,13 @@ impl From<io::Error> for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl error::Error for Error { impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self { use self::Error::*;
Error::Io(ref e) => Some(e),
Error::SocketMutexPoisoned | Error::SocketNotConnectedToPeer => None, match self {
Io(e) => Some(e),
SocketMutexPoisoned | SocketNotConnectedToPeer => None,
} }
} }
} }

View File

@ -37,7 +37,6 @@ use crate::prelude::*;
use core::fmt; use core::fmt;
use core::num::ParseIntError; use core::num::ParseIntError;
use core::str::FromStr; use core::str::FromStr;
#[cfg(feature = "std")] use std::error;
use secp256k1::{Secp256k1, Verification, XOnlyPublicKey}; use secp256k1::{Secp256k1, Verification, XOnlyPublicKey};
use bech32; use bech32;
@ -104,13 +103,22 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl ::std::error::Error for Error { impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self { use self::Error::*;
Error::Base58(ref e) => Some(e),
Error::Bech32(ref e) => Some(e), match self {
Error::UnparsableWitnessVersion(ref e) => Some(e), Base58(e) => Some(e),
_ => None, 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(feature = "std")]
#[cfg_attr(docsrs, doc(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 { fn is_too_precise(s: &str, precision: usize) -> bool {
s.contains('.') || precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0') s.contains('.') || precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0')

View File

@ -57,8 +57,8 @@ impl fmt::Display for Error {
Error::BadByte(b) => write!(f, "invalid base58 character 0x{:x}", b), 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::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::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::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::TooShort(_) => write!(f, "base58ck data not even long enough for a checksum"),
Error::Secp256k1(ref e) => fmt::Display::fmt(&e, f), Error::Secp256k1(ref e) => fmt::Display::fmt(&e, f),
Error::Hex(ref e) => write!(f, "Hexadecimal decoding error: {}", e) Error::Hex(ref e) => write!(f, "Hexadecimal decoding error: {}", e)
@ -68,7 +68,22 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(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 /// Vector-like object that holds the first 100 elements on the stack. If more space is needed it
/// will be allocated on the heap. /// will be allocated on the heap.

View File

@ -74,10 +74,6 @@ pub enum Error {
Io(io::Error), Io(io::Error),
} }
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl ::std::error::Error for 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> {
match *self { match *self {
@ -87,6 +83,20 @@ impl Display for Error {
} }
} }
#[cfg(feature = "std")]
#[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 {
UtxoMissing(_) => None,
Io(e) => Some(e),
}
}
}
impl From<io::Error> for Error { impl From<io::Error> for Error {
fn from(io: io::Error) -> Self { fn from(io: io::Error) -> Self {
Error::Io(io) Error::Io(io)

View File

@ -22,7 +22,6 @@ use crate::prelude::*;
use crate::io::Write; use crate::io::Write;
use core::{fmt, str::FromStr, default::Default}; use core::{fmt, str::FromStr, default::Default};
use core::ops::Index; use core::ops::Index;
#[cfg(feature = "std")] use std::error;
#[cfg(feature = "serde")] use serde; #[cfg(feature = "serde")] use serde;
use crate::hash_types::XpubIdentifier; use crate::hash_types::XpubIdentifier;
@ -497,12 +496,20 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl error::Error for Error { impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
if let Error::Secp256k1(ref e) = *self { use self::Error::*;
Some(e)
} else { match self {
None Secp256k1(e) => Some(e),
Base58(e) => Some(e),
Hex(e) => Some(e),
CannotDeriveFromHardenedKey
| InvalidChildNumber(_)
| InvalidChildNumberFormat
| InvalidDerivationPathFormat
| UnknownVersion(_)
| WrongExtendedKeyLength(_) => None,
} }
} }
} }

View File

@ -102,20 +102,31 @@ pub enum EcdsaSigError {
impl fmt::Display for EcdsaSigError { impl fmt::Display for EcdsaSigError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self { match *self {
EcdsaSigError::HexEncoding(e) =>
write!(f, "EcdsaSig hex encoding error: {}", e),
EcdsaSigError::NonStandardSighashType(hash_ty) => EcdsaSigError::NonStandardSighashType(hash_ty) =>
write!(f, "Non standard signature hash type {}", hash_ty), write!(f, "Non standard signature hash type {}", hash_ty),
EcdsaSigError::Secp256k1(ref e) =>
write!(f, "Invalid Ecdsa signature: {}", e),
EcdsaSigError::EmptySignature => EcdsaSigError::EmptySignature =>
write!(f, "Empty ECDSA signature"), 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),
} }
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(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 { impl From<secp256k1::Error> for EcdsaSigError {
fn from(e: secp256k1::Error) -> EcdsaSigError { fn from(e: secp256k1::Error) -> EcdsaSigError {

View File

@ -16,16 +16,14 @@
//! This module provides keys used in Bitcoin that can be roundtrip //! This module provides keys used in Bitcoin that can be roundtrip
//! (de)serialized. //! (de)serialized.
pub use secp256k1::{XOnlyPublicKey, KeyPair};
use crate::prelude::*; use crate::prelude::*;
use core::{ops, str::FromStr}; use core::{ops, str::FromStr};
use core::fmt::{self, Write}; 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::network::constants::Network;
use crate::hashes::{Hash, hash160, hex, hex::FromHex}; use crate::hashes::{Hash, hash160, hex, hex::FromHex};
use crate::hash_types::{PubkeyHash, WPubkeyHash}; use crate::hash_types::{PubkeyHash, WPubkeyHash};
@ -57,13 +55,15 @@ impl fmt::Display for Error {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl ::std::error::Error for Error { impl std::error::Error for Error {
fn cause(&self) -> Option<&dyn error::Error> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self { use self::Error::*;
Error::Base58(ref e) => Some(e),
Error::Secp256k1(ref e) => Some(e), match self {
Error::InvalidKeyPrefix(_) => None, Base58(e) => Some(e),
Error::Hex(ref 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::*; #[cfg(feature = "base64")] use crate::prelude::*;
use core::fmt; use core::fmt;
#[cfg(feature = "std")] use std::error;
use crate::hashes::sha256d; use crate::hashes::sha256d;
use secp256k1; use secp256k1;
@ -73,11 +72,13 @@ mod message_signing {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))] #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
impl error::Error for MessageSignatureError { impl std::error::Error for MessageSignatureError {
fn cause(&self) -> Option<&dyn error::Error> { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match *self { use self::MessageSignatureError::*;
MessageSignatureError::InvalidEncoding(ref e) => Some(e),
_ => None, 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::prelude::*;
use crate::io; use crate::io;
use core::fmt; use core::fmt;
#[cfg(feature = "std")] use std::error;
use crate::network; use crate::network;
use crate::consensus::encode; use crate::consensus::encode;
@ -91,12 +90,16 @@ impl fmt::Display for Error {
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl ::std::error::Error for Error { #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
fn cause(&self) -> Option<&dyn error::Error> { impl std::error::Error for Error {
match *self { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
Error::Encode(ref e) => Some(e), use self::Error::*;
Error::Network(ref e) => Some(e),
Error::BlockBadProofOfWork | Error::BlockBadTarget => None match self {
Encode(e) => Some(e),
Network(e) => Some(e),
BlockBadProofOfWork
| BlockBadTarget => None
} }
} }
} }

View File

@ -88,34 +88,59 @@ 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 {
match *self { 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::InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey),
Error::InvalidProprietaryKey => write!(f, "non-proprietary key type found when proprietary key was expected"), Error::InvalidProprietaryKey => write!(f, "non-proprietary key type found when proprietary key was expected"),
Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey), 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::UnsignedTxHasScriptSigs => f.write_str("the unsigned transaction has script sigs"),
Error::UnsignedTxHasScriptWitnesses => f.write_str("the unsigned transaction has script witnesses"), Error::UnsignedTxHasScriptWitnesses => f.write_str("the unsigned transaction has script witnesses"),
Error::MustHaveUnsignedTx => { Error::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"), 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::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} => { 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) => { 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"), Error::ConsensusEncoding => f.write_str("bitcoin consensus or BIP-174 encoding error"),
} }
} }
} }
#[cfg(feature = "std")] #[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)] #[doc(hidden)]
impl From<hashes::Error> for Error { impl From<hashes::Error> for Error {

View File

@ -110,7 +110,15 @@ impl core::fmt::Display for IncompleteTapTree {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(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). /// Taproot Tree representing a finalized [`TaprootBuilder`] (a complete binary tree).
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View File

@ -241,7 +241,16 @@ mod display_from_str {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(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")))] #[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
impl Display for PartiallySignedTransaction { impl Display for PartiallySignedTransaction {

View File

@ -286,7 +286,16 @@ impl fmt::Display for SchnorrSigError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(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 { impl From<secp256k1::Error> for SchnorrSigError {

View File

@ -224,7 +224,23 @@ impl fmt::Display for Error {
} }
#[cfg(feature = "std")] #[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> { impl<'u, T> Prevouts<'u, T> where T: Borrow<TxOut> {
fn check_all(&self, tx: &Transaction) -> Result<(), Error> { fn check_all(&self, tx: &Transaction) -> Result<(), Error> {

View File

@ -22,8 +22,6 @@ use secp256k1::{self, Secp256k1};
use core::fmt; use core::fmt;
use core::cmp::Reverse; use core::cmp::Reverse;
#[cfg(feature = "std")]
use std::error;
use crate::hashes::{sha256, Hash, HashEngine}; use crate::hashes::{sha256, Hash, HashEngine};
use crate::schnorr::{TweakedPublicKey, UntweakedPublicKey, TapTweak}; use crate::schnorr::{TweakedPublicKey, UntweakedPublicKey, TapTweak};
@ -486,7 +484,7 @@ impl TaprootBuilder {
// We cannot insert a leaf at a lower depth while a deeper branch is unfinished. Doing // 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 // so would mean the add_leaf/add_hidden invocations do not correspond to a DFS traversal of a
// binary tree. // binary tree.
if depth as usize + 1 < self.branch.len() { if (depth as usize + 1) < self.branch.len() {
return Err(TaprootBuilderError::NodeNotInDfsOrder); return Err(TaprootBuilderError::NodeNotInDfsOrder);
} }
@ -989,6 +987,9 @@ 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 {
match *self { match *self {
TaprootBuilderError::InvalidMerkleTreeDepth(d) => {
write!(f, "Merkle Tree depth({}) must be less than {}", d, TAPROOT_CONTROL_MAX_NODE_COUNT)
}
TaprootBuilderError::NodeNotInDfsOrder => { TaprootBuilderError::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",)
} }
@ -997,9 +998,6 @@ impl fmt::Display for TaprootBuilderError {
"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::InvalidMerkleTreeDepth(d) => {
write!(f, "Merkle Tree depth({}) must be less than {}", d, TAPROOT_CONTROL_MAX_NODE_COUNT)
}
TaprootBuilderError::InvalidInternalKey(e) => { TaprootBuilderError::InvalidInternalKey(e) => {
write!(f, "Invalid Internal XOnly key : {}", e) write!(f, "Invalid Internal XOnly key : {}", e)
} }
@ -1015,7 +1013,20 @@ impl fmt::Display for TaprootBuilderError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(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. /// Detailed error type for taproot utilities.
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@ -1069,7 +1080,23 @@ impl fmt::Display for TaprootError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(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)] #[cfg(test)]
mod test { mod test {
use crate::{Address, Network}; use crate::{Address, Network};

View File

@ -528,7 +528,11 @@ impl ::core::fmt::Display for ParseLengthError {
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(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 { impl Uint256 {
/// Decay to a uint128 /// Decay to a uint128