Merge pull request #415 from paritytech/address_serialize

keys::Address remote serialization
This commit is contained in:
Svyatoslav Nikolsky 2017-05-07 10:13:18 +03:00 committed by GitHub
commit c3ff946e83
6 changed files with 75 additions and 79 deletions

View File

@ -28,7 +28,7 @@ pub enum Type {
}
/// `AddressHash` with network identifier and format type
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
pub struct Address {
/// The type of the address.
pub kind: Type,

View File

@ -4,7 +4,7 @@ use v1::types::{GetTxOutResponse, TransactionOutputScript};
use v1::types::GetTxOutSetInfoResponse;
use v1::types::H256;
use v1::types::U256;
use v1::types::Address;
use keys::{self, Address};
use v1::helpers::errors::{block_not_found, block_at_height_not_found, transaction_not_found,
transaction_output_not_found, transaction_of_side_branch};
use jsonrpc_macros::Trailing;
@ -146,7 +146,16 @@ impl BlockChainClientCoreApi for BlockChainClientCore {
hex: script_bytes.clone().into(),
req_sigs: script.num_signatures_required() as u32,
script_type: script.script_type().into(),
addresses: script_addresses.into_iter().map(|a| Address::new(self.network, a)).collect(),
addresses: script_addresses.into_iter().map(|a| Address {
network: match self.network {
Magic::Mainnet => keys::Network::Mainnet,
// there's no correct choices for Regtests && Other networks
// => let's just make Testnet key
_ => keys::Network::Testnet,
},
hash: a.hash,
kind: a.kind,
}).collect(),
},
version: transaction.version,
coinbase: transaction.is_coinbase(),

View File

@ -55,9 +55,9 @@ impl RawClientCore {
.map(|output| match output {
TransactionOutput::Address(with_address) => {
let amount_in_satoshis = (with_address.amount * (chain::constants::SATOSHIS_IN_COIN as f64)) as u64;
let script = match (*with_address.address).kind {
keys::Type::P2PKH => ScriptBuilder::build_p2pkh(&(*with_address.address).hash),
keys::Type::P2SH => ScriptBuilder::build_p2sh(&(*with_address.address).hash),
let script = match with_address.address.kind {
keys::Type::P2PKH => ScriptBuilder::build_p2pkh(&with_address.address.hash),
keys::Type::P2SH => ScriptBuilder::build_p2sh(&with_address.address.hash),
};
chain::TransactionOutput {

View File

@ -1,92 +1,78 @@
use std::{ops, fmt};
use std::str::FromStr;
use serde::{Serialize, Deserialize, Serializer, Deserializer};
use serde::de::{Visitor, Unexpected, Expected};
use global_script::ScriptAddress;
use keys::Address as GlobalAddress;
use keys::Network as KeysNetwork;
use network::Magic;
use std::fmt;
use serde::{Serialize, Serializer, Deserializer};
use serde::de::{Visitor, Unexpected};
use keys::Address;
/// Bitcoin address
#[derive(Debug, PartialEq)]
pub struct Address(GlobalAddress);
pub fn serialize<S>(address: &Address, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
address.to_string().serialize(serializer)
}
impl Address {
pub fn new(network: Magic, address: ScriptAddress) -> Self {
Address(GlobalAddress {
network: match network {
Magic::Mainnet => KeysNetwork::Mainnet,
// there's no correct choices for Regtests && Other networks
// => let's just make Testnet key
_ => KeysNetwork::Testnet,
},
hash: address.hash,
kind: address.kind,
})
pub fn deserialize<'a, D>(deserializer: D) -> Result<Address, D::Error> where D: Deserializer<'a> {
deserializer.deserialize_any(AddressVisitor)
}
#[derive(Default)]
pub struct AddressVisitor;
impl<'b> Visitor<'b> for AddressVisitor {
type Value = Address;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an address")
}
pub fn deserialize_from_string<E>(value: &str, expected: &Expected) -> Result<Address, E> where E: ::serde::de::Error {
GlobalAddress::from_str(value)
.map(Address)
.map_err(|_| E::invalid_value(Unexpected::Str(value), expected))
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: ::serde::de::Error {
value.parse().map_err(|_| E::invalid_value(Unexpected::Str(value), &self))
}
}
impl Serialize for Address {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
serializer.serialize_str(&self.0.to_string())
pub mod vec {
use serde::{Serialize, Serializer, Deserializer, Deserialize};
use serde::de::Visitor;
use keys::Address;
use super::AddressVisitor;
pub fn serialize<S>(addresses: &Vec<Address>, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
addresses.iter().map(|address| address.to_string()).collect::<Vec<_>>().serialize(serializer)
}
}
impl<'a> Deserialize<'a> for Address {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'a> {
struct AddressVisitor;
impl<'b> Visitor<'b> for AddressVisitor {
type Value = Address;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an address")
}
fn visit_str<E>(self, value: &str) -> Result<Address, E> where E: ::serde::de::Error {
Address::deserialize_from_string(value, &self)
}
}
deserializer.deserialize_identifier(AddressVisitor)
}
}
impl<T> From<T> for Address where GlobalAddress: From<T> {
fn from(o: T) -> Self {
Address(GlobalAddress::from(o))
}
}
impl ops::Deref for Address {
type Target = GlobalAddress;
fn deref(&self) -> &Self::Target {
&self.0
pub fn deserialize<'a, D>(deserializer: D) -> Result<Vec<Address>, D::Error> where D: Deserializer<'a> {
<Vec<&'a str> as Deserialize>::deserialize(deserializer)?
.into_iter()
.map(|value| AddressVisitor::default().visit_str(value))
.collect()
}
}
#[cfg(test)]
mod tests {
use serde_json;
use super::Address;
use keys::Address;
use v1::types;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct TestStruct {
#[serde(with = "types::address")]
address: Address,
}
impl TestStruct {
fn new(address: Address) -> Self {
TestStruct {
address: address,
}
}
}
#[test]
fn address_serialize() {
let address: Address = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into();
assert_eq!(serde_json::to_string(&address).unwrap(), r#""1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa""#);
let test = TestStruct::new("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into());
assert_eq!(serde_json::to_string(&test).unwrap(), r#"{"address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"}"#);
}
#[test]
fn address_deserialize() {
let address: Address = "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into();
assert_eq!(serde_json::from_str::<Address>(r#""1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa""#).unwrap(), address);
assert!(serde_json::from_str::<Address>(r#""DEADBEEF""#).is_err());
let test = TestStruct::new("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into());
assert_eq!(serde_json::from_str::<TestStruct>(r#"{"address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"}"#).unwrap(), test);
}
}

View File

@ -1,4 +1,4 @@
mod address;
pub mod address;
mod block;
mod block_template;
mod block_template_request;
@ -12,7 +12,6 @@ mod transaction;
mod uint;
mod nodes;
pub use self::address::Address;
pub use self::block::RawBlock;
pub use self::block_template::{BlockTemplate, BlockTemplateTransaction};
pub use self::block_template_request::{BlockTemplateRequest, BlockTemplateRequestMode};

View File

@ -1,7 +1,8 @@
use std::fmt;
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use serde::ser::SerializeMap;
use super::address::Address;
use keys::Address;
use v1::types;
use super::bytes::Bytes;
use super::hash::H256;
use super::script::ScriptType;
@ -75,6 +76,7 @@ pub struct TransactionOutputScript {
#[serde(rename = "type")]
pub script_type: ScriptType,
/// Array of bitcoin addresses
#[serde(with = "types::address::vec")]
pub addresses: Vec<Address>,
}
@ -166,7 +168,7 @@ impl Serialize for TransactionOutputs {
for output in &self.outputs {
match output {
&TransactionOutput::Address(ref address_output) => {
state.serialize_entry(&address_output.address, &address_output.amount)?;
state.serialize_entry(&address_output.address.to_string(), &address_output.amount)?;
},
&TransactionOutput::ScriptData(ref script_output) => {
state.serialize_entry("data", &script_output.script_data)?;
@ -200,7 +202,7 @@ impl<'a> Deserialize<'a> for TransactionOutputs {
script_data: value,
}));
} else {
let address = try!(Address::deserialize_from_string(&key, &"an address"));
let address = types::address::AddressVisitor::default().visit_str(&key)?;
let amount: f64 = try!(visitor.next_value());
outputs.push(TransactionOutput::Address(TransactionOutputWithAddress {
address: address,