From 126cbb00efe13f223b0376f64f79ff914d722318 Mon Sep 17 00:00:00 2001 From: DanGould Date: Thu, 2 Feb 2023 12:34:49 -0500 Subject: [PATCH 1/2] Associate io::Error with psbt::Error In order to associate the error, psbt::Error must not derive so many traits. Tests are also adjusted for the new error type. --- bitcoin/src/psbt/error.rs | 15 +++++++++++++-- bitcoin/src/psbt/mod.rs | 15 ++++++++++++--- bitcoin/src/psbt/serialize.rs | 6 +++--- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/bitcoin/src/psbt/error.rs b/bitcoin/src/psbt/error.rs index e1a1614b..cae556ac 100644 --- a/bitcoin/src/psbt/error.rs +++ b/bitcoin/src/psbt/error.rs @@ -11,6 +11,7 @@ use crate::consensus::encode; use crate::psbt::raw; use crate::hashes; +use crate::io; use crate::bip32::ExtendedPubKey; /// Enum for marking psbt hash error. @@ -22,7 +23,7 @@ pub enum PsbtHash { Hash256, } /// Ways that a Partially Signed Transaction might fail. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Debug)] #[non_exhaustive] pub enum Error { /// Magic bytes for a PSBT must be the ASCII for "psbt" serialized in most @@ -100,6 +101,8 @@ pub enum Error { Version(&'static str), /// PSBT data is not consumed entirely PartialDataConsumption, + /// I/O error. + Io(io::Error), } impl fmt::Display for Error { @@ -140,6 +143,7 @@ impl fmt::Display for Error { Error::XPubKey(s) => write!(f, "xpub key error - {}", s), Error::Version(s) => write!(f, "version error {}", s), Error::PartialDataConsumption => f.write_str("data not consumed entirely when explicitly deserializing"), + Error::Io(ref e) => write_err!(f, "I/O error"; e), } } } @@ -152,6 +156,7 @@ impl std::error::Error for Error { match self { HashParse(e) => Some(e), + Io(e) => Some(e), | InvalidMagic | MissingUtxo | InvalidSeparator @@ -180,7 +185,7 @@ impl std::error::Error for Error { | Taproot(_) | XPubKey(_) | Version(_) - | PartialDataConsumption=> None + | PartialDataConsumption=> None, } } } @@ -197,3 +202,9 @@ impl From for Error { Error::ConsensusEncoding } } + +impl From for Error { + fn from(e: io::Error) -> Self { + Error::Io(e) + } +} diff --git a/bitcoin/src/psbt/mod.rs b/bitcoin/src/psbt/mod.rs index 9d83ca90..ebca2936 100644 --- a/bitcoin/src/psbt/mod.rs +++ b/bitcoin/src/psbt/mod.rs @@ -1732,15 +1732,24 @@ mod tests { // no previous output let mut t2 = t.clone(); t2.inputs[0].non_witness_utxo = None; - assert_eq!(t2.fee(), Err(Error::MissingUtxo)); + match t2.fee().unwrap_err() { + Error::MissingUtxo => {}, + e => panic!("unexpected error: {:?}", e) + } // negative fee let mut t3 = t.clone(); t3.unsigned_tx.output[0].value = prev_output_val; - assert_eq!(t3.fee(), Err(Error::NegativeFee)); + match t3.fee().unwrap_err() { + Error::NegativeFee => {}, + e => panic!("unexpected error: {:?}", e) + } // overflow t.unsigned_tx.output[0].value = u64::max_value(); t.unsigned_tx.output[1].value = u64::max_value(); - assert_eq!(t.fee(), Err(Error::FeeOverflow)); + match t.fee().unwrap_err() { + Error::FeeOverflow => {}, + e => panic!("unexpected error: {:?}", e) + } } #[test] diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs index 47a60a64..f908f975 100644 --- a/bitcoin/src/psbt/serialize.rs +++ b/bitcoin/src/psbt/serialize.rs @@ -225,7 +225,7 @@ impl Serialize for KeySource { impl Deserialize for KeySource { fn deserialize(bytes: &[u8]) -> Result { if bytes.len() < 4 { - return Err(encode::Error::from(io::Error::from(io::ErrorKind::UnexpectedEof)).into()) + return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) } let fprint: Fingerprint = bytes[0..4].try_into().expect("4 is the fingerprint length"); @@ -319,7 +319,7 @@ impl Serialize for (XOnlyPublicKey, TapLeafHash) { impl Deserialize for (XOnlyPublicKey, TapLeafHash) { fn deserialize(bytes: &[u8]) -> Result { if bytes.len() < 32 { - return Err(encode::Error::from(io::Error::from(io::ErrorKind::UnexpectedEof)).into()) + return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) } let a: XOnlyPublicKey = Deserialize::deserialize(&bytes[..32])?; let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?; @@ -353,7 +353,7 @@ impl Serialize for (ScriptBuf, LeafVersion) { impl Deserialize for (ScriptBuf, LeafVersion) { fn deserialize(bytes: &[u8]) -> Result { if bytes.is_empty() { - return Err(encode::Error::from(io::Error::from(io::ErrorKind::UnexpectedEof)).into()) + return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into()) } // The last byte is LeafVersion. let script = ScriptBuf::deserialize(&bytes[..bytes.len() - 1])?; From 0ffd928a7df9aa4243fe454a32557f02a8e1a8c1 Mon Sep 17 00:00:00 2001 From: DanGould Date: Thu, 2 Feb 2023 12:54:30 -0500 Subject: [PATCH 2/2] Carry ConsensusEncoding(encode::Error) When psbt::Error was Eq, it could not have associated dyn error types. --- bitcoin/src/psbt/error.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bitcoin/src/psbt/error.rs b/bitcoin/src/psbt/error.rs index cae556ac..47bd4df7 100644 --- a/bitcoin/src/psbt/error.rs +++ b/bitcoin/src/psbt/error.rs @@ -74,7 +74,7 @@ pub enum Error { /// global extended public key has inconsistent key sources CombineInconsistentKeySources(Box), /// Serialization error in bitcoin consensus-encoded structures - ConsensusEncoding, + ConsensusEncoding(encode::Error), /// Negative fee NegativeFee, /// Integer overflow in fee calculation @@ -129,7 +129,7 @@ impl fmt::Display for Error { write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash ) }, Error::CombineInconsistentKeySources(ref s) => { write!(f, "combine conflict: {}", s) }, - Error::ConsensusEncoding => f.write_str("bitcoin consensus or BIP-174 encoding error"), + Error::ConsensusEncoding(ref e) => write_err!(f, "bitcoin consensus encoding error"; e), Error::NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"), Error::FeeOverflow => f.write_str("integer overflow in fee calculation"), Error::InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e), @@ -156,6 +156,7 @@ impl std::error::Error for Error { match self { HashParse(e) => Some(e), + ConsensusEncoding(e) => Some(e), Io(e) => Some(e), | InvalidMagic | MissingUtxo @@ -172,7 +173,6 @@ impl std::error::Error for Error { | NonStandardSighashType(_) | InvalidPreimageHashPair{ .. } | CombineInconsistentKeySources(_) - | ConsensusEncoding | NegativeFee | FeeOverflow | InvalidPublicKey(_) @@ -198,8 +198,8 @@ impl From for Error { } impl From for Error { - fn from(_: encode::Error) -> Self { - Error::ConsensusEncoding + fn from(e: encode::Error) -> Self { + Error::ConsensusEncoding(e) } }