Skip to content

Commit fd6b9f4

Browse files
committed
Merge rust-bitcoin/rust-bitcoin#987: Implement std::error::Error for the new MSRV
97a5bb1 Implement std::error::source codebase wide (Tobin C. Harding) 0a9191b Add parenthesis around left hand side of companion (Tobin C. Harding) 7cf8af2 Put Error impl block below Display (Tobin C. Harding) 2384712 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 97a5bb1 Tree-SHA512: 46313a28929445f32e01e30ca3b0246b30bc9d5e43db5754d4b441e9c30d3e427efaf247100eb6b452f98beec5a4fcde1daba7943a772114aa34f78ab52cbc60
2 parents c2d06a2 + b7b4a25 commit fd6b9f4

File tree

22 files changed

+296
-106
lines changed

22 files changed

+296
-106
lines changed

src/blockdata/block.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,16 @@ impl fmt::Display for Bip34Error {
355355
}
356356

357357
#[cfg(feature = "std")]
358-
impl ::std::error::Error for Bip34Error {}
358+
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
359+
impl std::error::Error for Bip34Error {
360+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
361+
use self::Bip34Error::*;
362+
363+
match self {
364+
Unsupported | NotPresent | UnexpectedPush(_) => None,
365+
}
366+
}
367+
}
359368

