From fc146bd2250365b487a896f0446818a73e3c5fbc Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Sat, 10 Dec 2016 21:24:39 +0300 Subject: [PATCH] continue blockchain RPCs --- Cargo.lock | 7 +- rpc/Cargo.toml | 1 + rpc/src/lib.rs | 1 + rpc/src/v1/impls/blockchain.rs | 7 +- rpc/src/v1/traits/blockchain.rs | 4 +- rpc/src/v1/types/get_tx_out_response.rs | 35 ++++++++ rpc/src/v1/types/hash.rs | 18 +++-- rpc/src/v1/types/mod.rs.in | 2 + rpc/src/v1/types/script.rs | 102 ++++++++++++++++++++++++ script/src/lib.rs | 2 +- 10 files changed, 160 insertions(+), 19 deletions(-) create mode 100644 rpc/src/v1/types/script.rs diff --git a/Cargo.lock b/Cargo.lock index fe1f6f02..613d898e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -331,7 +331,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-core" version = "4.0.0" -source = "git+https://github.com/ethcore/jsonrpc.git#140257f1a726e9190bdaafeb4625b2a5400de4da" +source = "git+https://github.com/ethcore/jsonrpc.git#ce49b762bc3e005f0cf549e1d98fc51b47f2aa54" dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -343,7 +343,7 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" version = "6.1.1" -source = "git+https://github.com/ethcore/jsonrpc.git#140257f1a726e9190bdaafeb4625b2a5400de4da" +source = "git+https://github.com/ethcore/jsonrpc.git#ce49b762bc3e005f0cf549e1d98fc51b47f2aa54" dependencies = [ "hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)", "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", @@ -354,7 +354,7 @@ dependencies = [ [[package]] name = "jsonrpc-macros" version = "0.1.0" -source = "git+https://github.com/ethcore/jsonrpc.git#140257f1a726e9190bdaafeb4625b2a5400de4da" +source = "git+https://github.com/ethcore/jsonrpc.git#ce49b762bc3e005f0cf549e1d98fc51b47f2aa54" dependencies = [ "jsonrpc-core 4.0.0 (git+https://github.com/ethcore/jsonrpc.git)", "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -810,6 +810,7 @@ dependencies = [ "p2p 0.1.0", "primitives 0.1.0", "rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "script 0.1.0", "serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index f0a05ae7..d1d14c0d 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -28,6 +28,7 @@ db = { path = "../db" } test-data = { path = "../test-data" } miner = { path = "../miner" } verification = { path = "../verification" } +script = { path = "../script" } [build-dependencies] serde_codegen = { version = "0.8.0", optional = true } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index b8a0376b..816d4e4c 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -23,6 +23,7 @@ extern crate miner; extern crate verification; #[cfg(test)] extern crate ethcore_devtools as devtools; +extern crate script; pub mod v1; pub mod rpc_server; diff --git a/rpc/src/v1/impls/blockchain.rs b/rpc/src/v1/impls/blockchain.rs index dfd39bdb..ed9ed399 100644 --- a/rpc/src/v1/impls/blockchain.rs +++ b/rpc/src/v1/impls/blockchain.rs @@ -6,15 +6,13 @@ use v1::types::GetTxOutSetInfoResponse; use v1::types::H256; use v1::types::U256; use v1::helpers::errors::{block_not_found, block_at_height_not_found}; +use jsonrpc_macros::Trailing; use jsonrpc_core::Error; use db; use verification; use ser::serialize; use primitives::hash::H256 as GlobalH256; -// TODO -// use jsonrpc_macros::Trailing; -type Trailing = Option; pub struct BlockChainClient { core: T, @@ -122,7 +120,7 @@ impl BlockChain for BlockChainClient where T: BlockChainClientCoreApi { fn block(&self, hash: H256, verbose: Trailing) -> Result { let global_hash: GlobalH256 = hash.clone().into(); - if verbose.unwrap_or_default() { + if verbose.0 { let verbose_block = self.core.verbose_block(global_hash.reversed()); if let Some(mut verbose_block) = verbose_block { verbose_block.previousblockhash = verbose_block.previousblockhash.map(|h| h.reversed()); @@ -142,6 +140,7 @@ impl BlockChain for BlockChainClient where T: BlockChainClientCoreApi { } fn transaction(&self, _hash: H256, _watch_only: Trailing) -> Result { + // TODO: we do not have wallet yet => we can not support rpc_unimplemented!() } diff --git a/rpc/src/v1/traits/blockchain.rs b/rpc/src/v1/traits/blockchain.rs index 44228127..74a925bc 100644 --- a/rpc/src/v1/traits/blockchain.rs +++ b/rpc/src/v1/traits/blockchain.rs @@ -1,3 +1,4 @@ +use jsonrpc_macros::Trailing; use jsonrpc_core::Error; use v1::types::H256; @@ -6,9 +7,6 @@ use v1::types::GetTransactionResponse; use v1::types::GetTxOutResponse; use v1::types::GetTxOutSetInfoResponse; -// TODO -// use jsonrpc_macros::Trailing; -type Trailing = Option; build_rpc_trait! { /// Parity-bitcoin blockchain data interface. diff --git a/rpc/src/v1/types/get_tx_out_response.rs b/rpc/src/v1/types/get_tx_out_response.rs index e7bfc620..7fa884c5 100644 --- a/rpc/src/v1/types/get_tx_out_response.rs +++ b/rpc/src/v1/types/get_tx_out_response.rs @@ -1,3 +1,38 @@ +use super::bytes::Bytes; +use super::hash::{H160, H256}; +use super::script::ScriptType; + +/// gettxout response #[derive(Debug, Serialize, Deserialize)] pub struct GetTxOutResponse { + /// Hash of the block this transaction output is included into. + bestblock: H256, + /// Number of confirmations of this transaction + confirmations: u32, + /// Transaction value in BTC + value: f64, + /// Script info + #[serde(rename = "scriptPubKey")] + script_pub_key: TxOutScriptPubKey, + /// This transaction version + version: i32, + /// Is this transactio a coinbase transaction? + coinbase: bool, +} + +/// Script pub key information +#[derive(Debug, Serialize, Deserialize)] +pub struct TxOutScriptPubKey { + /// Script code + asm: String, + /// Script hex + hex: Bytes, + /// Number of required signatures + #[serde(rename = "reqSigs")] + req_sigs: u32, + /// Type of script + #[serde(rename = "type")] + script_type: ScriptType, + /// Array of bitcoin addresses + addresses: Vec, } diff --git a/rpc/src/v1/types/hash.rs b/rpc/src/v1/types/hash.rs index 24c3f299..428765bc 100644 --- a/rpc/src/v1/types/hash.rs +++ b/rpc/src/v1/types/hash.rs @@ -5,6 +5,7 @@ use std::hash::{Hash, Hasher}; use serde; use rustc_serialize::hex::{ToHex, FromHex}; use primitives::hash::H256 as GlobalH256; +use primitives::hash::H160 as GlobalH160; macro_rules! impl_hash { ($name: ident, $other: ident, $size: expr) => { @@ -12,14 +13,6 @@ macro_rules! impl_hash { #[derive(Eq)] pub struct $name([u8; $size]); - impl $name { - pub fn reversed(&self) -> Self { - let mut result = self.clone(); - result.0.reverse(); - result - } - } - impl Default for $name { fn default() -> Self { $name([0; $size]) @@ -135,6 +128,15 @@ macro_rules! impl_hash { } impl_hash!(H256, GlobalH256, 32); +impl_hash!(H160, GlobalH160, 20); + +impl H256 { + pub fn reversed(&self) -> Self { + let mut result = self.clone(); + result.0.reverse(); + result + } +} #[cfg(test)] mod tests { diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index dbd4f77e..58d73215 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -8,6 +8,7 @@ mod get_tx_out_set_info_response; mod hash; mod raw_block; mod raw_transaction; +mod script; mod uint; pub use self::block_template::{BlockTemplate, BlockTemplateTransaction}; @@ -20,4 +21,5 @@ pub use self::get_tx_out_set_info_response::GetTxOutSetInfoResponse; pub use self::hash::H256; pub use self::raw_block::RawBlock; pub use self::raw_transaction::RawTransaction; +pub use self::script::ScriptType; pub use self::uint::U256; diff --git a/rpc/src/v1/types/script.rs b/rpc/src/v1/types/script.rs new file mode 100644 index 00000000..bf9fbe13 --- /dev/null +++ b/rpc/src/v1/types/script.rs @@ -0,0 +1,102 @@ +use serde::{Serialize, Deserialize, Serializer, Deserializer}; +use script::ScriptType as GlobalScriptType; + +#[derive(Debug, PartialEq)] +pub enum ScriptType { + NonStandard, + PubKey, + PubKeyHash, + ScriptHash, + Multisig, + NullData, + WitnessScript, + WitnessKey, +} + +impl From for ScriptType { + fn from(script_type: GlobalScriptType) -> Self { + match script_type { + GlobalScriptType::NonStandard => ScriptType::NonStandard, + GlobalScriptType::PubKey => ScriptType::PubKey, + GlobalScriptType::PubKeyHash => ScriptType::PubKeyHash, + GlobalScriptType::ScriptHash => ScriptType::ScriptHash, + GlobalScriptType::Multisig => ScriptType::Multisig, + GlobalScriptType::NullData => ScriptType::NullData, + GlobalScriptType::WitnessScript => ScriptType::WitnessScript, + GlobalScriptType::WitnessKey => ScriptType::WitnessKey, + } + } +} + +impl Serialize for ScriptType { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { + match *self { + ScriptType::NonStandard => "nonstandard".serialize(serializer), + ScriptType::PubKey => "pubkey".serialize(serializer), + ScriptType::PubKeyHash => "pubkeyhash".serialize(serializer), + ScriptType::ScriptHash => "scripthash".serialize(serializer), + ScriptType::Multisig => "multisig".serialize(serializer), + ScriptType::NullData => "nulldata".serialize(serializer), + ScriptType::WitnessScript => "witness_v0_scripthash".serialize(serializer), + ScriptType::WitnessKey => "witness_v0_keyhash".serialize(serializer), + } + } +} + +impl Deserialize for ScriptType { + fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { + use serde::de::Visitor; + + struct ScriptTypeVisitor; + + impl Visitor for ScriptTypeVisitor { + type Value = ScriptType; + + fn visit_str(&mut self, value: &str) -> Result where E: ::serde::de::Error { + match value { + "nonstandard" => Ok(ScriptType::NonStandard), + "pubkey" => Ok(ScriptType::PubKey), + "pubkeyhash" => Ok(ScriptType::PubKeyHash), + "scripthash" => Ok(ScriptType::ScriptHash), + "multisig" => Ok(ScriptType::Multisig), + "nulldata" => Ok(ScriptType::NullData), + "witness_v0_scripthash" => Ok(ScriptType::WitnessScript), + "witness_v0_keyhash" => Ok(ScriptType::WitnessKey), + _ => Err(E::invalid_value(&format!("unknown ScriptType variant: {}", value))), + } + } + } + + deserializer.deserialize(ScriptTypeVisitor) + } +} + +#[cfg(test)] +mod tests { + use super::ScriptType; + use serde_json; + + #[test] + fn script_type_serialize() { + assert_eq!(serde_json::to_string(&ScriptType::NonStandard).unwrap(), r#""nonstandard""#); + assert_eq!(serde_json::to_string(&ScriptType::PubKey).unwrap(), r#""pubkey""#); + assert_eq!(serde_json::to_string(&ScriptType::PubKeyHash).unwrap(), r#""pubkeyhash""#); + assert_eq!(serde_json::to_string(&ScriptType::ScriptHash).unwrap(), r#""scripthash""#); + assert_eq!(serde_json::to_string(&ScriptType::Multisig).unwrap(), r#""multisig""#); + assert_eq!(serde_json::to_string(&ScriptType::NullData).unwrap(), r#""nulldata""#); + assert_eq!(serde_json::to_string(&ScriptType::WitnessScript).unwrap(), r#""witness_v0_scripthash""#); + assert_eq!(serde_json::to_string(&ScriptType::WitnessKey).unwrap(), r#""witness_v0_keyhash""#); + } + + #[test] + fn script_type_deserialize() { + assert_eq!(serde_json::from_str::(r#""nonstandard""#).unwrap(), ScriptType::NonStandard); + assert_eq!(serde_json::from_str::(r#""pubkey""#).unwrap(), ScriptType::PubKey); + assert_eq!(serde_json::from_str::(r#""pubkeyhash""#).unwrap(), ScriptType::PubKeyHash); + assert_eq!(serde_json::from_str::(r#""scripthash""#).unwrap(), ScriptType::ScriptHash); + assert_eq!(serde_json::from_str::(r#""multisig""#).unwrap(), ScriptType::Multisig); + assert_eq!(serde_json::from_str::(r#""nulldata""#).unwrap(), ScriptType::NullData); + assert_eq!(serde_json::from_str::(r#""witness_v0_scripthash""#).unwrap(), ScriptType::WitnessScript); + assert_eq!(serde_json::from_str::(r#""witness_v0_keyhash""#).unwrap(), ScriptType::WitnessKey); + } +} diff --git a/script/src/lib.rs b/script/src/lib.rs index 09ba56c6..e90f8bf3 100644 --- a/script/src/lib.rs +++ b/script/src/lib.rs @@ -25,7 +25,7 @@ pub use self::flags::VerificationFlags; pub use self::interpreter::{eval_script, verify_script}; pub use self::opcode::Opcode; pub use self::num::Num; -pub use self::script::Script; +pub use self::script::{Script, ScriptType}; pub use self::sign::{ TransactionInputSigner, UnsignedTransactionInput, Sighash, SighashBase, SignatureVersion