From c50eb78ca1efe1aa48ff93688df47bfe2137d33b Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 13:17:44 +0100 Subject: [PATCH] jsonrpc optionals --- ethcore/src/client.rs | 8 +++++ ethcore/src/lib.rs | 2 +- ethcore/src/transaction.rs | 3 +- rpc/src/v1/impls/eth.rs | 33 +++++++++++++++++-- rpc/src/v1/traits/eth.rs | 1 + rpc/src/v1/types/block.rs | 14 ++++---- rpc/src/v1/types/mod.rs | 2 ++ rpc/src/v1/types/optionals.rs | 58 +++++++++++++++++++++++++++++++++ rpc/src/v1/types/transaction.rs | 26 +++++++-------- 9 files changed, 121 insertions(+), 26 deletions(-) create mode 100644 rpc/src/v1/types/optionals.rs diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index b31f98f0b..f9e9be475 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -31,6 +31,7 @@ use service::{NetSyncMessage, SyncMessage}; use env_info::LastHashes; use verification::*; use block::*; +use transaction::SignedTransaction; pub use blockchain::TreeRoute; /// General block status @@ -104,6 +105,9 @@ pub trait BlockChainClient : Sync + Send { /// Get block total difficulty. fn block_total_difficulty_at(&self, n: BlockNumber) -> Option; + /// Get transaction with given hash. + fn transaction(&self, hash: &H256) -> Option; + /// Get a tree route between `from` and `to`. /// See `BlockChain::tree_route`. fn tree_route(&self, from: &H256, to: &H256) -> Option; @@ -388,6 +392,10 @@ impl BlockChainClient for Client { self.chain.read().unwrap().block_hash(n).and_then(|h| self.block_total_difficulty(&h)) } + fn transaction(&self, hash: &H256) -> Option { + self.chain.read().unwrap().transaction(hash) + } + fn tree_route(&self, from: &H256, to: &H256) -> Option { self.chain.read().unwrap().tree_route(from.clone(), to.clone()) } diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 9537c8862..6c4535339 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -98,6 +98,7 @@ pub mod ethereum; pub mod header; pub mod service; pub mod spec; +pub mod transaction; pub mod views; pub mod receipt; @@ -115,7 +116,6 @@ mod state; mod account; mod account_db; mod action_params; -mod transaction; mod null_engine; mod builtin; mod extras; diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index 119f565dd..c431fe605 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -156,8 +156,7 @@ impl Transaction { } } - - +/// Signed transaction information. #[derive(Debug, Clone, Eq)] pub struct SignedTransaction { /// Plain Transaction. diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 606a1ba6d..4ef75bdd2 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -22,8 +22,9 @@ use util::uint::*; use util::sha3::*; use ethcore::client::*; use ethcore::views::*; +use ethcore::transaction::Action; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, Transaction, OptionalValue}; /// Eth rpc implementation. pub struct EthClient { @@ -129,7 +130,7 @@ impl Eth for EthClient { (Some(bytes), Some(total_difficulty)) => { let view = HeaderView::new(&bytes); let block = Block { - hash: view.sha3(), + hash: OptionalValue::Value(view.sha3()), parent_hash: view.parent_hash(), uncles_hash: view.uncles_hash(), author: view.author(), @@ -137,7 +138,7 @@ impl Eth for EthClient { state_root: view.state_root(), transactions_root: view.transactions_root(), receipts_root: view.receipts_root(), - number: U256::from(view.number()), + number: OptionalValue::Value(U256::from(view.number())), gas_used: view.gas_used(), gas_limit: view.gas_limit(), logs_bloom: view.log_bloom(), @@ -161,8 +162,34 @@ impl Eth for EthClient { Err(err) => Err(err) } } + + fn transaction_at(&self, params: Params) -> Result { + match from_params::(params) { + Ok(hash) => match self.client.transaction(&hash) { + Some(t) => to_value(&Transaction { + hash: t.hash(), + nonce: t.nonce, + block_hash: OptionalValue::Value(H256::default()), // todo + block_number: OptionalValue::Value(U256::default()), // todo + transaction_index: U256::default(), // todo + from: t.sender().unwrap(), + to: match t.action { + Action::Create => OptionalValue::Null, + Action::Call(ref address) => OptionalValue::Value(address.clone()) + }, + value: t.value, + gas_price: t.gas_price, + gas: t.gas, + input: Bytes::new(t.data.clone()) + }), + None => Ok(Value::Null) + }, + Err(err) => Err(err) + } + } } + /// Eth filter rpc implementation. pub struct EthFilterClient { client: Arc diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index d247e2174..b0b9a3cf4 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -131,6 +131,7 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_estimateGas", Eth::estimate_gas); delegate.add_method("eth_getBlockByHash", Eth::block); delegate.add_method("eth_getBlockByNumber", Eth::block); + delegate.add_method("eth_getTransactionByHash", Eth::transaction_at); delegate.add_method("eth_getTransactionByBlockHashAndIndex", Eth::transaction_at); delegate.add_method("eth_getTransactionByBlockNumberAndIndex", Eth::transaction_at); delegate.add_method("eth_getTransactionReceipt", Eth::transaction_receipt); diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index 59cafcf60..d3dced686 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -17,7 +17,7 @@ use serde::{Serialize, Serializer}; use util::hash::*; use util::uint::*; -use v1::types::{Bytes, Transaction}; +use v1::types::{Bytes, Transaction, OptionalValue}; #[derive(Debug)] pub enum BlockTransactions { @@ -37,7 +37,7 @@ impl Serialize for BlockTransactions { #[derive(Debug, Serialize)] pub struct Block { - pub hash: H256, + pub hash: OptionalValue, #[serde(rename="parentHash")] pub parent_hash: H256, #[serde(rename="sha3Uncles")] @@ -51,7 +51,7 @@ pub struct Block { pub transactions_root: H256, #[serde(rename="receiptsRoot")] pub receipts_root: H256, - pub number: U256, + pub number: OptionalValue, #[serde(rename="gasUsed")] pub gas_used: U256, #[serde(rename="gasLimit")] @@ -73,14 +73,14 @@ mod tests { use serde_json; use util::hash::*; use util::uint::*; - use v1::types::{Transaction, Bytes}; + use v1::types::{Transaction, Bytes, OptionalValue}; use super::*; #[test] fn test_serialize_block_transactions() { let t = BlockTransactions::Full(vec![Transaction::default()]); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x00","transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}]"#); + assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}]"#); let t = BlockTransactions::Hashes(vec![H256::default()]); let serialized = serde_json::to_string(&t).unwrap(); @@ -90,7 +90,7 @@ mod tests { #[test] fn test_serialize_block() { let block = Block { - hash: H256::default(), + hash: OptionalValue::Value(H256::default()), parent_hash: H256::default(), uncles_hash: H256::default(), author: Address::default(), @@ -98,7 +98,7 @@ mod tests { state_root: H256::default(), transactions_root: H256::default(), receipts_root: H256::default(), - number: U256::default(), + number: OptionalValue::Value(U256::default()), gas_used: U256::default(), gas_limit: U256::default(), extra_data: Bytes::default(), diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 2286c69a1..9dc57f24f 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -17,11 +17,13 @@ mod block; mod block_number; mod bytes; +mod optionals; mod sync; mod transaction; pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; pub use self::bytes::Bytes; +pub use self::optionals::OptionalValue; pub use self::sync::SyncStatus; pub use self::transaction::Transaction; diff --git a/rpc/src/v1/types/optionals.rs b/rpc/src/v1/types/optionals.rs new file mode 100644 index 000000000..5db272251 --- /dev/null +++ b/rpc/src/v1/types/optionals.rs @@ -0,0 +1,58 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use serde::{Serialize, Serializer}; +use serde_json::Value; + +#[derive(Debug)] +pub enum OptionalValue where T: Serialize { + Value(T), + Null +} + +impl Default for OptionalValue where T: Serialize { + fn default() -> Self { + OptionalValue::Null + } +} + +impl Serialize for OptionalValue where T: Serialize { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: Serializer { + match *self { + OptionalValue::Value(ref value) => value.serialize(serializer), + OptionalValue::Null => Value::Null.serialize(serializer) + } + } +} + +#[cfg(test)] +mod tests { + use serde_json; + use util::hash::*; + use super::*; + + #[test] + fn test_serialize_optional_value() { + let v: OptionalValue = OptionalValue::Null; + let serialized = serde_json::to_string(&v).unwrap(); + assert_eq!(serialized, r#"null"#); + + let v = OptionalValue::Value(H256::default()); + let serialized = serde_json::to_string(&v).unwrap(); + assert_eq!(serialized, r#""0x0000000000000000000000000000000000000000000000000000000000000000""#); + } +} diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 968ec2471..147e6d2a7 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -16,25 +16,25 @@ use util::hash::*; use util::uint::*; -use v1::types::Bytes; +use v1::types::{Bytes, OptionalValue}; #[derive(Debug, Default, Serialize)] pub struct Transaction { - hash: H256, - nonce: U256, + pub hash: H256, + pub nonce: U256, #[serde(rename="blockHash")] - block_hash: H256, + pub block_hash: OptionalValue, #[serde(rename="blockNumber")] - block_number: U256, + pub block_number: OptionalValue, #[serde(rename="transactionIndex")] - transaction_index: U256, - from: Address, - to: Address, - value: U256, + pub transaction_index: U256, + pub from: Address, + pub to: OptionalValue
, + pub value: U256, #[serde(rename="gasPrice")] - gas_price: U256, - gas: U256, - input: Bytes + pub gas_price: U256, + pub gas: U256, + pub input: Bytes } #[cfg(test)] @@ -46,7 +46,7 @@ mod tests { fn test_transaction_serialize() { let t = Transaction::default(); let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x00","transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":"0x0000000000000000000000000000000000000000","value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}"#); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}"#); } }