From 57dd6739c3660522aaf6efd3b911ffdd40028a7f Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Wed, 25 May 2022 12:56:51 +1000 Subject: [PATCH] Do not print error when displaying for std builds We implement `source` for all our error types. This means that we should not display the source error explicitly because users can call `source` to get the source error. However, `std::Error::source()` is only available for "std" builds, so that we do not loose the error source information in "no-std" builds add a macro that conditionally adds the source onto the error message. --- src/blockdata/transaction.rs | 4 ++-- src/consensus/encode.rs | 4 ++-- src/internal_macros.rs | 19 +++++++++++++++++++ src/network/mod.rs | 2 +- src/util/address.rs | 6 +++--- src/util/base58.rs | 4 ++-- src/util/bip158.rs | 2 +- src/util/bip32.rs | 6 +++--- src/util/ecdsa.rs | 6 +++--- src/util/key.rs | 6 +++--- src/util/misc.rs | 2 +- src/util/mod.rs | 4 ++-- src/util/psbt/error.rs | 2 +- src/util/psbt/mod.rs | 13 +++++++++---- src/util/schnorr.rs | 2 +- src/util/taproot.rs | 9 ++++----- 16 files changed, 57 insertions(+), 34 deletions(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index c35a1b65..9d00ce88 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -130,8 +130,8 @@ pub enum ParseOutPointError { impl fmt::Display for ParseOutPointError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - ParseOutPointError::Txid(ref e) => write!(f, "error parsing TXID: {}", e), - ParseOutPointError::Vout(ref e) => write!(f, "error parsing vout: {}", e), + ParseOutPointError::Txid(ref e) => write_err!(f, "error parsing TXID"; e), + ParseOutPointError::Vout(ref e) => write_err!(f, "error parsing vout"; e), ParseOutPointError::Format => write!(f, "OutPoint not in : format"), ParseOutPointError::TooLong => write!(f, "vout should be at most 10 digits"), ParseOutPointError::VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"), diff --git a/src/consensus/encode.rs b/src/consensus/encode.rs index 6db2fe4f..894ec89f 100644 --- a/src/consensus/encode.rs +++ b/src/consensus/encode.rs @@ -86,8 +86,8 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::Io(ref e) => write!(f, "I/O error: {}", e), - Error::Psbt(ref e) => write!(f, "PSBT error: {}", e), + Error::Io(ref e) => write_err!(f, "IO error"; e), + Error::Psbt(ref e) => write_err!(f, "PSBT error"; e), Error::UnexpectedNetworkMagic { expected: ref e, actual: ref a } => write!(f, "unexpected network magic: expected {}, actual {}", e, a), Error::OversizedVectorAllocation { requested: ref r, max: ref m } => write!(f, diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 1814420b..516baf81 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -564,3 +564,22 @@ macro_rules! user_enum { } ); } + +/// Formats error. If `std` feature is OFF appends error source (delimited by `: `). We do this +/// because `e.source()` is only available in std builds, without this macro the error source is +/// lost for no-std builds. +macro_rules! write_err { + ($writer:expr, $string:literal $(, $args:expr),*; $source:expr) => { + { + #[cfg(feature = "std")] + { + let _ = &$source; // Prevents clippy warnings. + write!($writer, $string $(, $args)*) + } + #[cfg(not(feature = "std"))] + { + write!($writer, concat!($string, ": {}") $(, $args)*, $source) + } + } + } +} diff --git a/src/network/mod.rs b/src/network/mod.rs index 25cdf3d8..45f2f73f 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -58,7 +58,7 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::Io(ref e) => fmt::Display::fmt(e, f), + Error::Io(ref e) => write_err!(f, "IO error"; e), } } } diff --git a/src/util/address.rs b/src/util/address.rs index afa4c714..a86e5422 100644 --- a/src/util/address.rs +++ b/src/util/address.rs @@ -86,12 +86,12 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::Base58(_) => write!(f, "base58 address encoding error"), - Error::Bech32(_) => write!(f, "bech32 address encoding error"), + Error::Base58(ref e) => write_err!(f, "base58 address encoding error"; e), + Error::Bech32(ref e) => write_err!(f, "bech32 address encoding error"; e), Error::EmptyBech32Payload => write!(f, "the bech32 payload was empty"), Error::InvalidBech32Variant { expected, found } => write!(f, "invalid bech32 checksum variant found {:?} when {:?} was expected", found, expected), Error::InvalidWitnessVersion(v) => write!(f, "invalid witness script version: {}", v), - Error::UnparsableWitnessVersion(_) => write!(f, "incorrect format of a witness version byte"), + Error::UnparsableWitnessVersion(ref e) => write_err!(f, "incorrect format of a witness version byte"; e), Error::MalformedWitnessVersion => f.write_str("bitcoin script opcode does not match any known witness version, the script is malformed"), Error::InvalidWitnessProgramLength(l) => write!(f, "the witness program must be between 2 and 40 bytes in length: length={}", l), Error::InvalidSegwitV0ProgramLength(l) => write!(f, "a v0 witness program must be either of length 20 or 32 bytes: length={}", l), diff --git a/src/util/base58.rs b/src/util/base58.rs index 70e8c5d4..fc249654 100644 --- a/src/util/base58.rs +++ b/src/util/base58.rs @@ -60,8 +60,8 @@ impl fmt::Display for Error { 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) + Error::Secp256k1(ref e) => write_err!(f, "secp256k1 error while parsing secret key"; e), + Error::Hex(ref e) => write_err!(f, "hexadecimal decoding error"; e) } } } diff --git a/src/util/bip158.rs b/src/util/bip158.rs index 4dda211b..fa52a167 100644 --- a/src/util/bip158.rs +++ b/src/util/bip158.rs @@ -78,7 +78,7 @@ impl Display for Error { fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { match *self { Error::UtxoMissing(ref coin) => write!(f, "unresolved UTXO {}", coin), - Error::Io(ref io) => write!(f, "{}", io) + Error::Io(ref e) => write_err!(f, "IO error"; e), } } } diff --git a/src/util/bip32.rs b/src/util/bip32.rs index 0bc23c64..af9b4d79 100644 --- a/src/util/bip32.rs +++ b/src/util/bip32.rs @@ -482,14 +482,14 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::CannotDeriveFromHardenedKey => f.write_str("cannot derive hardened key from public key"), - Error::Secp256k1(ref e) => fmt::Display::fmt(e, f), + Error::Secp256k1(ref e) => write_err!(f, "secp256k1 error"; e), Error::InvalidChildNumber(ref n) => write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n), Error::InvalidChildNumberFormat => f.write_str("invalid child number format"), Error::InvalidDerivationPathFormat => f.write_str("invalid derivation path format"), Error::UnknownVersion(ref bytes) => write!(f, "unknown version magic bytes: {:?}", bytes), Error::WrongExtendedKeyLength(ref len) => write!(f, "encoded extended key data has wrong length {}", len), - Error::Base58(ref err) => write!(f, "base58 encoding error: {}", err), - Error::Hex(ref e) => write!(f, "Hexadecimal decoding error: {}", e) + Error::Base58(ref e) => write_err!(f, "base58 encoding error"; e), + Error::Hex(ref e) => write_err!(f, "Hexadecimal decoding error"; e), } } } diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index 185b22f6..856b00ea 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -102,14 +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::HexEncoding(ref e) => + write_err!(f, "EcdsaSig hex encoding error"; e), EcdsaSigError::NonStandardSighashType(hash_ty) => write!(f, "Non standard signature hash type {}", hash_ty), EcdsaSigError::EmptySignature => write!(f, "Empty ECDSA signature"), EcdsaSigError::Secp256k1(ref e) => - write!(f, "Invalid Ecdsa signature: {}", e), + write_err!(f, "invalid ECDSA signature"; e), } } } diff --git a/src/util/key.rs b/src/util/key.rs index 9885c6c0..9feed76b 100644 --- a/src/util/key.rs +++ b/src/util/key.rs @@ -45,10 +45,10 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::Base58(ref e) => write!(f, "Key base58 error: {}", e), - Error::Secp256k1(ref e) => write!(f, "Key secp256k1 error: {}", e), + Error::Base58(ref e) => write_err!(f, "key base58 error"; e), + Error::Secp256k1(ref e) => write_err!(f, "key secp256k1 error"; e), Error::InvalidKeyPrefix(ref b) => write!(f, "key prefix invalid: {}", b), - Error::Hex(ref e) => write!(f, "Key hex decoding error: {}", e) + Error::Hex(ref e) => write_err!(f, "key hex decoding error"; e) } } } diff --git a/src/util/misc.rs b/src/util/misc.rs index 9f61f563..43ffa6c6 100644 --- a/src/util/misc.rs +++ b/src/util/misc.rs @@ -63,7 +63,7 @@ mod message_signing { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { MessageSignatureError::InvalidLength => write!(f, "length not 65 bytes"), - MessageSignatureError::InvalidEncoding(ref e) => write!(f, "invalid encoding: {}", e), + MessageSignatureError::InvalidEncoding(ref e) => write_err!(f, "invalid encoding"; e), MessageSignatureError::InvalidBase64 => write!(f, "invalid base64"), MessageSignatureError::UnsupportedAddressType(ref address_type) => write!(f, "unsupported address type: {}", address_type), } diff --git a/src/util/mod.rs b/src/util/mod.rs index 2d3d8a23..442b90d1 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -81,8 +81,8 @@ pub enum Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Error::Encode(ref e) => fmt::Display::fmt(e, f), - Error::Network(ref e) => fmt::Display::fmt(e, f), + Error::Encode(ref e) => write_err!(f, "encoding error"; e), + Error::Network(ref e) => write_err!(f, "network error"; e), Error::BlockBadProofOfWork => f.write_str("block target correct but not attained"), Error::BlockBadTarget => f.write_str("block target incorrect"), } diff --git a/src/util/psbt/error.rs b/src/util/psbt/error.rs index b191e28b..a484a223 100644 --- a/src/util/psbt/error.rs +++ b/src/util/psbt/error.rs @@ -103,7 +103,7 @@ impl fmt::Display for Error { 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(ref e) => write_err!(f, "hash parse error"; e), 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 ) diff --git a/src/util/psbt/mod.rs b/src/util/psbt/mod.rs index 81aeefa3..ff198489 100644 --- a/src/util/psbt/mod.rs +++ b/src/util/psbt/mod.rs @@ -232,9 +232,11 @@ mod display_from_str { impl Display for PsbtParseError { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - PsbtParseError::PsbtEncoding(err) => Display::fmt(err, f), - PsbtParseError::Base64Encoding(err) => Display::fmt(err, f), + use self::PsbtParseError::*; + + match *self { + PsbtEncoding(ref e) => write_err!(f, "error in internal PSBT data structure"; e), + Base64Encoding(ref e) => write_err!(f, "error in PSBT base64 encoding"; e), } } } @@ -924,7 +926,10 @@ mod tests { let err = hex_psbt!("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a07570000220702fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da7560000800100008000000080010000000000000000").unwrap_err(); assert_eq!(err.to_string(), "parse failed: Invalid xonly public key"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6924214022cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b094089756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err(); - assert_eq!(err.to_string(), "PSBT error: Hash Parse Error: bad slice length 33 (expected 32)"); + #[cfg(feature = "std")] + assert_eq!(err.to_string(), "PSBT error"); + #[cfg(not(feature = "std"))] + assert_eq!(err.to_string(), "PSBT error: hash parse error: bad slice length 33 (expected 32)"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b094289756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb01010000").unwrap_err(); assert_eq!(err.to_string(), "parse failed: Invalid Schnorr signature length"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b093989756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err(); diff --git a/src/util/schnorr.rs b/src/util/schnorr.rs index 8d679120..059e0db2 100644 --- a/src/util/schnorr.rs +++ b/src/util/schnorr.rs @@ -277,7 +277,7 @@ impl fmt::Display for SchnorrSigError { SchnorrSigError::InvalidSighashType(hash_ty) => write!(f, "Invalid signature hash type {}", hash_ty), SchnorrSigError::Secp256k1(ref e) => - write!(f, "Schnorr Signature has correct len, but is malformed : {}", e), + write_err!(f, "Schnorr signature has correct len but is malformed"; e), SchnorrSigError::InvalidSchnorrSigSize(sz) => write!(f, "Invalid Schnorr signature size: {}", sz), } diff --git a/src/util/taproot.rs b/src/util/taproot.rs index b1efc1da..2444ed00 100644 --- a/src/util/taproot.rs +++ b/src/util/taproot.rs @@ -998,8 +998,8 @@ 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::InvalidInternalKey(e) => { - write!(f, "Invalid Internal XOnly key : {}", e) + TaprootBuilderError::InvalidInternalKey(ref e) => { + write_err!(f, "invalid internal x-only key"; e) } TaprootBuilderError::IncompleteTree => { write!(f, "Called finalize on an incomplete tree") @@ -1070,9 +1070,8 @@ impl fmt::Display for TaprootError { "Control Block size({}) must be of the form 33 + 32*m where 0 <= m <= {} ", sz, TAPROOT_CONTROL_MAX_NODE_COUNT ), - // TODO: add source when in MSRV - TaprootError::InvalidInternalKey(e) => write!(f, "Invalid Internal XOnly key : {}", e), - TaprootError::InvalidParity(e) => write!(f, "Invalid parity value for internal key: {}", e), + TaprootError::InvalidInternalKey(ref e) => write_err!(f, "invalid internal x-only key"; e), + TaprootError::InvalidParity(_) => write!(f, "invalid parity value for internal key"), TaprootError::EmptyTree => write!(f, "Taproot Tree must contain at least one script"), } }