Merge pull request #271 from stevenroose/serde-outpoint
Add special human-readable serde for OutPoint and most bip32 types
This commit is contained in:
commit
2e915bf7ef
|
@ -45,7 +45,7 @@ pub struct OutPoint {
|
||||||
/// The index of the referenced output in its transaction's vout
|
/// The index of the referenced output in its transaction's vout
|
||||||
pub vout: u32,
|
pub vout: u32,
|
||||||
}
|
}
|
||||||
serde_struct_impl!(OutPoint, txid, vout);
|
serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout);
|
||||||
|
|
||||||
impl OutPoint {
|
impl OutPoint {
|
||||||
/// Create a new [OutPoint].
|
/// Create a new [OutPoint].
|
||||||
|
|
|
@ -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<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
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<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
|
||||||
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: $crate::serde::Serializer,
|
|
||||||
{
|
|
||||||
let &$thing(ref dat) = self;
|
|
||||||
(&dat[..]).serialize(serializer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! impl_array_newtype_show {
|
macro_rules! impl_array_newtype_show {
|
||||||
($thing:ident) => {
|
($thing:ident) => {
|
||||||
impl ::std::fmt::Debug for $thing {
|
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<D>(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<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: $crate::serde::de::Error,
|
||||||
|
{
|
||||||
|
$name::from_str(v).map_err(E::custom)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: $crate::serde::de::Error,
|
||||||
|
{
|
||||||
|
self.visit_str(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||||
|
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
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<D>(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<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: $crate::serde::de::Error,
|
||||||
|
{
|
||||||
|
$name::from_str(v).map_err(E::custom)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: $crate::serde::de::Error,
|
||||||
|
{
|
||||||
|
self.visit_str(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||||
|
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<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
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<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
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<A>(self, mut map: A) -> Result<Self::Value, A::Error>
|
||||||
|
where
|
||||||
|
A: $crate::serde::de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
use $crate::serde::de::Error;
|
||||||
|
|
||||||
|
$(let mut $fe = None;)*
|
||||||
|
|
||||||
|
loop {
|
||||||
|
match map.next_key::<Enum>()? {
|
||||||
|
Some(Enum::Unknown__Field) => {
|
||||||
|
map.next_value::<IgnoredAny>()?;
|
||||||
|
}
|
||||||
|
$(
|
||||||
|
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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
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<I>(iter: I) -> Result<Self, bitcoin_hashes::hex::Error>
|
||||||
|
where I: Iterator<Item=Result<u8, bitcoin_hashes::hex::Error>> +
|
||||||
|
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<Self, Self::Err> {
|
||||||
|
hex::FromHex::from_hex(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature="serde")]
|
||||||
|
impl ::serde::Serialize for $t {
|
||||||
|
fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
|
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: ::serde::Deserializer<'de>>(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<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||||
|
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<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
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<E>(self, v: &[u8]) -> Result<Self::Value, E>
|
||||||
|
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 {
|
macro_rules! user_enum {
|
||||||
(
|
(
|
||||||
$(#[$attr:meta])*
|
$(#[$attr:meta])*
|
||||||
|
@ -498,7 +792,7 @@ macro_rules! user_enum {
|
||||||
where
|
where
|
||||||
S: ::serde::Serializer,
|
S: ::serde::Serializer,
|
||||||
{
|
{
|
||||||
serializer.serialize_str(&self.to_string())
|
serializer.collect_str(&self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -46,9 +46,6 @@ use std::str::FromStr;
|
||||||
use bitcoin_bech32::{self, WitnessProgram, u5};
|
use bitcoin_bech32::{self, WitnessProgram, u5};
|
||||||
use bitcoin_hashes::{hash160, Hash};
|
use bitcoin_hashes::{hash160, Hash};
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
use serde;
|
|
||||||
|
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
use blockdata::script;
|
use blockdata::script;
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
|
@ -75,6 +72,7 @@ pub struct Address {
|
||||||
/// The network on which this address is usable
|
/// The network on which this address is usable
|
||||||
pub network: Network,
|
pub network: Network,
|
||||||
}
|
}
|
||||||
|
serde_string_impl!(Address, "a Bitcoin address");
|
||||||
|
|
||||||
impl Address {
|
impl Address {
|
||||||
/// Creates a pay to (compressed) public key hash address from a public key
|
/// 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<D>(deserializer: D) -> Result<Self, D::Error>
|
|
||||||
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<E>(self, v: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: serde::de::Error,
|
|
||||||
{
|
|
||||||
Address::from_str(v).map_err(E::custom)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: serde::de::Error,
|
|
||||||
{
|
|
||||||
self.visit_str(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: serde::de::Error,
|
|
||||||
{
|
|
||||||
self.visit_str(&v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_str(Visitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
impl serde::Serialize for Address {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
serializer.serialize_str(&self.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
|
@ -23,7 +23,7 @@ use std::str::FromStr;
|
||||||
#[cfg(feature = "serde")] use serde;
|
#[cfg(feature = "serde")] use serde;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
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 secp256k1::{self, Secp256k1};
|
||||||
|
|
||||||
use network::constants::Network;
|
use network::constants::Network;
|
||||||
|
@ -34,13 +34,13 @@ use util::key::{PublicKey, PrivateKey};
|
||||||
pub struct ChainCode([u8; 32]);
|
pub struct ChainCode([u8; 32]);
|
||||||
impl_array_newtype!(ChainCode, u8, 32);
|
impl_array_newtype!(ChainCode, u8, 32);
|
||||||
impl_array_newtype_show!(ChainCode);
|
impl_array_newtype_show!(ChainCode);
|
||||||
impl_array_newtype_encodable!(ChainCode, u8, 32);
|
impl_bytes_newtype!(ChainCode, 32);
|
||||||
|
|
||||||
/// A fingerprint
|
/// A fingerprint
|
||||||
pub struct Fingerprint([u8; 4]);
|
pub struct Fingerprint([u8; 4]);
|
||||||
impl_array_newtype!(Fingerprint, u8, 4);
|
impl_array_newtype!(Fingerprint, u8, 4);
|
||||||
impl_array_newtype_show!(Fingerprint);
|
impl_array_newtype_show!(Fingerprint);
|
||||||
impl_array_newtype_encodable!(Fingerprint, u8, 4);
|
impl_bytes_newtype!(Fingerprint, 4);
|
||||||
|
|
||||||
impl Default for Fingerprint {
|
impl Default for Fingerprint {
|
||||||
fn default() -> Fingerprint { Fingerprint([0; 4]) }
|
fn default() -> Fingerprint { Fingerprint([0; 4]) }
|
||||||
|
@ -62,6 +62,7 @@ pub struct ExtendedPrivKey {
|
||||||
/// Chain code
|
/// Chain code
|
||||||
pub chain_code: ChainCode
|
pub chain_code: ChainCode
|
||||||
}
|
}
|
||||||
|
serde_string_impl!(ExtendedPrivKey, "a BIP-32 extended private key");
|
||||||
|
|
||||||
/// Extended public key
|
/// Extended public key
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
@ -79,6 +80,7 @@ pub struct ExtendedPubKey {
|
||||||
/// Chain code
|
/// Chain code
|
||||||
pub chain_code: ChainCode
|
pub chain_code: ChainCode
|
||||||
}
|
}
|
||||||
|
serde_string_impl!(ExtendedPubKey, "a BIP-32 extended public key");
|
||||||
|
|
||||||
/// A child number for a derived key
|
/// A child number for a derived key
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
@ -213,6 +215,7 @@ impl serde::Serialize for ChildNumber {
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
pub struct DerivationPath(Vec<ChildNumber>);
|
pub struct DerivationPath(Vec<ChildNumber>);
|
||||||
impl_index_newtype!(DerivationPath, ChildNumber);
|
impl_index_newtype!(DerivationPath, ChildNumber);
|
||||||
|
serde_string_impl!(DerivationPath, "a BIP-32 derivation path");
|
||||||
|
|
||||||
impl From<Vec<ChildNumber>> for DerivationPath {
|
impl From<Vec<ChildNumber>> for DerivationPath {
|
||||||
fn from(numbers: Vec<ChildNumber>) -> Self {
|
fn from(numbers: Vec<ChildNumber>) -> Self {
|
||||||
|
@ -349,44 +352,6 @@ impl fmt::Debug for DerivationPath {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
impl<'de> serde::Deserialize<'de> for DerivationPath {
|
|
||||||
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
|
||||||
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<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
|
|
||||||
DerivationPath::from_str(v).map_err(E::custom)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_borrowed_str<E: de::Error>(self, v: &'de str) -> Result<Self::Value, E> {
|
|
||||||
self.visit_str(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_string<E: de::Error>(self, v: String) -> Result<Self::Value, E> {
|
|
||||||
self.visit_str(&v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
deserializer.deserialize_str(Visitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
impl serde::Serialize for DerivationPath {
|
|
||||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
|
||||||
serializer.serialize_str(&self.to_string())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A BIP32 error
|
/// A BIP32 error
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -725,6 +690,9 @@ impl FromStr for ExtendedPubKey {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use super::ChildNumber::{Hardened, Normal};
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
|
|
||||||
|
@ -733,10 +701,6 @@ mod tests {
|
||||||
|
|
||||||
use network::constants::Network::{self, Bitcoin};
|
use network::constants::Network::{self, Bitcoin};
|
||||||
|
|
||||||
use super::{ChildNumber, DerivationPath, ExtendedPrivKey, ExtendedPubKey};
|
|
||||||
use super::ChildNumber::{Hardened, Normal};
|
|
||||||
use super::Error;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_derivation_path() {
|
fn test_parse_derivation_path() {
|
||||||
assert_eq!(DerivationPath::from_str("42"), Err(Error::InvalidDerivationPathFormat));
|
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).unwrap());
|
||||||
serde_round_trip!(ChildNumber::from_hardened_idx((1 << 31) - 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()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue