diff --git a/keys/src/address.rs b/keys/src/address.rs index 3d22f609..40987c40 100644 --- a/keys/src/address.rs +++ b/keys/src/address.rs @@ -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, diff --git a/rpc/src/v1/impls/blockchain.rs b/rpc/src/v1/impls/blockchain.rs index c7c7098d..d7562424 100644 --- a/rpc/src/v1/impls/blockchain.rs +++ b/rpc/src/v1/impls/blockchain.rs @@ -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(), diff --git a/rpc/src/v1/impls/raw.rs b/rpc/src/v1/impls/raw.rs index fb88688b..f8a39ab5 100644 --- a/rpc/src/v1/impls/raw.rs +++ b/rpc/src/v1/impls/raw.rs @@ -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 { diff --git a/rpc/src/v1/types/address.rs b/rpc/src/v1/types/address.rs index d19b6d3f..c8b611b1 100644 --- a/rpc/src/v1/types/address.rs +++ b/rpc/src/v1/types/address.rs @@ -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(address: &Address, serializer: S) -> Result 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 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(value: &str, expected: &Expected) -> Result where E: ::serde::de::Error { - GlobalAddress::from_str(value) - .map(Address) - .map_err(|_| E::invalid_value(Unexpected::Str(value), expected)) + fn visit_str(self, value: &str) -> Result where E: ::serde::de::Error { + value.parse().map_err(|_| E::invalid_value(Unexpected::Str(value), &self)) } } -impl Serialize for Address { - fn serialize(&self, serializer: S) -> Result 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(addresses: &Vec
, serializer: S) -> Result where S: Serializer { + addresses.iter().map(|address| address.to_string()).collect::>().serialize(serializer) } -} -impl<'a> Deserialize<'a> for Address { - fn deserialize(deserializer: D) -> Result 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(self, value: &str) -> Result where E: ::serde::de::Error { - Address::deserialize_from_string(value, &self) - } - } - - deserializer.deserialize_identifier(AddressVisitor) - } -} - -impl From for Address where GlobalAddress: From { - 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, D::Error> where D: Deserializer<'a> { + 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::
(r#""1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa""#).unwrap(), address); - assert!(serde_json::from_str::
(r#""DEADBEEF""#).is_err()); + let test = TestStruct::new("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa".into()); + assert_eq!(serde_json::from_str::(r#"{"address":"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"}"#).unwrap(), test); } } diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 90f64e85..8e4bee7f 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -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}; diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 09a26670..ded7f080 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -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
, } @@ -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,