diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index 65475afd..862452e1 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -45,7 +45,7 @@ pub struct OutPoint { /// The index of the referenced output in its transaction's vout pub vout: u32, } -serde_struct_impl!(OutPoint, txid, vout); +serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout); impl OutPoint { /// Create a new [OutPoint]. diff --git a/src/internal_macros.rs b/src/internal_macros.rs index b7121625..4f6d47a2 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -162,57 +162,6 @@ macro_rules! impl_array_newtype { } } -macro_rules! impl_array_newtype_encodable { - ($thing:ident, $ty:ty, $len:expr) => { - #[cfg(feature = "serde")] - impl<'de> $crate::serde::Deserialize<'de> for $thing { - fn deserialize(deserializer: D) -> Result - where - D: $crate::serde::Deserializer<'de>, - { - use $crate::std::fmt::{self, Formatter}; - - struct Visitor; - impl<'de> $crate::serde::de::Visitor<'de> for Visitor { - type Value = $thing; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a fixed size array") - } - - #[inline] - fn visit_seq(self, mut seq: A) -> Result - where - A: $crate::serde::de::SeqAccess<'de>, - { - let mut ret: [$ty; $len] = [0; $len]; - for item in ret.iter_mut() { - *item = match seq.next_element()? { - Some(c) => c, - None => return Err($crate::serde::de::Error::custom("end of stream")) - }; - } - Ok($thing(ret)) - } - } - - deserializer.deserialize_seq(Visitor) - } - } - - #[cfg(feature = "serde")] - impl $crate::serde::Serialize for $thing { - fn serialize(&self, serializer: S) -> Result - where - S: $crate::serde::Serializer, - { - let &$thing(ref dat) = self; - (&dat[..]).serialize(serializer) - } - } - } -} - macro_rules! impl_array_newtype_show { ($thing:ident) => { impl ::std::fmt::Debug for $thing { @@ -400,6 +349,351 @@ macro_rules! serde_struct_impl { ) } +macro_rules! serde_string_impl { + ($name:ident, $expecting:expr) => { + #[cfg(feature = "serde")] + impl<'de> $crate::serde::Deserialize<'de> for $name { + fn deserialize(deserializer: D) -> Result<$name, D::Error> + where + D: $crate::serde::de::Deserializer<'de>, + { + use $crate::std::fmt::{self, Formatter}; + use $crate::std::str::FromStr; + + struct Visitor; + impl<'de> $crate::serde::de::Visitor<'de> for Visitor { + type Value = $name; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str($expecting) + } + + fn visit_str(self, v: &str) -> Result + where + E: $crate::serde::de::Error, + { + $name::from_str(v).map_err(E::custom) + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: $crate::serde::de::Error, + { + self.visit_str(v) + } + + fn visit_string(self, v: String) -> Result + where + E: $crate::serde::de::Error, + { + self.visit_str(&v) + } + } + + deserializer.deserialize_str(Visitor) + } + } + + #[cfg(feature = "serde")] + impl<'de> $crate::serde::Serialize for $name { + fn serialize(&self, serializer: S) -> Result + where + S: $crate::serde::Serializer, + { + serializer.collect_str(&self) + } + } + }; +} + +/// A combination of serde_struct_impl and serde_string_impl where string is +/// used for human-readable serialization and struct is used for +/// non-human-readable serialization. +macro_rules! serde_struct_human_string_impl { + ($name:ident, $expecting:expr, $($fe:ident),*) => ( + #[cfg(feature = "serde")] + impl<'de> $crate::serde::Deserialize<'de> for $name { + fn deserialize(deserializer: D) -> Result<$name, D::Error> + where + D: $crate::serde::de::Deserializer<'de>, + { + if deserializer.is_human_readable() { + use $crate::std::fmt::{self, Formatter}; + use $crate::std::str::FromStr; + + struct Visitor; + impl<'de> $crate::serde::de::Visitor<'de> for Visitor { + type Value = $name; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str($expecting) + } + + fn visit_str(self, v: &str) -> Result + where + E: $crate::serde::de::Error, + { + $name::from_str(v).map_err(E::custom) + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: $crate::serde::de::Error, + { + self.visit_str(v) + } + + fn visit_string(self, v: String) -> Result + where + E: $crate::serde::de::Error, + { + self.visit_str(&v) + } + } + + deserializer.deserialize_str(Visitor) + } else { + use $crate::std::fmt::{self, Formatter}; + use $crate::serde::de::IgnoredAny; + + #[allow(non_camel_case_types)] + enum Enum { Unknown__Field, $($fe),* } + + struct EnumVisitor; + impl<'de> $crate::serde::de::Visitor<'de> for EnumVisitor { + type Value = Enum; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a field name") + } + + fn visit_str(self, v: &str) -> Result + where + E: $crate::serde::de::Error, + { + match v { + $( + stringify!($fe) => Ok(Enum::$fe) + ),*, + _ => Ok(Enum::Unknown__Field) + } + } + } + + impl<'de> $crate::serde::Deserialize<'de> for Enum { + fn deserialize(deserializer: D) -> Result + where + D: $crate::serde::de::Deserializer<'de>, + { + deserializer.deserialize_str(EnumVisitor) + } + } + + struct Visitor; + + impl<'de> $crate::serde::de::Visitor<'de> for Visitor { + type Value = $name; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a struct") + } + + fn visit_map(self, mut map: A) -> Result + where + A: $crate::serde::de::MapAccess<'de>, + { + use $crate::serde::de::Error; + + $(let mut $fe = None;)* + + loop { + match map.next_key::()? { + Some(Enum::Unknown__Field) => { + map.next_value::()?; + } + $( + Some(Enum::$fe) => { + $fe = Some(map.next_value()?); + } + )* + None => { break; } + } + } + + $( + let $fe = match $fe { + Some(x) => x, + None => return Err(A::Error::missing_field(stringify!($fe))), + }; + )* + + let ret = $name { + $($fe: $fe),* + }; + + Ok(ret) + } + } + // end type defs + + static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; + + deserializer.deserialize_struct(stringify!($name), FIELDS, Visitor) + } + } + } + + #[cfg(feature = "serde")] + impl<'de> $crate::serde::Serialize for $name { + fn serialize(&self, serializer: S) -> Result + where + S: $crate::serde::Serializer, + { + if serializer.is_human_readable() { + serializer.collect_str(&self) + } else { + use $crate::serde::ser::SerializeStruct; + + // Only used to get the struct length. + static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; + + let mut st = serializer.serialize_struct(stringify!($name), FIELDS.len())?; + + $( + st.serialize_field(stringify!($fe), &self.$fe)?; + )* + + st.end() + } + } + } + ) +} + +/// Implements several traits for byte-based newtypes. +/// Implements: +/// - std::fmt::LowerHex (implies bitcoin_hashes::hex::ToHex) +/// - std::fmt::Display +/// - std::str::FromStr +/// - bitcoin_hashes::hex::FromHex +macro_rules! impl_bytes_newtype { + ($t:ident, $len:expr) => ( + + impl ::std::fmt::LowerHex for $t { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + for &ch in self.0.iter() { + write!(f, "{:02x}", ch)?; + } + Ok(()) + } + } + + impl ::std::fmt::Display for $t { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::LowerHex::fmt(self, f) + } + } + + impl ::bitcoin_hashes::hex::FromHex for $t { + fn from_byte_iter(iter: I) -> Result + where I: Iterator> + + ExactSizeIterator + + DoubleEndedIterator, + { + if iter.len() == $len { + let mut ret = [0; $len]; + for (n, byte) in iter.enumerate() { + ret[n] = byte?; + } + Ok($t(ret)) + } else { + Err(::bitcoin_hashes::hex::Error::InvalidLength(2 * $len, 2 * iter.len())) + } + } + } + + impl ::std::str::FromStr for $t { + type Err = bitcoin_hashes::hex::Error; + fn from_str(s: &str) -> Result { + hex::FromHex::from_hex(s) + } + } + + #[cfg(feature="serde")] + impl ::serde::Serialize for $t { + fn serialize(&self, s: S) -> Result { + if s.is_human_readable() { + s.serialize_str(&::bitcoin_hashes::hex::ToHex::to_hex(self)) + } else { + s.serialize_bytes(&self[..]) + } + } + } + + #[cfg(feature="serde")] + impl<'de> ::serde::Deserialize<'de> for $t { + fn deserialize>(d: D) -> Result<$t, D::Error> { + if d.is_human_readable() { + struct HexVisitor; + + impl<'de> ::serde::de::Visitor<'de> for HexVisitor { + type Value = $t; + + fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + formatter.write_str("an ASCII hex string") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: ::serde::de::Error, + { + if let Ok(hex) = ::std::str::from_utf8(v) { + ::bitcoin_hashes::hex::FromHex::from_hex(hex).map_err(E::custom) + } else { + return Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)); + } + } + + fn visit_str(self, v: &str) -> Result + where + E: ::serde::de::Error, + { + ::bitcoin_hashes::hex::FromHex::from_hex(v).map_err(E::custom) + } + } + + d.deserialize_str(HexVisitor) + } else { + struct BytesVisitor; + + impl<'de> ::serde::de::Visitor<'de> for BytesVisitor { + type Value = $t; + + fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + formatter.write_str("a bytestring") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: ::serde::de::Error, + { + if v.len() != $len { + Err(E::invalid_length(v.len(), &stringify!($len))) + } else { + let mut ret = [0; $len]; + ret.copy_from_slice(v); + Ok($t(ret)) + } + } + } + + d.deserialize_bytes(BytesVisitor) + } + } + } + ) +} + macro_rules! user_enum { ( $(#[$attr:meta])* @@ -498,7 +792,7 @@ macro_rules! user_enum { where S: ::serde::Serializer, { - serializer.serialize_str(&self.to_string()) + serializer.collect_str(&self) } } ); diff --git a/src/util/address.rs b/src/util/address.rs index 909cb785..74c58748 100644 --- a/src/util/address.rs +++ b/src/util/address.rs @@ -46,9 +46,6 @@ use std::str::FromStr; use bitcoin_bech32::{self, WitnessProgram, u5}; use bitcoin_hashes::{hash160, Hash}; -#[cfg(feature = "serde")] -use serde; - use blockdata::opcodes; use blockdata::script; use network::constants::Network; @@ -75,6 +72,7 @@ pub struct Address { /// The network on which this address is usable pub network: Network, } +serde_string_impl!(Address, "a Bitcoin address"); impl Address { /// Creates a pay to (compressed) public key hash address from a public key @@ -299,59 +297,6 @@ impl ::std::fmt::Debug for Address { } } -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for Address { - #[inline] - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use std::fmt::{self, Formatter}; - - struct Visitor; - impl<'de> serde::de::Visitor<'de> for Visitor { - type Value = Address; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a Bitcoin address") - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - Address::from_str(v).map_err(E::custom) - } - - fn visit_borrowed_str(self, v: &'de str) -> Result - where - E: serde::de::Error, - { - self.visit_str(v) - } - - fn visit_string(self, v: String) -> Result - where - E: serde::de::Error, - { - self.visit_str(&v) - } - } - - deserializer.deserialize_str(Visitor) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Address { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - #[cfg(test)] mod tests { use std::str::FromStr; diff --git a/src/util/bip32.rs b/src/util/bip32.rs index 926e1c8f..62653899 100644 --- a/src/util/bip32.rs +++ b/src/util/bip32.rs @@ -23,7 +23,7 @@ use std::str::FromStr; #[cfg(feature = "serde")] use serde; use byteorder::{BigEndian, ByteOrder, ReadBytesExt}; -use bitcoin_hashes::{hash160, sha512, Hash, HashEngine, Hmac, HmacEngine}; +use bitcoin_hashes::{self, hex, hash160, sha512, Hash, HashEngine, Hmac, HmacEngine}; use secp256k1::{self, Secp256k1}; use network::constants::Network; @@ -34,13 +34,13 @@ use util::key::{PublicKey, PrivateKey}; pub struct ChainCode([u8; 32]); impl_array_newtype!(ChainCode, u8, 32); impl_array_newtype_show!(ChainCode); -impl_array_newtype_encodable!(ChainCode, u8, 32); +impl_bytes_newtype!(ChainCode, 32); /// A fingerprint pub struct Fingerprint([u8; 4]); impl_array_newtype!(Fingerprint, u8, 4); impl_array_newtype_show!(Fingerprint); -impl_array_newtype_encodable!(Fingerprint, u8, 4); +impl_bytes_newtype!(Fingerprint, 4); impl Default for Fingerprint { fn default() -> Fingerprint { Fingerprint([0; 4]) } @@ -62,6 +62,7 @@ pub struct ExtendedPrivKey { /// Chain code pub chain_code: ChainCode } +serde_string_impl!(ExtendedPrivKey, "a BIP-32 extended private key"); /// Extended public key #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -79,6 +80,7 @@ pub struct ExtendedPubKey { /// Chain code pub chain_code: ChainCode } +serde_string_impl!(ExtendedPubKey, "a BIP-32 extended public key"); /// A child number for a derived key #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -213,6 +215,7 @@ impl serde::Serialize for ChildNumber { #[derive(Clone, PartialEq, Eq)] pub struct DerivationPath(Vec); impl_index_newtype!(DerivationPath, ChildNumber); +serde_string_impl!(DerivationPath, "a BIP-32 derivation path"); impl From> for DerivationPath { fn from(numbers: Vec) -> Self { @@ -349,44 +352,6 @@ impl fmt::Debug for DerivationPath { } } -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for DerivationPath { - fn deserialize>(deserializer: D) -> Result { - use std::fmt; - use serde::de; - - struct Visitor; - impl<'de> de::Visitor<'de> for Visitor { - type Value = DerivationPath; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a Bitcoin address") - } - - fn visit_str(self, v: &str) -> Result { - DerivationPath::from_str(v).map_err(E::custom) - } - - fn visit_borrowed_str(self, v: &'de str) -> Result { - self.visit_str(v) - } - - fn visit_string(self, v: String) -> Result { - self.visit_str(&v) - } - } - - deserializer.deserialize_str(Visitor) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for DerivationPath { - fn serialize(&self, serializer: S) -> Result { - serializer.serialize_str(&self.to_string()) - } -} - /// A BIP32 error #[derive(Clone, PartialEq, Eq, Debug)] pub enum Error { @@ -725,6 +690,9 @@ impl FromStr for ExtendedPubKey { #[cfg(test)] mod tests { + use super::*; + use super::ChildNumber::{Hardened, Normal}; + use std::str::FromStr; use std::string::ToString; @@ -733,10 +701,6 @@ mod tests { use network::constants::Network::{self, Bitcoin}; - use super::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey}; - use super::ChildNumber::{Hardened, Normal}; - use super::Error; - #[test] fn test_parse_derivation_path() { assert_eq!(DerivationPath::from_str("42"), Err(Error::InvalidDerivationPathFormat)); @@ -997,5 +961,29 @@ mod tests { serde_round_trip!(ChildNumber::from_hardened_idx(1).unwrap()); serde_round_trip!(ChildNumber::from_hardened_idx((1 << 31) - 1).unwrap()); } + + #[test] + #[cfg(feature = "serde")] + pub fn encode_fingerprint_chaincode() { + use serde_json; + let fp = Fingerprint::from(&[1u8,2,3,42][..]); + let cc = ChainCode::from( + &[1u8,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2][..] + ); + + serde_round_trip!(fp); + serde_round_trip!(cc); + + assert_eq!("\"0102032a\"", serde_json::to_string(&fp).unwrap()); + assert_eq!( + "\"0102030405060708090001020304050607080900010203040506070809000102\"", + serde_json::to_string(&cc).unwrap() + ); + assert_eq!("0102032a", fp.to_string()); + assert_eq!( + "0102030405060708090001020304050607080900010203040506070809000102", + cc.to_string() + ); + } }