360369
#[cfg(test)]
361370
mod tests {

src/blockdata/script.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,20 @@ impl fmt::Display for Error {
188188

189189
#[cfg(feature = "std")]
190190
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
191-
impl ::std::error::Error for Error {}
191+
impl std::error::Error for Error {
192+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
193+
use self::Error::*;
194+
195+
match self {
196+
NonMinimalPush
197+
| EarlyEndOfScript
198+
| NumericOverflow
199+
| BitcoinConsensus(_) // TODO: This should return `Some` but bitcoinconsensus::Error does not implement Error.
200+
| UnknownSpentOutput(_)
201+
| SerializationError => None,
202+
}
203+
}
204+
}
192205

193206
// Our internal error proves that we only return these two cases from `read_uint_iter`.
194207
// Since it's private we don't bother with trait impls besides From.

src/blockdata/transaction.rs

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use crate::prelude::*;
2727

2828
use crate::io;
2929
use core::{fmt, str, default::Default};
30-
#[cfg(feature = "std")] use std::error;
3130

3231
use crate::hashes::{self, Hash, sha256d};
3332
use crate::hashes::hex::FromHex;
@@ -142,12 +141,14 @@ impl fmt::Display for ParseOutPointError {
142141

143142
#[cfg(feature = "std")]
144143
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
145-
impl error::Error for ParseOutPointError {
146-
fn cause(&self) -> Option<&dyn error::Error> {
147-
match *self {
148-
ParseOutPointError::Txid(ref e) => Some(e),
149-
ParseOutPointError::Vout(ref e) => Some(e),
150-
_ => None,
144+
impl std::error::Error for ParseOutPointError {
145+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
146+
use self::ParseOutPointError::*;
147+
148+
match self {
149+
Txid(e) => Some(e),
150+
Vout(e) => Some(e),
151+
Format | TooLong | VoutNotCanonical => None,
151152
}
152153
}
153154
}
@@ -733,7 +734,11 @@ impl fmt::Display for NonStandardSighashType {
733734

734735
#[cfg(feature = "std")]
735736
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
736-
impl error::Error for NonStandardSighashType {}
737+
impl std::error::Error for NonStandardSighashType {
738+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
739+
None
740+
}
741+
}
737742

738743
/// Legacy Hashtype of an input's signature
739744
#[deprecated(since = "0.28.0", note = "Please use [`EcdsaSighashType`] instead")]
@@ -886,9 +891,13 @@ impl fmt::Display for SighashTypeParseError {
886891
}
887892
}
888893

889-
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
890894
#[cfg(feature = "std")]
891-
impl ::std::error::Error for SighashTypeParseError {}
895+
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
896+
impl std::error::Error for SighashTypeParseError {
897+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
898+
None
899+
}
900+
}
892901

893902
#[cfg(test)]
894903
mod tests {

src/consensus/encode.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
use crate::prelude::*;
3131

3232
use core::{fmt, mem, u32, convert::From};
33-
#[cfg(feature = "std")] use std::error;
3433

3534
use crate::hashes::{sha256d, Hash, sha256};
3635
use crate::hash_types::{BlockHash, FilterHash, TxMerkleNode, FilterHeader};
@@ -106,18 +105,20 @@ impl fmt::Display for Error {
106105

107106
#[cfg(feature = "std")]
108107
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
109-
impl ::std::error::Error for Error {
110-
fn cause(&self) -> Option<&dyn error::Error> {
111-
match *self {
112-
Error::Io(ref e) => Some(e),
113-
Error::Psbt(ref e) => Some(e),
114-
Error::UnexpectedNetworkMagic { .. }
115-
| Error::OversizedVectorAllocation { .. }
116-
| Error::InvalidChecksum { .. }
117-
| Error::NonMinimalVarInt
118-
| Error::UnknownNetworkMagic(..)
119-
| Error::ParseFailed(..)
120-
| Error::UnsupportedSegwitFlag(..) => None,
108+
impl std::error::Error for Error {
109+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
110+
use self::Error::*;
111+
112+
match self {
113+
Io(e) => Some(e),
114+
Psbt(e) => Some(e),
115+
UnexpectedNetworkMagic { .. }
116+
| OversizedVectorAllocation { .. }
117+
| InvalidChecksum { .. }
118+
| NonMinimalVarInt
119+
| UnknownNetworkMagic(_)
120+
| ParseFailed(_)
121+
| UnsupportedSegwitFlag(_) => None,
121122
}
122123
}
123124
}

src/network/message.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,13 @@ impl fmt::Display for CommandStringError {
111111
}
112112
}
113113

114-
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
115114
#[cfg(feature = "std")]
116-
impl ::std::error::Error for CommandStringError {}
115+
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
116+
impl std::error::Error for CommandStringError {
117+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
118+
None
119+
}
120+
}
117121

118122
/// A Network message
119123
#[derive(Clone, Debug, PartialEq, Eq)]

src/network/mod.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
2121
use crate::io;
2222
use core::fmt;
23-
#[cfg(feature = "std")] use std::error;
2423

2524
pub mod constants;
2625

@@ -79,11 +78,13 @@ impl From<io::Error> for Error {
7978

8079
#[cfg(feature = "std")]
8180
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
82-
impl error::Error for Error {
83-
fn cause(&self) -> Option<&dyn error::Error> {
84-
match *self {
85-
Error::Io(ref e) => Some(e),
86-
Error::SocketMutexPoisoned | Error::SocketNotConnectedToPeer => None,
81+
impl std::error::Error for Error {
82+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
83+
use self::Error::*;
84+
85+
match self {
86+
Io(e) => Some(e),
87+
SocketMutexPoisoned | SocketNotConnectedToPeer => None,
8788
}
8889
}
8990
}

src/util/address.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ use crate::prelude::*;
3737
use core::fmt;
3838
use core::num::ParseIntError;
3939
use core::str::FromStr;
40-
#[cfg(feature = "std")] use std::error;
4140

4241
use secp256k1::{Secp256k1, Verification, XOnlyPublicKey};
4342
use bech32;
@@ -104,13 +103,22 @@ impl fmt::Display for Error {
104103

105104
#[cfg(feature = "std")]
106105
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
107-
impl ::std::error::Error for Error {
108-
fn cause(&self) -> Option<&dyn error::Error> {
109-
match *self {
110-
Error::Base58(ref e) => Some(e),
111-
Error::Bech32(ref e) => Some(e),
112-
Error::UnparsableWitnessVersion(ref e) => Some(e),
113-
_ => None,
106+
impl std::error::Error for Error {
107+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
108+
use self::Error::*;
109+
110+
match self {
111+
Base58(e) => Some(e),
112+
Bech32(e) => Some(e),
113+
UnparsableWitnessVersion(e) => Some(e),
114+
EmptyBech32Payload
115+
| InvalidBech32Variant { .. }
116+
| InvalidWitnessVersion(_)
117+
| MalformedWitnessVersion
118+
| InvalidWitnessProgramLength(_)
119+
| InvalidSegwitV0ProgramLength(_)
120+
| UncompressedPubkey
121+
| ExcessiveScriptSize => None,
114122
}
115123
}
116124
}

src/util/amount.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ impl fmt::Display for ParseAmountError {
192192

193193
#[cfg(feature = "std")]
194194
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
195-
impl ::std::error::Error for ParseAmountError {}
195+
impl std::error::Error for ParseAmountError {}
196196

197197
fn is_too_precise(s: &str, precision: usize) -> bool {
198198
s.contains('.') || precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0')

src/util/base58.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ impl fmt::Display for Error {
5757
Error::BadByte(b) => write!(f, "invalid base58 character 0x{:x}", b),
5858
Error::BadChecksum(exp, actual) => write!(f, "base58ck checksum 0x{:x} does not match expected 0x{:x}", actual, exp),
5959
Error::InvalidLength(ell) => write!(f, "length {} invalid for this base58 type", ell),
60-
Error::InvalidAddressVersion(ref v) => write!(f, "address version {} is invalid for this base58 type", v),
6160
Error::InvalidExtendedKeyVersion(ref v) => write!(f, "extended key version {:#04x?} is invalid for this base58 type", v),
61+
Error::InvalidAddressVersion(ref v) => write!(f, "address version {} is invalid for this base58 type", v),
6262
Error::TooShort(_) => write!(f, "base58ck data not even long enough for a checksum"),
6363
Error::Secp256k1(ref e) => fmt::Display::fmt(&e, f),
6464
Error::Hex(ref e) => write!(f, "Hexadecimal decoding error: {}", e)
@@ -68,7 +68,22 @@ impl fmt::Display for Error {
6868

6969
#[cfg(feature = "std")]
7070
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
71-
impl ::std::error::Error for Error {}
71+
impl std::error::Error for Error {
72+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
73+
use self::Error::*;
74+
75+
match self {
76+
BadByte(_)
77+
| BadChecksum(_, _)
78+
| InvalidLength(_)
79+
| InvalidExtendedKeyVersion(_)
80+
| InvalidAddressVersion(_)
81+
| TooShort(_) => None,
82+
Secp256k1(e) => Some(e),
83+
Hex(e) => Some(e),
84+
}
85+
}
86+
}
7287

7388
/// Vector-like object that holds the first 100 elements on the stack. If more space is needed it
7489
/// will be allocated on the heap.

src/util/bip158.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,6 @@ pub enum Error {
7474
Io(io::Error),
7575
}
7676

77-
#[cfg(feature = "std")]
78-
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
79-
impl ::std::error::Error for Error {}
80-
8177
impl Display for Error {
8278
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
8379
match *self {
@@ -87,6 +83,20 @@ impl Display for Error {
8783
}
8884
}
8985

86+
#[cfg(feature = "std")]
87+
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
88+
impl std::error::Error for Error {
89+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
90+
use self::Error::*;
91+
92+
match self {
93+
UtxoMissing(_) => None,
94+
Io(e) => Some(e),
95+
}
96+
}
97+
}
98+
99+
90100
impl From<io::Error> for Error {
91101
fn from(io: io::Error) -> Self {
92102
Error::Io(io)

0 commit comments

Comments
 (0)