diff --git a/core/src/core/committed.rs b/core/src/core/committed.rs index a5c6e72bb..8298feded 100644 --- a/core/src/core/committed.rs +++ b/core/src/core/committed.rs @@ -22,7 +22,7 @@ use util::secp::pedersen::Commitment; use util::{secp, secp_static, static_secp_instance}; /// Errors from summing and verifying kernel excesses via committed trait. -#[derive(Debug, Clone, PartialEq, Eq, Fail)] +#[derive(Debug, Clone, PartialEq, Eq, Fail, Serialize, Deserialize)] pub enum Error { /// Keychain related error. #[fail(display = "Keychain error {}", _0)] diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index 750b3f883..dbba4a196 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -210,7 +210,7 @@ impl Readable for KernelFeatures { } /// Errors thrown by Transaction validation -#[derive(Clone, Eq, Debug, PartialEq)] +#[derive(Clone, Eq, Debug, PartialEq, Serialize, Deserialize)] pub enum Error { /// Underlying Secp256k1 error (signature validation or invalid public key /// typically) diff --git a/core/src/libtx/error.rs b/core/src/libtx/error.rs index 61ff4e7a2..f69e248ec 100644 --- a/core/src/libtx/error.rs +++ b/core/src/libtx/error.rs @@ -25,7 +25,7 @@ pub struct Error { inner: Context, } -#[derive(Clone, Debug, Eq, Fail, PartialEq)] +#[derive(Clone, Debug, Eq, Fail, PartialEq, Serialize, Deserialize)] /// Libwallet error types pub enum ErrorKind { /// SECP error diff --git a/core/src/ser.rs b/core/src/ser.rs index 15b99cc5f..028f6263a 100644 --- a/core/src/ser.rs +++ b/core/src/ser.rs @@ -37,10 +37,17 @@ use util::secp::Signature; use util::secp::{ContextFlag, Secp256k1}; /// Possible errors deriving from serializing or deserializing. -#[derive(Clone, Eq, PartialEq, Debug)] +#[derive(Clone, Eq, PartialEq, Debug, Serialize, Deserialize)] pub enum Error { /// Wraps an io error produced when reading or writing - IOErr(String, io::ErrorKind), + IOErr( + String, + #[serde( + serialize_with = "serialize_error_kind", + deserialize_with = "deserialize_error_kind" + )] + io::ErrorKind, + ), /// Expected a given value that wasn't found UnexpectedData { /// What we wanted @@ -392,26 +399,30 @@ impl<'a> BinReader<'a> { } } +fn map_io_err(err: io::Error) -> Error { + Error::IOErr(format!("{}", err), err.kind()) +} + /// Utility wrapper for an underlying byte Reader. Defines higher level methods /// to read numbers, byte vectors, hashes, etc. impl<'a> Reader for BinReader<'a> { fn read_u8(&mut self) -> Result { - self.source.read_u8().map_err(Into::into) + self.source.read_u8().map_err(map_io_err) } fn read_u16(&mut self) -> Result { - self.source.read_u16::().map_err(Into::into) + self.source.read_u16::().map_err(map_io_err) } fn read_u32(&mut self) -> Result { - self.source.read_u32::().map_err(Into::into) + self.source.read_u32::().map_err(map_io_err) } fn read_i32(&mut self) -> Result { - self.source.read_i32::().map_err(Into::into) + self.source.read_i32::().map_err(map_io_err) } fn read_u64(&mut self) -> Result { - self.source.read_u64::().map_err(Into::into) + self.source.read_u64::().map_err(map_io_err) } fn read_i64(&mut self) -> Result { - self.source.read_i64::().map_err(Into::into) + self.source.read_i64::().map_err(map_io_err) } /// Read a variable size vector from the underlying Read. Expects a usize fn read_bytes_len_prefix(&mut self) -> Result, Error> { @@ -429,7 +440,7 @@ impl<'a> Reader for BinReader<'a> { self.source .read_exact(&mut buf) .map(move |_| buf) - .map_err(Into::into) + .map_err(map_io_err) } fn expect_u8(&mut self, val: u8) -> Result { @@ -941,3 +952,446 @@ impl AsFixedBytes for keychain::Identifier { IDENTIFIER_SIZE } } + +// serializer for io::Errorkind, originally auto-generated by serde-derive +// slightly modified to handle the #[non_exhaustive] tag on io::ErrorKind +fn serialize_error_kind( + kind: &io::ErrorKind, + serializer: S, +) -> serde::export::Result +where + S: serde::Serializer, +{ + match *kind { + io::ErrorKind::NotFound => { + serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 0u32, "NotFound") + } + io::ErrorKind::PermissionDenied => serde::Serializer::serialize_unit_variant( + serializer, + "ErrorKind", + 1u32, + "PermissionDenied", + ), + io::ErrorKind::ConnectionRefused => serde::Serializer::serialize_unit_variant( + serializer, + "ErrorKind", + 2u32, + "ConnectionRefused", + ), + io::ErrorKind::ConnectionReset => serde::Serializer::serialize_unit_variant( + serializer, + "ErrorKind", + 3u32, + "ConnectionReset", + ), + io::ErrorKind::ConnectionAborted => serde::Serializer::serialize_unit_variant( + serializer, + "ErrorKind", + 4u32, + "ConnectionAborted", + ), + io::ErrorKind::NotConnected => { + serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 5u32, "NotConnected") + } + io::ErrorKind::AddrInUse => { + serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 6u32, "AddrInUse") + } + io::ErrorKind::AddrNotAvailable => serde::Serializer::serialize_unit_variant( + serializer, + "ErrorKind", + 7u32, + "AddrNotAvailable", + ), + io::ErrorKind::BrokenPipe => { + serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 8u32, "BrokenPipe") + } + io::ErrorKind::AlreadyExists => serde::Serializer::serialize_unit_variant( + serializer, + "ErrorKind", + 9u32, + "AlreadyExists", + ), + io::ErrorKind::WouldBlock => { + serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 10u32, "WouldBlock") + } + io::ErrorKind::InvalidInput => serde::Serializer::serialize_unit_variant( + serializer, + "ErrorKind", + 11u32, + "InvalidInput", + ), + io::ErrorKind::InvalidData => { + serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 12u32, "InvalidData") + } + io::ErrorKind::TimedOut => { + serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 13u32, "TimedOut") + } + io::ErrorKind::WriteZero => { + serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 14u32, "WriteZero") + } + io::ErrorKind::Interrupted => { + serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 15u32, "Interrupted") + } + io::ErrorKind::Other => { + serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 16u32, "Other") + } + io::ErrorKind::UnexpectedEof => serde::Serializer::serialize_unit_variant( + serializer, + "ErrorKind", + 17u32, + "UnexpectedEof", + ), + // #[non_exhaustive] is used on the definition of ErrorKind for future compatability + // That means match statements always need to match on _. + // The downside here is that rustc won't be able to warn us if io::ErrorKind another + // field is added to io::ErrorKind + _ => serde::Serializer::serialize_unit_variant(serializer, "ErrorKind", 16u32, "Other"), + } +} + +// deserializer for io::Errorkind, originally auto-generated by serde-derive +fn deserialize_error_kind<'de, D>(deserializer: D) -> serde::export::Result +where + D: serde::Deserializer<'de>, +{ + #[allow(non_camel_case_types)] + enum Field { + field0, + field1, + field2, + field3, + field4, + field5, + field6, + field7, + field8, + field9, + field10, + field11, + field12, + field13, + field14, + field15, + field16, + field17, + } + struct FieldVisitor; + impl<'de> serde::de::Visitor<'de> for FieldVisitor { + type Value = Field; + fn expecting( + &self, + formatter: &mut serde::export::Formatter, + ) -> serde::export::fmt::Result { + serde::export::Formatter::write_str(formatter, "variant identifier") + } + fn visit_u64(self, value: u64) -> serde::export::Result + where + E: serde::de::Error, + { + match value { + 0u64 => serde::export::Ok(Field::field0), + 1u64 => serde::export::Ok(Field::field1), + 2u64 => serde::export::Ok(Field::field2), + 3u64 => serde::export::Ok(Field::field3), + 4u64 => serde::export::Ok(Field::field4), + 5u64 => serde::export::Ok(Field::field5), + 6u64 => serde::export::Ok(Field::field6), + 7u64 => serde::export::Ok(Field::field7), + 8u64 => serde::export::Ok(Field::field8), + 9u64 => serde::export::Ok(Field::field9), + 10u64 => serde::export::Ok(Field::field10), + 11u64 => serde::export::Ok(Field::field11), + 12u64 => serde::export::Ok(Field::field12), + 13u64 => serde::export::Ok(Field::field13), + 14u64 => serde::export::Ok(Field::field14), + 15u64 => serde::export::Ok(Field::field15), + 16u64 => serde::export::Ok(Field::field16), + 17u64 => serde::export::Ok(Field::field17), + _ => serde::export::Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Unsigned(value), + &"variant index 0 <= i < 18", + )), + } + } + fn visit_str(self, value: &str) -> serde::export::Result + where + E: serde::de::Error, + { + match value { + "NotFound" => serde::export::Ok(Field::field0), + "PermissionDenied" => serde::export::Ok(Field::field1), + "ConnectionRefused" => serde::export::Ok(Field::field2), + "ConnectionReset" => serde::export::Ok(Field::field3), + "ConnectionAborted" => serde::export::Ok(Field::field4), + "NotConnected" => serde::export::Ok(Field::field5), + "AddrInUse" => serde::export::Ok(Field::field6), + "AddrNotAvailable" => serde::export::Ok(Field::field7), + "BrokenPipe" => serde::export::Ok(Field::field8), + "AlreadyExists" => serde::export::Ok(Field::field9), + "WouldBlock" => serde::export::Ok(Field::field10), + "InvalidInput" => serde::export::Ok(Field::field11), + "InvalidData" => serde::export::Ok(Field::field12), + "TimedOut" => serde::export::Ok(Field::field13), + "WriteZero" => serde::export::Ok(Field::field14), + "Interrupted" => serde::export::Ok(Field::field15), + "Other" => serde::export::Ok(Field::field16), + "UnexpectedEof" => serde::export::Ok(Field::field17), + _ => serde::export::Err(serde::de::Error::unknown_variant(value, VARIANTS)), + } + } + fn visit_bytes(self, value: &[u8]) -> serde::export::Result + where + E: serde::de::Error, + { + match value { + b"NotFound" => serde::export::Ok(Field::field0), + b"PermissionDenied" => serde::export::Ok(Field::field1), + b"ConnectionRefused" => serde::export::Ok(Field::field2), + b"ConnectionReset" => serde::export::Ok(Field::field3), + b"ConnectionAborted" => serde::export::Ok(Field::field4), + b"NotConnected" => serde::export::Ok(Field::field5), + b"AddrInUse" => serde::export::Ok(Field::field6), + b"AddrNotAvailable" => serde::export::Ok(Field::field7), + b"BrokenPipe" => serde::export::Ok(Field::field8), + b"AlreadyExists" => serde::export::Ok(Field::field9), + b"WouldBlock" => serde::export::Ok(Field::field10), + b"InvalidInput" => serde::export::Ok(Field::field11), + b"InvalidData" => serde::export::Ok(Field::field12), + b"TimedOut" => serde::export::Ok(Field::field13), + b"WriteZero" => serde::export::Ok(Field::field14), + b"Interrupted" => serde::export::Ok(Field::field15), + b"Other" => serde::export::Ok(Field::field16), + b"UnexpectedEof" => serde::export::Ok(Field::field17), + _ => { + let value = &serde::export::from_utf8_lossy(value); + serde::export::Err(serde::de::Error::unknown_variant(value, VARIANTS)) + } + } + } + } + impl<'de> serde::Deserialize<'de> for Field { + #[inline] + fn deserialize(deserializer: D) -> serde::export::Result + where + D: serde::Deserializer<'de>, + { + serde::Deserializer::deserialize_identifier(deserializer, FieldVisitor) + } + } + struct Visitor<'de> { + marker: serde::export::PhantomData, + lifetime: serde::export::PhantomData<&'de ()>, + } + impl<'de> serde::de::Visitor<'de> for Visitor<'de> { + type Value = io::ErrorKind; + fn expecting( + &self, + formatter: &mut serde::export::Formatter, + ) -> serde::export::fmt::Result { + serde::export::Formatter::write_str(formatter, "enum io::ErrorKind") + } + fn visit_enum(self, data: A) -> serde::export::Result + where + A: serde::de::EnumAccess<'de>, + { + match match serde::de::EnumAccess::variant(data) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + } { + (Field::field0, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::NotFound) + } + (Field::field1, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::PermissionDenied) + } + (Field::field2, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::ConnectionRefused) + } + (Field::field3, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::ConnectionReset) + } + (Field::field4, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::ConnectionAborted) + } + (Field::field5, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::NotConnected) + } + (Field::field6, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::AddrInUse) + } + (Field::field7, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::AddrNotAvailable) + } + (Field::field8, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::BrokenPipe) + } + (Field::field9, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::AlreadyExists) + } + (Field::field10, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::WouldBlock) + } + (Field::field11, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::InvalidInput) + } + (Field::field12, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::InvalidData) + } + (Field::field13, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::TimedOut) + } + (Field::field14, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::WriteZero) + } + (Field::field15, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::Interrupted) + } + (Field::field16, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::Other) + } + (Field::field17, variant) => { + match serde::de::VariantAccess::unit_variant(variant) { + serde::export::Ok(val) => val, + serde::export::Err(err) => { + return serde::export::Err(err); + } + }; + serde::export::Ok(io::ErrorKind::UnexpectedEof) + } + } + } + } + const VARIANTS: &'static [&'static str] = &[ + "NotFound", + "PermissionDenied", + "ConnectionRefused", + "ConnectionReset", + "ConnectionAborted", + "NotConnected", + "AddrInUse", + "AddrNotAvailable", + "BrokenPipe", + "AlreadyExists", + "WouldBlock", + "InvalidInput", + "InvalidData", + "TimedOut", + "WriteZero", + "Interrupted", + "Other", + "UnexpectedEof", + ]; + serde::Deserializer::deserialize_enum( + deserializer, + "ErrorKind", + VARIANTS, + Visitor { + marker: serde::export::PhantomData::, + lifetime: serde::export::PhantomData, + }, + ) +} diff --git a/keychain/src/extkey_bip32.rs b/keychain/src/extkey_bip32.rs index e06778c7a..22335772e 100644 --- a/keychain/src/extkey_bip32.rs +++ b/keychain/src/extkey_bip32.rs @@ -295,7 +295,7 @@ impl serde::Serialize for ChildNumber { } /// A BIP32 error -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] pub enum Error { /// A pk->pk derivation was attempted on a hardened key CannotDeriveFromHardenedKey, diff --git a/keychain/src/mnemonic.rs b/keychain/src/mnemonic.rs index 4afea6aaf..752907db1 100644 --- a/keychain/src/mnemonic.rs +++ b/keychain/src/mnemonic.rs @@ -29,7 +29,7 @@ lazy_static! { } /// An error that might occur during mnemonic decoding -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub enum Error { /// Invalid word encountered BadWord(String), diff --git a/keychain/src/types.rs b/keychain/src/types.rs index 1cd41c5e4..a6c774935 100644 --- a/keychain/src/types.rs +++ b/keychain/src/types.rs @@ -40,7 +40,7 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; // Size of an identifier in bytes pub const IDENTIFIER_SIZE: usize = 17; -#[derive(PartialEq, Eq, Clone, Debug)] +#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)] pub enum Error { Secp(secp::Error), KeyDerivation(extkey_bip32::Error),