From c50eb78ca1efe1aa48ff93688df47bfe2137d33b Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 13:17:44 +0100 Subject: [PATCH 01/15] 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"}"#); } } From 5d05c367916191b0312cd6dfe9a728d4f2b16269 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 15:17:01 +0100 Subject: [PATCH 02/15] LocalizedTransaction --- ethcore/src/blockchain.rs | 10 +++++----- ethcore/src/client.rs | 6 +++--- ethcore/src/transaction.rs | 21 +++++++++++++++++++++ ethcore/src/views.rs | 16 ++++++++++++++++ rpc/src/v1/impls/eth.rs | 18 +++++++++--------- rpc/src/v1/types/block.rs | 2 +- rpc/src/v1/types/transaction.rs | 4 ++-- 7 files changed, 57 insertions(+), 20 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index ff1e508d3..af7800870 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -111,19 +111,19 @@ pub trait BlockProvider { } /// Get transaction with given transaction hash. - fn transaction(&self, hash: &H256) -> Option { + fn transaction(&self, hash: &H256) -> Option { self.transaction_address(hash).and_then(|address| self.transaction_at(&address)) } /// Get transaction at given address. - fn transaction_at(&self, address: &TransactionAddress) -> Option { - self.block(&address.block_hash).map(|bytes| BlockView::new(&bytes).transactions()).and_then(|t| t.into_iter().nth(address.index)) + fn transaction_at(&self, address: &TransactionAddress) -> Option { + self.block(&address.block_hash).map(|bytes| BlockView::new(&bytes).localized_transactions()).and_then(|t| t.into_iter().nth(address.index)) } /// Get a list of transactions for a given block. /// Returns None if block deos not exist. - fn transactions(&self, hash: &H256) -> Option> { - self.block(hash).map(|bytes| BlockView::new(&bytes).transactions()) + fn transactions(&self, hash: &H256) -> Option> { + self.block(hash).map(|bytes| BlockView::new(&bytes).localized_transactions()) } /// Returns reference to genesis hash. diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 84d7a7209..002f5bffe 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -31,7 +31,7 @@ use service::{NetSyncMessage, SyncMessage}; use env_info::LastHashes; use verification::*; use block::*; -use transaction::SignedTransaction; +use transaction::LocalizedTransaction; pub use blockchain::TreeRoute; /// General block status @@ -106,7 +106,7 @@ pub trait BlockChainClient : Sync + Send { fn block_total_difficulty_at(&self, n: BlockNumber) -> Option; /// Get transaction with given hash. - fn transaction(&self, hash: &H256) -> Option; + fn transaction(&self, hash: &H256) -> Option; /// Get a tree route between `from` and `to`. /// See `BlockChain::tree_route`. @@ -392,7 +392,7 @@ 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 { + fn transaction(&self, hash: &H256) -> Option { self.chain.read().unwrap().transaction(hash) } diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index c431fe605..2713290bb 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -19,6 +19,7 @@ use util::*; use error::*; use evm::Schedule; +use header::BlockNumber; #[derive(Debug, Clone, PartialEq, Eq)] /// Transaction action type. @@ -289,6 +290,26 @@ impl SignedTransaction { } } +/// Signed Transaction that is a part of canon blockchain. +pub struct LocalizedTransaction { + /// Signed part. + pub signed: SignedTransaction, + /// Block number. + pub block_number: BlockNumber, + /// Block hash. + pub block_hash: H256, + /// Transaction index within block. + pub transaction_index: usize +} + +impl Deref for LocalizedTransaction { + type Target = SignedTransaction; + + fn deref(&self) -> &Self::Target { + &self.signed + } +} + #[test] fn sender_test() { let t: SignedTransaction = decode(&FromHex::from_hex("f85f800182520894095e7baea6a6c7c4c2dfeb977efac326af552d870a801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804").unwrap()); diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index 5b6b56ea5..3cfe5f183 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -155,6 +155,22 @@ impl<'a> BlockView<'a> { self.rlp.val_at(1) } + /// Return List of transactions with additional localization info. + pub fn localized_transactions(&self) -> Vec { + let header = self.header_view(); + let block_hash = header.sha3(); + let block_number = header.number(); + self.rlp.val_at::>(1) + .into_iter() + .enumerate() + .map(|(i, t)| LocalizedTransaction { + signed: t, + block_hash: block_hash.clone(), + block_number: block_number, + transaction_index: i + }).collect() + } + /// Return number of transactions in given block, without deserializing them. pub fn transactions_count(&self) -> usize { self.rlp.at(1).iter().count() diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 4ef75bdd2..ef5f5b732 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -97,8 +97,8 @@ impl Eth for EthClient { } fn block_transaction_count(&self, params: Params) -> Result { - match from_params::(params) { - Ok(hash) => match self.client.block(&hash) { + match from_params::<(H256,)>(params) { + Ok((hash,)) => match self.client.block(&hash) { Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), None => Ok(Value::Null) }, @@ -107,8 +107,8 @@ impl Eth for EthClient { } fn block_uncles_count(&self, params: Params) -> Result { - match from_params::(params) { - Ok(hash) => match self.client.block(&hash) { + match from_params::<(H256,)>(params) { + Ok((hash,)) => match self.client.block(&hash) { Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()), None => Ok(Value::Null) }, @@ -164,14 +164,14 @@ impl Eth for EthClient { } fn transaction_at(&self, params: Params) -> Result { - match from_params::(params) { - Ok(hash) => match self.client.transaction(&hash) { + match from_params::<(H256,)>(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 + block_hash: OptionalValue::Value(t.block_hash.clone()), + block_number: OptionalValue::Value(U256::from(t.block_number)), + transaction_index: OptionalValue::Value(U256::from(t.transaction_index)), from: t.sender().unwrap(), to: match t.action { Action::Create => OptionalValue::Null, diff --git a/rpc/src/v1/types/block.rs b/rpc/src/v1/types/block.rs index d3dced686..b92111bcb 100644 --- a/rpc/src/v1/types/block.rs +++ b/rpc/src/v1/types/block.rs @@ -80,7 +80,7 @@ mod tests { 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":null,"blockNumber":null,"transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}]"#); + assert_eq!(serialized, r#"[{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"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(); diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 147e6d2a7..e45fe033b 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -27,7 +27,7 @@ pub struct Transaction { #[serde(rename="blockNumber")] pub block_number: OptionalValue, #[serde(rename="transactionIndex")] - pub transaction_index: U256, + pub transaction_index: OptionalValue, pub from: Address, pub to: OptionalValue
, pub value: U256, @@ -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":null,"blockNumber":null,"transactionIndex":"0x00","from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}"#); + assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x00","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x00","gasPrice":"0x00","gas":"0x00","input":"0x00"}"#); } } From abcfe9f9e8f91aae3ae0527bd21473bfaae409c1 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 16:38:21 +0100 Subject: [PATCH 03/15] eth_getBlock properly returns transactions --- rpc/src/v1/impls/eth.rs | 27 ++++++--------------------- rpc/src/v1/types/transaction.rs | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index ef5f5b732..63783df34 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -22,7 +22,6 @@ 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, Transaction, OptionalValue}; @@ -126,9 +125,10 @@ impl Eth for EthClient { fn block(&self, params: Params) -> Result { match from_params::<(H256, bool)>(params) { - Ok((hash, include_txs)) => match (self.client.block_header(&hash), self.client.block_total_difficulty(&hash)) { + Ok((hash, include_txs)) => match (self.client.block(&hash), self.client.block_total_difficulty(&hash)) { (Some(bytes), Some(total_difficulty)) => { - let view = HeaderView::new(&bytes); + let block_view = BlockView::new(&bytes); + let view = block_view.header_view(); let block = Block { hash: OptionalValue::Value(view.sha3()), parent_hash: view.parent_hash(), @@ -148,9 +148,9 @@ impl Eth for EthClient { uncles: vec![], transactions: { if include_txs { - BlockTransactions::Hashes(vec![]) + BlockTransactions::Full(block_view.localized_transactions().into_iter().map(From::from).collect()) } else { - BlockTransactions::Full(vec![]) + BlockTransactions::Hashes(block_view.transaction_hashes()) } }, extra_data: Bytes::default() @@ -166,22 +166,7 @@ impl Eth for EthClient { fn transaction_at(&self, params: Params) -> Result { match from_params::<(H256,)>(params) { Ok((hash,)) => match self.client.transaction(&hash) { - Some(t) => to_value(&Transaction { - hash: t.hash(), - nonce: t.nonce, - block_hash: OptionalValue::Value(t.block_hash.clone()), - block_number: OptionalValue::Value(U256::from(t.block_number)), - transaction_index: OptionalValue::Value(U256::from(t.transaction_index)), - 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()) - }), + Some(t) => to_value(&Transaction::from(t)), None => Ok(Value::Null) }, Err(err) => Err(err) diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index e45fe033b..0e9256ada 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -16,6 +16,7 @@ use util::hash::*; use util::uint::*; +use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; #[derive(Debug, Default, Serialize)] @@ -37,6 +38,27 @@ pub struct Transaction { pub input: Bytes } +impl From for Transaction { + fn from(t: LocalizedTransaction) -> Transaction { + Transaction { + hash: t.hash(), + nonce: t.nonce, + block_hash: OptionalValue::Value(t.block_hash.clone()), + block_number: OptionalValue::Value(U256::from(t.block_number)), + transaction_index: OptionalValue::Value(U256::from(t.transaction_index)), + 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()) + } + } +} + #[cfg(test)] mod tests { use super::*; From 1f69b60041c97432d0f4bff95705df439c68e513 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 17:37:16 +0100 Subject: [PATCH 04/15] filter deserialization --- rpc/src/v1/types/filter.rs | 75 ++++++++++++++++++++++++++++++++++++++ rpc/src/v1/types/mod.rs | 2 + 2 files changed, 77 insertions(+) create mode 100644 rpc/src/v1/types/filter.rs diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs new file mode 100644 index 000000000..ef2d8b29e --- /dev/null +++ b/rpc/src/v1/types/filter.rs @@ -0,0 +1,75 @@ +// 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::{Deserialize, Deserializer, Error}; +use serde_json::value; +use jsonrpc_core::Value; +use util::hash::*; +use v1::types::BlockNumber; + +#[derive(Debug, PartialEq)] +pub enum Topic { + Single(H256), + Multiple(Vec), + Null +} + +impl Deserialize for Topic { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + let v = try!(Value::deserialize(deserializer)); + + if v.is_null() { + return Ok(Topic::Null); + } + + Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Topic::Single) + .or_else(|_| Deserialize::deserialize(&mut value::Deserializer::new(v.clone())).map(Topic::Multiple)) + .map_err(|_| Error::syntax("")) // unreachable, but types must match + } +} + +#[derive(Debug, Deserialize)] +pub struct Filter { + #[serde(rename="fromBlock")] + pub from_block: BlockNumber, + #[serde(rename="toBlock")] + pub to_block: BlockNumber, + pub address: Address, + pub topics: Vec +} + +#[cfg(test)] +mod tests { + use serde_json; + use std::str::FromStr; + use util::hash::*; + use super::*; + + #[test] + fn filter_deserialization() { + let s = r#"["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"]]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![ + Topic::Single(H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap()), + Topic::Null, + Topic::Multiple(vec![ + H256::from_str("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap(), + H256::from_str("0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc").unwrap() + ]) + ]); + } +} diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index 9dc57f24f..b35e7ff15 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -17,6 +17,7 @@ mod block; mod block_number; mod bytes; +mod filter; mod optionals; mod sync; mod transaction; @@ -24,6 +25,7 @@ mod transaction; pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; pub use self::bytes::Bytes; +pub use self::filter::Filter; pub use self::optionals::OptionalValue; pub use self::sync::SyncStatus; pub use self::transaction::Transaction; From b12d0f690d2020a88e41415e7c5f9866f9f7d33a Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 17:45:39 +0100 Subject: [PATCH 05/15] fixed filter deserialization --- rpc/src/v1/types/filter.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/rpc/src/v1/types/filter.rs b/rpc/src/v1/types/filter.rs index ef2d8b29e..9b21cf8e7 100644 --- a/rpc/src/v1/types/filter.rs +++ b/rpc/src/v1/types/filter.rs @@ -42,14 +42,14 @@ impl Deserialize for Topic { } } -#[derive(Debug, Deserialize)] +#[derive(Debug, PartialEq, Deserialize)] pub struct Filter { #[serde(rename="fromBlock")] - pub from_block: BlockNumber, + pub from_block: Option, #[serde(rename="toBlock")] - pub to_block: BlockNumber, - pub address: Address, - pub topics: Vec + pub to_block: Option, + pub address: Option
, + pub topics: Option> } #[cfg(test)] @@ -58,9 +58,10 @@ mod tests { use std::str::FromStr; use util::hash::*; use super::*; + use v1::types::BlockNumber; #[test] - fn filter_deserialization() { + fn topic_deserialization() { let s = r#"["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null, ["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", "0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc"]]"#; let deserialized: Vec = serde_json::from_str(s).unwrap(); assert_eq!(deserialized, vec![ @@ -72,4 +73,16 @@ mod tests { ]) ]); } + + #[test] + fn filter_deserialization() { + let s = r#"{"fromBlock":"earliest","toBlock":"latest"}"#; + let deserialized: Filter = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, Filter { + from_block: Some(BlockNumber::Earliest), + to_block: Some(BlockNumber::Latest), + address: None, + topics: None + }); + } } From 75ccb22d2625c1a828b15f0f1347735e67a1d2c4 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 18:14:04 +0100 Subject: [PATCH 06/15] add Debug, PartialEq and Eq to LocalizedTransaction --- ethcore/src/transaction.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index 2713290bb..b43c271d3 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -291,6 +291,7 @@ impl SignedTransaction { } /// Signed Transaction that is a part of canon blockchain. +#[derive(Debug, PartialEq, Eq)] pub struct LocalizedTransaction { /// Signed part. pub signed: SignedTransaction, From 27acdf38e201fc434ca4011e8a3bd0e44a34bd95 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 9 Feb 2016 18:34:06 +0100 Subject: [PATCH 07/15] fixed ethsync tests --- sync/src/tests/helpers.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 7cb1b3c53..0b2d5ea18 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -22,6 +22,7 @@ use ethcore::error::*; use io::SyncIo; use chain::{ChainSync}; use ethcore::receipt::Receipt; +use ethcore::transaction::LocalizedTransaction; pub struct TestBlockChainClient { pub blocks: RwLock>, @@ -86,6 +87,10 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } + fn transaction(&self, hash: &H256) -> Option { + unimplemented!(); + } + fn block_header(&self, h: &H256) -> Option { self.blocks.read().unwrap().get(h).map(|r| Rlp::new(r).at(0).as_raw().to_vec()) } From 4df096fed3d68e0f44283e30352d5c543ddf95be Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 10 Feb 2016 00:12:09 +0100 Subject: [PATCH 08/15] optimize blockchains transaction_at --- ethcore/src/blockchain.rs | 2 +- ethcore/src/views.rs | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index af7800870..c88a375a8 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -117,7 +117,7 @@ pub trait BlockProvider { /// Get transaction at given address. fn transaction_at(&self, address: &TransactionAddress) -> Option { - self.block(&address.block_hash).map(|bytes| BlockView::new(&bytes).localized_transactions()).and_then(|t| t.into_iter().nth(address.index)) + self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index)) } /// Get a list of transactions for a given block. diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index 3cfe5f183..4a7ff054d 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -160,7 +160,7 @@ impl<'a> BlockView<'a> { let header = self.header_view(); let block_hash = header.sha3(); let block_number = header.number(); - self.rlp.val_at::>(1) + self.transactions() .into_iter() .enumerate() .map(|(i, t)| LocalizedTransaction { @@ -186,6 +186,24 @@ impl<'a> BlockView<'a> { self.rlp.at(1).iter().map(|rlp| rlp.as_raw().sha3()).collect() } + /// Returns transaction at given index without deserializing unnecessary data. + pub fn transaction_at(&self, index: usize) -> Option { + self.rlp.at(1).iter().nth(index).map(|rlp| rlp.as_val()) + } + + /// Returns localized transaction at given index. + pub fn localized_transaction_at(&self, index: usize) -> Option { + let header = self.header_view(); + let block_hash = header.sha3(); + let block_number = header.number(); + self.transaction_at(index).map(|t| LocalizedTransaction { + signed: t, + block_hash: block_hash, + block_number: block_number, + transaction_index: index + }) + } + /// Return list of uncles of given block. pub fn uncles(&self) -> Vec
{ self.rlp.val_at(2) From bceae29fcaf56a9f8ffd78c17dad5f9072f9d2e6 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 10 Feb 2016 10:12:56 +0100 Subject: [PATCH 09/15] small clenaup --- rpc/src/v1/impls/eth.rs | 40 +++++++++++++++------------------------- rpc/src/v1/traits/eth.rs | 16 +++++++++++----- 2 files changed, 26 insertions(+), 30 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 63783df34..afd6a1d1c 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -96,36 +96,30 @@ impl Eth for EthClient { } fn block_transaction_count(&self, params: Params) -> Result { - match from_params::<(H256,)>(params) { - Ok((hash,)) => match self.client.block(&hash) { + from_params::<(H256,)>(params) + .and_then(|(hash,)| match self.client.block(&hash) { Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), None => Ok(Value::Null) - }, - Err(err) => Err(err) - } + }) } fn block_uncles_count(&self, params: Params) -> Result { - match from_params::<(H256,)>(params) { - Ok((hash,)) => match self.client.block(&hash) { + from_params::<(H256,)>(params) + .and_then(|(hash,)| match self.client.block(&hash) { Some(bytes) => to_value(&BlockView::new(&bytes).uncles_count()), None => Ok(Value::Null) - }, - Err(err) => Err(err) - } + }) } // TODO: do not ignore block number param fn code_at(&self, params: Params) -> Result { - match from_params::<(Address, BlockNumber)>(params) { - Ok((address, _block_number)) => to_value(&self.client.code(&address).map_or_else(Bytes::default, Bytes::new)), - Err(err) => Err(err) - } + from_params::<(Address, BlockNumber)>(params) + .and_then(|(address, _block_number)| to_value(&self.client.code(&address).map_or_else(Bytes::default, Bytes::new))) } fn block(&self, params: Params) -> Result { - match from_params::<(H256, bool)>(params) { - Ok((hash, include_txs)) => match (self.client.block(&hash), self.client.block_total_difficulty(&hash)) { + from_params::<(H256, bool)>(params) + .and_then(|(hash, include_txs)| match (self.client.block(&hash), self.client.block_total_difficulty(&hash)) { (Some(bytes), Some(total_difficulty)) => { let block_view = BlockView::new(&bytes); let view = block_view.header_view(); @@ -158,19 +152,15 @@ impl Eth for EthClient { to_value(&block) }, _ => Ok(Value::Null) - }, - Err(err) => Err(err) - } + }) } - fn transaction_at(&self, params: Params) -> Result { - match from_params::<(H256,)>(params) { - Ok((hash,)) => match self.client.transaction(&hash) { + fn transaction_by_hash(&self, params: Params) -> Result { + from_params::<(H256,)>(params) + .and_then(|(hash,)| match self.client.transaction(&hash) { Some(t) => to_value(&Transaction::from(t)), None => Ok(Value::Null) - }, - Err(err) => Err(err) - } + }) } } diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index b0b9a3cf4..640af1f82 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -74,8 +74,14 @@ pub trait Eth: Sized + Send + Sync + 'static { /// Estimate gas needed for execution of given contract. fn estimate_gas(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Returns transaction at given block and index. - fn transaction_at(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Get transaction by it's hash. + fn transaction_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Returns transaction at given block hash and index. + fn transaction_by_block_hash_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Returns transaction by given block number and index. + fn transaction_by_block_number_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } /// Returns transaction receipt. fn transaction_receipt(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -131,9 +137,9 @@ 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_getTransactionByHash", Eth::transaction_by_hash); + delegate.add_method("eth_getTransactionByBlockHashAndIndex", Eth::transaction_by_block_hash_and_index); + delegate.add_method("eth_getTransactionByBlockNumberAndIndex", Eth::transaction_by_block_number_and_index); delegate.add_method("eth_getTransactionReceipt", Eth::transaction_receipt); delegate.add_method("eth_getUncleByBlockHashAndIndex", Eth::uncle_at); delegate.add_method("eth_getUncleByBlockNumberAndIndex", Eth::uncle_at); From 626277ef9aa3deb47e35530f7625c6a440d93263 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 10 Feb 2016 11:28:40 +0100 Subject: [PATCH 10/15] block and transaction ids, jsonrpcs eth_getTransactionByHash --- ethcore/src/blockchain.rs | 24 ++++++++------ ethcore/src/client.rs | 8 ++--- ethcore/src/views.rs | 16 ++++++++++ rpc/src/v1/impls/eth.rs | 20 +++++++++--- rpc/src/v1/types/index.rs | 66 +++++++++++++++++++++++++++++++++++++++ rpc/src/v1/types/mod.rs | 2 ++ 6 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 rpc/src/v1/types/index.rs diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index c88a375a8..febadfc52 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -111,17 +111,22 @@ pub trait BlockProvider { } /// Get transaction with given transaction hash. - fn transaction(&self, hash: &H256) -> Option { - self.transaction_address(hash).and_then(|address| self.transaction_at(&address)) - } - - /// Get transaction at given address. - fn transaction_at(&self, address: &TransactionAddress) -> Option { - self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index)) + fn transaction(&self, id: TransactionId) -> Option { + match id { + TransactionId::Hash(ref hash) => self.transaction_address(hash), + TransactionId::BlockPosition(BlockId::Hash(hash), index) => Some(TransactionAddress { + block_hash: hash, + index: index + }), + TransactionId::BlockPosition(BlockId::Number(number), index) => self.block_hash(number).map(|hash| TransactionAddress { + block_hash: hash, + index: index + }) + }.and_then(|address| self.block(&address.block_hash).and_then(|bytes| BlockView::new(&bytes).localized_transaction_at(address.index))) } /// Get a list of transactions for a given block. - /// Returns None if block deos not exist. + /// Returns None if block does not exist. fn transactions(&self, hash: &H256) -> Option> { self.block(hash).map(|bytes| BlockView::new(&bytes).localized_transactions()) } @@ -669,6 +674,7 @@ mod tests { use util::hash::*; use blockchain::*; use tests::helpers::*; + use views::TransactionId; #[test] fn valid_tests_extra32() { @@ -864,7 +870,7 @@ mod tests { let transactions = bc.transactions(&b1_hash).unwrap(); assert_eq!(transactions.len(), 7); for t in transactions { - assert_eq!(bc.transaction(&t.hash()).unwrap(), t); + assert_eq!(bc.transaction(TransactionId::Hash(t.hash())).unwrap(), t); } } } diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 002f5bffe..93038af48 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -19,7 +19,7 @@ use util::*; use rocksdb::{Options, DB, DBCompactionStyle}; use blockchain::{BlockChain, BlockProvider, CacheSize}; -use views::BlockView; +use views::{BlockView, TransactionId}; use error::*; use header::BlockNumber; use state::State; @@ -106,7 +106,7 @@ pub trait BlockChainClient : Sync + Send { fn block_total_difficulty_at(&self, n: BlockNumber) -> Option; /// Get transaction with given hash. - fn transaction(&self, hash: &H256) -> Option; + fn transaction(&self, id: TransactionId) -> Option; /// Get a tree route between `from` and `to`. /// See `BlockChain::tree_route`. @@ -392,8 +392,8 @@ 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 transaction(&self, id: TransactionId) -> Option { + self.chain.read().unwrap().transaction(id) } fn tree_route(&self, from: &H256, to: &H256) -> Option { diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index 4a7ff054d..624d9bb96 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -19,6 +19,22 @@ use util::*; use header::*; use transaction::*; +/// Uniqly identifies block in canon blockchain. +pub enum BlockId { + /// Block's sha3. + Hash(H256), + /// Block number. + Number(BlockNumber) +} + +/// Uniqly identifies transaction in canon blockchain. +pub enum TransactionId { + /// Transaction's sha3. + Hash(H256), + /// Block id and transaction index within this block. + BlockPosition(BlockId, usize) +} + /// View onto transaction rlp. pub struct TransactionView<'a> { rlp: Rlp<'a> diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index afd6a1d1c..c21157599 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -23,7 +23,7 @@ use util::sha3::*; use ethcore::client::*; use ethcore::views::*; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, Transaction, OptionalValue}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, Transaction, OptionalValue, Index}; /// Eth rpc implementation. pub struct EthClient { @@ -152,15 +152,27 @@ impl Eth for EthClient { to_value(&block) }, _ => Ok(Value::Null) - }) + }) } fn transaction_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) - .and_then(|(hash,)| match self.client.transaction(&hash) { + .and_then(|(hash,)| match self.client.transaction(TransactionId::Hash(hash)) { Some(t) => to_value(&Transaction::from(t)), None => Ok(Value::Null) - }) + }) + } + + fn transaction_by_block_hash_and_index(&self, params: Params) -> Result { + from_params::<(H256, Index)>(params) + .and_then(|(hash, index)| match self.client.transaction(TransactionId::BlockPosition(BlockId::Hash(hash), index.value())) { + Some(t) => to_value(&Transaction::from(t)), + None => Ok(Value::Null) + }) + } + + fn transaction_by_block_number_and_index(&self, _params: Params) -> Result { + unimplemented!() } } diff --git a/rpc/src/v1/types/index.rs b/rpc/src/v1/types/index.rs new file mode 100644 index 000000000..a77096fbf --- /dev/null +++ b/rpc/src/v1/types/index.rs @@ -0,0 +1,66 @@ +// 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::{Deserialize, Deserializer, Error}; +use serde::de::Visitor; + +/// Represents usize. +#[derive(Debug, PartialEq)] +pub struct Index(usize); + +impl Index { + pub fn value(&self) -> usize { + self.0 + } +} + +impl Deserialize for Index { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.visit(IndexVisitor) + } +} + +struct IndexVisitor; + +impl Visitor for IndexVisitor { + type Value = Index; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + match value { + _ if value.starts_with("0x") => usize::from_str_radix(&value[2..], 16).map(Index).map_err(|_| Error::syntax("invalid index")), + _ => value.parse::().map(Index).map_err(|_| Error::syntax("invalid index")) + } + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + + #[test] + fn block_number_deserialization() { + let s = r#"["0xa", "10"]"#; + let deserialized: Vec = serde_json::from_str(s).unwrap(); + assert_eq!(deserialized, vec![Index(10), Index(10)]); + } +} + diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index b35e7ff15..bdbd157ff 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -18,6 +18,7 @@ mod block; mod block_number; mod bytes; mod filter; +mod index; mod optionals; mod sync; mod transaction; @@ -26,6 +27,7 @@ pub use self::block::{Block, BlockTransactions}; pub use self::block_number::BlockNumber; pub use self::bytes::Bytes; pub use self::filter::Filter; +pub use self::index::Index; pub use self::optionals::OptionalValue; pub use self::sync::SyncStatus; pub use self::transaction::Transaction; From 7491815e27dd75f003f9123763783eaf2d667902 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 10 Feb 2016 11:44:03 +0100 Subject: [PATCH 11/15] fixed ethsync tests --- sync/src/tests/helpers.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index 0b2d5ea18..d392fc653 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -23,6 +23,7 @@ use io::SyncIo; use chain::{ChainSync}; use ethcore::receipt::Receipt; use ethcore::transaction::LocalizedTransaction; +use ethcore::views::TransactionId; pub struct TestBlockChainClient { pub blocks: RwLock>, @@ -87,7 +88,7 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn transaction(&self, hash: &H256) -> Option { + fn transaction(&self, _id: TransactionId) -> Option { unimplemented!(); } From 8c43c989af59e44afdc366da05acad44f9b67d0f Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 10 Feb 2016 12:41:36 +0100 Subject: [PATCH 12/15] fixed Uniquely typo --- ethcore/src/views.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index 624d9bb96..6d4371c8b 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -19,7 +19,7 @@ use util::*; use header::*; use transaction::*; -/// Uniqly identifies block in canon blockchain. +/// Uniquely identifies block in canon blockchain. pub enum BlockId { /// Block's sha3. Hash(H256), @@ -27,7 +27,7 @@ pub enum BlockId { Number(BlockNumber) } -/// Uniqly identifies transaction in canon blockchain. +/// Uniquely identifies transaction in canon blockchain. pub enum TransactionId { /// Transaction's sha3. Hash(H256), From 75b54cc27736ce954f5d4a0dc4e12c2687802f11 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 10 Feb 2016 12:43:26 +0100 Subject: [PATCH 13/15] updated BlockId and TransactionId description --- ethcore/src/views.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index 6d4371c8b..a49c06708 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -19,15 +19,15 @@ use util::*; use header::*; use transaction::*; -/// Uniquely identifies block in canon blockchain. +/// Uniquely identifies block. pub enum BlockId { /// Block's sha3. Hash(H256), - /// Block number. + /// Block number within canon blockchain. Number(BlockNumber) } -/// Uniquely identifies transaction in canon blockchain. +/// Uniquely identifies transaction. pub enum TransactionId { /// Transaction's sha3. Hash(H256), From dc8fa4ebfdf8ae7de4124c895b8fe058a7fda88e Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 10 Feb 2016 15:06:13 +0100 Subject: [PATCH 14/15] moved BlockId and TransactionId to blockchain.rs --- ethcore/src/blockchain.rs | 19 ++++++++++++++++++- ethcore/src/client.rs | 4 ++-- ethcore/src/views.rs | 16 ---------------- rpc/src/v1/impls/eth.rs | 1 + sync/src/tests/helpers.rs | 2 +- 5 files changed, 22 insertions(+), 20 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index febadfc52..f7c45d94e 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -23,6 +23,24 @@ use extras::*; use transaction::*; use views::*; +/// Uniquely identifies block. +pub enum BlockId { + /// Block's sha3. + /// Querying by hash is always faster. + Hash(H256), + /// Block number within canon blockchain. + Number(BlockNumber) +} + +/// Uniquely identifies transaction. +pub enum TransactionId { + /// Transaction's sha3. + Hash(H256), + /// Block id and transaction index within this block. + /// Querying by block position is always faster. + BlockPosition(BlockId, usize) +} + /// Represents a tree route between `from` block and `to` block: pub struct TreeRoute { /// A vector of hashes of all blocks, ordered from `from` to `to`. @@ -674,7 +692,6 @@ mod tests { use util::hash::*; use blockchain::*; use tests::helpers::*; - use views::TransactionId; #[test] fn valid_tests_extra32() { diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 93038af48..3de5c097e 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -18,8 +18,8 @@ use util::*; use rocksdb::{Options, DB, DBCompactionStyle}; -use blockchain::{BlockChain, BlockProvider, CacheSize}; -use views::{BlockView, TransactionId}; +use blockchain::{BlockChain, BlockProvider, CacheSize, TransactionId}; +use views::BlockView; use error::*; use header::BlockNumber; use state::State; diff --git a/ethcore/src/views.rs b/ethcore/src/views.rs index a49c06708..4a7ff054d 100644 --- a/ethcore/src/views.rs +++ b/ethcore/src/views.rs @@ -19,22 +19,6 @@ use util::*; use header::*; use transaction::*; -/// Uniquely identifies block. -pub enum BlockId { - /// Block's sha3. - Hash(H256), - /// Block number within canon blockchain. - Number(BlockNumber) -} - -/// Uniquely identifies transaction. -pub enum TransactionId { - /// Transaction's sha3. - Hash(H256), - /// Block id and transaction index within this block. - BlockPosition(BlockId, usize) -} - /// View onto transaction rlp. pub struct TransactionView<'a> { rlp: Rlp<'a> diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index c21157599..32c1919bf 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -22,6 +22,7 @@ use util::uint::*; use util::sha3::*; use ethcore::client::*; use ethcore::views::*; +use ethcore::blockchain::{BlockId, TransactionId}; use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, Transaction, OptionalValue, Index}; diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index d392fc653..f8c08dc93 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -23,7 +23,7 @@ use io::SyncIo; use chain::{ChainSync}; use ethcore::receipt::Receipt; use ethcore::transaction::LocalizedTransaction; -use ethcore::views::TransactionId; +use ethcore::blockchain::TransactionId; pub struct TestBlockChainClient { pub blocks: RwLock>, From 5347d4fe430031f7b82194845fe6b41e069d2f1f Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 10 Feb 2016 15:15:28 +0100 Subject: [PATCH 15/15] changed BlockPosition -> Location --- ethcore/src/blockchain.rs | 6 +++--- rpc/src/v1/impls/eth.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index f7c45d94e..764b76588 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -38,7 +38,7 @@ pub enum TransactionId { Hash(H256), /// Block id and transaction index within this block. /// Querying by block position is always faster. - BlockPosition(BlockId, usize) + Location(BlockId, usize) } /// Represents a tree route between `from` block and `to` block: @@ -132,11 +132,11 @@ pub trait BlockProvider { fn transaction(&self, id: TransactionId) -> Option { match id { TransactionId::Hash(ref hash) => self.transaction_address(hash), - TransactionId::BlockPosition(BlockId::Hash(hash), index) => Some(TransactionAddress { + TransactionId::Location(BlockId::Hash(hash), index) => Some(TransactionAddress { block_hash: hash, index: index }), - TransactionId::BlockPosition(BlockId::Number(number), index) => self.block_hash(number).map(|hash| TransactionAddress { + TransactionId::Location(BlockId::Number(number), index) => self.block_hash(number).map(|hash| TransactionAddress { block_hash: hash, index: index }) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 32c1919bf..5d60b40a6 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -166,7 +166,7 @@ impl Eth for EthClient { fn transaction_by_block_hash_and_index(&self, params: Params) -> Result { from_params::<(H256, Index)>(params) - .and_then(|(hash, index)| match self.client.transaction(TransactionId::BlockPosition(BlockId::Hash(hash), index.value())) { + .and_then(|(hash, index)| match self.client.transaction(TransactionId::Location(BlockId::Hash(hash), index.value())) { Some(t) => to_value(&Transaction::from(t)), None => Ok(Value::Null) })