diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index b2254e285..61e3b4cd8 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -21,7 +21,7 @@ use util::*; use util::panics::*; use views::BlockView; use error::*; -use header::{BlockNumber}; +use header::{BlockNumber, Header}; use state::State; use spec::Spec; use engine::Engine; @@ -36,7 +36,7 @@ use filter::Filter; use log_entry::LocalizedLogEntry; use block_queue::{BlockQueue, BlockQueueInfo}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; -use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; +use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient}; use env_info::EnvInfo; use executive::{Executive, Executed}; use receipt::LocalizedReceipt; @@ -549,6 +549,11 @@ impl BlockChainClient for Client where V: Verifier { self.transaction_address(id).and_then(|address| self.chain.transaction(&address)) } + fn uncle(&self, id: UncleId) -> Option
{ + let index = id.1; + self.block(id.0).and_then(|block| BlockView::new(&block).uncle_at(index)) + } + fn transaction_receipt(&self, id: TransactionId) -> Option { self.transaction_address(id).and_then(|address| { let t = self.chain.block(&address.block_hash) diff --git a/ethcore/src/client/ids.rs b/ethcore/src/client/ids.rs index 303657a76..79302354f 100644 --- a/ethcore/src/client/ids.rs +++ b/ethcore/src/client/ids.rs @@ -20,7 +20,7 @@ use util::hash::H256; use header::BlockNumber; /// Uniquely identifies block. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Hash, Eq)] pub enum BlockId { /// Block's sha3. /// Querying by hash is always faster. @@ -34,7 +34,7 @@ pub enum BlockId { } /// Uniquely identifies transaction. -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Hash, Eq)] pub enum TransactionId { /// Transaction's sha3. Hash(H256), @@ -42,3 +42,11 @@ pub enum TransactionId { /// Querying by block position is always faster. Location(BlockId, usize) } + +/// Uniquely identifies Uncle. +pub struct UncleId ( + /// Block id. + pub BlockId, + /// Position in block. + pub usize +); diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 74b05652f..65733f3bf 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -23,7 +23,7 @@ mod test_client; pub use self::client::*; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig}; -pub use self::ids::{BlockId, TransactionId}; +pub use self::ids::{BlockId, TransactionId, UncleId}; pub use self::test_client::{TestBlockChainClient, EachBlockWith}; pub use executive::Executed; @@ -34,7 +34,7 @@ use util::numbers::U256; use blockchain::TreeRoute; use block_queue::BlockQueueInfo; use block::{ClosedBlock, SealedBlock}; -use header::BlockNumber; +use header::{BlockNumber, Header}; use transaction::{LocalizedTransaction, SignedTransaction}; use log_entry::LocalizedLogEntry; use filter::Filter; @@ -77,6 +77,9 @@ pub trait BlockChainClient : Sync + Send { /// Get transaction with given hash. fn transaction(&self, id: TransactionId) -> Option; + /// Get uncle with given id. + fn uncle(&self, id: UncleId) -> Option
; + /// Get transaction receipt with given hash. fn transaction_receipt(&self, id: TransactionId) -> Option; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 48c16ac10..b2230af7b 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -19,7 +19,7 @@ use util::*; use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; use blockchain::TreeRoute; -use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId}; +use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId}; use header::{Header as BlockHeader, BlockNumber}; use filter::Filter; use log_entry::LocalizedLogEntry; @@ -52,6 +52,8 @@ pub struct TestBlockChainClient { pub code: RwLock>, /// Execution result. pub execution_result: RwLock>, + /// Transaction receipts. + pub receipts: RwLock>, } #[derive(Clone)] @@ -87,12 +89,18 @@ impl TestBlockChainClient { storage: RwLock::new(HashMap::new()), code: RwLock::new(HashMap::new()), execution_result: RwLock::new(None), + receipts: RwLock::new(HashMap::new()), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); client } + /// Set the transaction receipt result + pub fn set_transaction_receipt(&self, id: TransactionId, receipt: LocalizedReceipt) { + self.receipts.write().unwrap().insert(id, receipt); + } + /// Set the execution result. pub fn set_execution_result(&self, result: Executed) { *self.execution_result.write().unwrap() = Some(result); @@ -224,10 +232,14 @@ impl BlockChainClient for TestBlockChainClient { unimplemented!(); } - fn transaction_receipt(&self, _id: TransactionId) -> Option { + fn uncle(&self, _id: UncleId) -> Option { unimplemented!(); } + fn transaction_receipt(&self, id: TransactionId) -> Option { + self.receipts.read().unwrap().get(&id).cloned() + } + fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { unimplemented!(); } diff --git a/ethcore/src/log_entry.rs b/ethcore/src/log_entry.rs index cf74a6df9..63e07730e 100644 --- a/ethcore/src/log_entry.rs +++ b/ethcore/src/log_entry.rs @@ -78,7 +78,7 @@ impl FromJson for LogEntry { } /// Log localized in a blockchain. -#[derive(Default, Debug, PartialEq)] +#[derive(Default, Debug, PartialEq, Clone)] pub struct LocalizedLogEntry { /// Plain log entry. pub entry: LogEntry, diff --git a/ethcore/src/receipt.rs b/ethcore/src/receipt.rs index 7f0b0d8dd..2fbd3f14c 100644 --- a/ethcore/src/receipt.rs +++ b/ethcore/src/receipt.rs @@ -76,6 +76,7 @@ impl HeapSizeOf for Receipt { } /// Receipt with additional info. +#[derive(Debug, Clone, PartialEq)] pub struct LocalizedReceipt { /// Transaction hash. pub transaction_hash: H256, diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index d7ee478bf..963afbecb 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -23,18 +23,27 @@ use ethminer::{MinerService, AccountDetails}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; -use util::rlp::encode; +use util::rlp::{encode, UntrustedRlp, View}; +use util::crypto::KeyPair; use ethcore::client::*; use ethcore::block::IsBlock; use ethcore::views::*; use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; -use ethcore::transaction::Transaction as EthTransaction; +use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action}; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log, Receipt}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt}; use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner}; use util::keys::store::AccountProvider; +fn default_gas() -> U256 { + U256::from(21_000) +} + +fn default_gas_price() -> U256 { + shannon() * U256::from(50) +} + /// Eth rpc implementation. pub struct EthClient where C: BlockChainClient, @@ -61,7 +70,6 @@ impl EthClient } } - impl EthClient where C: BlockChainClient, S: SyncProvider, @@ -127,9 +135,65 @@ impl EthClient } } - fn uncle(&self, _block: BlockId, _index: usize) -> Result { - // TODO: implement! - Ok(Value::Null) + fn uncle(&self, id: UncleId) -> Result { + let client = take_weak!(self.client); + match client.uncle(id).and_then(|u| client.block_total_difficulty(BlockId::Hash(u.hash())).map(|diff| (diff, u))) { + Some((difficulty, uncle)) => { + let block = Block { + hash: OptionalValue::Value(uncle.hash()), + parent_hash: uncle.parent_hash, + uncles_hash: uncle.uncles_hash, + author: uncle.author, + miner: uncle.author, + state_root: uncle.state_root, + transactions_root: uncle.transactions_root, + number: OptionalValue::Value(U256::from(uncle.number)), + gas_used: uncle.gas_used, + gas_limit: uncle.gas_limit, + logs_bloom: uncle.log_bloom, + timestamp: U256::from(uncle.timestamp), + difficulty: uncle.difficulty, + total_difficulty: difficulty, + receipts_root: uncle.receipts_root, + extra_data: Bytes::new(uncle.extra_data), + // todo: + nonce: H64::from(0), + uncles: vec![], + transactions: BlockTransactions::Hashes(vec![]), + }; + to_value(&block) + }, + None => Ok(Value::Null) + } + } + + fn sign_call(client: &Arc, accounts: &Arc, request: CallRequest) -> Option { + match request.from { + Some(ref from) => { + let transaction = EthTransaction { + nonce: request.nonce.unwrap_or_else(|| client.nonce(from)), + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(default_gas), + gas_price: request.gas_price.unwrap_or_else(default_gas_price), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |d| d.to_vec()) + }; + + accounts.account_secret(from).ok().map(|secret| transaction.sign(&secret)) + }, + None => { + let transaction = EthTransaction { + nonce: request.nonce.unwrap_or_else(U256::zero), + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(default_gas), + gas_price: request.gas_price.unwrap_or_else(default_gas_price), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |d| d.to_vec()) + }; + + KeyPair::create().ok().map(|kp| transaction.sign(kp.secret())) + } + } } } @@ -191,7 +255,7 @@ impl Eth for EthClient fn gas_price(&self, params: Params) -> Result { match params { - Params::None => to_value(&(shannon() * U256::from(50))), + Params::None => to_value(&default_gas_price()), _ => Err(Error::invalid_params()) } } @@ -304,12 +368,12 @@ impl Eth for EthClient fn uncle_by_block_hash_and_index(&self, params: Params) -> Result { from_params::<(H256, Index)>(params) - .and_then(|(hash, index)| self.uncle(BlockId::Hash(hash), index.value())) + .and_then(|(hash, index)| self.uncle(UncleId(BlockId::Hash(hash), index.value()))) } fn uncle_by_block_number_and_index(&self, params: Params) -> Result { from_params::<(BlockNumber, Index)>(params) - .and_then(|(number, index)| self.uncle(number.into(), index.value())) + .and_then(|(number, index)| self.uncle(UncleId(number.into(), index.value()))) } fn compilers(&self, params: Params) -> Result { @@ -371,7 +435,6 @@ impl Eth for EthClient } fn submit_hashrate(&self, params: Params) -> Result { - // TODO: Index should be U256. from_params::<(U256, H256)>(params).and_then(|(rate, id)| { self.external_miner.submit_hashrate(rate, id); to_value(&true) @@ -380,14 +443,22 @@ impl Eth for EthClient fn send_transaction(&self, params: Params) -> Result { from_params::<(TransactionRequest, )>(params) - .and_then(|(transaction_request, )| { + .and_then(|(request, )| { let accounts = take_weak!(self.accounts); - match accounts.account_secret(&transaction_request.from) { + match accounts.account_secret(&request.from) { Ok(secret) => { let miner = take_weak!(self.miner); let client = take_weak!(self.client); - let transaction: EthTransaction = transaction_request.into(); + let transaction = EthTransaction { + nonce: request.nonce.unwrap_or_else(|| client.nonce(&request.from)), + action: request.to.map_or(Action::Create, Action::Call), + gas: request.gas.unwrap_or_else(default_gas), + gas_price: request.gas_price.unwrap_or_else(default_gas_price), + value: request.value.unwrap_or_else(U256::zero), + data: request.data.map_or_else(Vec::new, |d| d.to_vec()) + }; + let signed_transaction = transaction.sign(&secret); let hash = signed_transaction.hash(); @@ -408,47 +479,58 @@ impl Eth for EthClient }) } - fn call(&self, params: Params) -> Result { - from_params::<(TransactionRequest, BlockNumber)>(params) - .and_then(|(transaction_request, _block_number)| { - let accounts = take_weak!(self.accounts); - match accounts.account_secret(&transaction_request.from) { - Ok(secret) => { + fn send_raw_transaction(&self, params: Params) -> Result { + from_params::<(Bytes, )>(params) + .and_then(|(raw_transaction, )| { + let decoded: Result = UntrustedRlp::new(&raw_transaction.to_vec()).as_val(); + match decoded { + Ok(signed_tx) => { + let miner = take_weak!(self.miner); let client = take_weak!(self.client); - let transaction: EthTransaction = transaction_request.into(); - let signed_transaction = transaction.sign(&secret); - - let output = client.call(&signed_transaction) - .map(|e| Bytes::new(e.output)) - .unwrap_or(Bytes::default()); - - to_value(&output) + let hash = signed_tx.hash(); + let import = miner.import_transactions(vec![signed_tx], |a: &Address| AccountDetails { + nonce: client.nonce(a), + balance: client.balance(a), + }); + match import.into_iter().collect::, _>>() { + Ok(_) => to_value(&hash), + Err(e) => { + warn!("Error sending transaction: {:?}", e); + to_value(&U256::zero()) + } + } }, - Err(_) => { to_value(&Bytes::default()) } + Err(_) => { to_value(&U256::zero()) } } + }) + } + + fn call(&self, params: Params) -> Result { + from_params::<(CallRequest, BlockNumber)>(params) + .and_then(|(request, _block_number)| { + let client = take_weak!(self.client); + let accounts = take_weak!(self.accounts); + let signed = Self::sign_call(&client, &accounts, request); + let output = signed.map(|tx| client.call(&tx) + .map(|e| Bytes::new(e.output)) + .unwrap_or(Bytes::default())); + + to_value(&output) }) } fn estimate_gas(&self, params: Params) -> Result { - from_params::<(TransactionRequest, BlockNumber)>(params) - .and_then(|(transaction_request, _block_number)| { + from_params::<(CallRequest, BlockNumber)>(params) + .and_then(|(request, _block_number)| { + let client = take_weak!(self.client); let accounts = take_weak!(self.accounts); - match accounts.account_secret(&transaction_request.from) { - Ok(secret) => { - let client = take_weak!(self.client); + let signed = Self::sign_call(&client, &accounts, request); + let output = signed.map(|tx| client.call(&tx) + .map(|e| e.gas_used + e.refunded) + .unwrap_or(U256::zero())); - let transaction: EthTransaction = transaction_request.into(); - let signed_transaction = transaction.sign(&secret); - - let gas_used = client.call(&signed_transaction) - .map(|e| e.gas_used + e.refunded) - .unwrap_or(U256::zero()); - - to_value(&gas_used) - }, - Err(_) => { to_value(&U256::zero()) } - } + to_value(&output) }) } } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 72235b390..4564076eb 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -14,12 +14,15 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use std::str::FromStr; use std::collections::HashMap; use std::sync::{Arc, RwLock}; use jsonrpc_core::IoHandler; -use util::hash::{Address, H256}; +use util::hash::{Address, H256, FixedHash}; use util::numbers::{Uint, U256}; -use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed}; +use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionId}; +use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; +use ethcore::receipt::LocalizedReceipt; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner}; @@ -382,6 +385,63 @@ fn rpc_eth_sign() { unimplemented!() } +#[test] +fn rpc_eth_transaction_receipt() { + let receipt = LocalizedReceipt { + transaction_hash: H256::zero(), + transaction_index: 0, + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: 0x4510c, + cumulative_gas_used: U256::from(0x20), + gas_used: U256::from(0x10), + contract_address: None, + logs: vec![LocalizedLogEntry { + entry: LogEntry { + address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), + topics: vec![ + H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), + H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap() + ], + data: vec![], + }, + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: 0x4510c, + transaction_hash: H256::new(), + transaction_index: 0, + log_index: 1, + }] + }; + + let hash = H256::from_str("b903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238").unwrap(); + let tester = EthTester::default(); + tester.client.set_transaction_receipt(TransactionId::Hash(hash), receipt); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":{"blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","contractAddress":null,"cumulativeGasUsed":"0x20","gasUsed":"0x10","logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","data":"0x","logIndex":"0x01","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00"}],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00"},"id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_eth_transaction_receipt_null() { + let tester = EthTester::default(); + + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": ["0xb903239f8543d04b5dc1ba6579132b143087c68db1b2168786408fcbce568238"], + "id": 1 + }"#; + let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#; + + assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); +} + #[test] fn rpc_eth_compilers() { let request = r#"{"jsonrpc": "2.0", "method": "eth_getCompilers", "params": [], "id": 1}"#; diff --git a/rpc/src/v1/types/call_request.rs b/rpc/src/v1/types/call_request.rs new file mode 100644 index 000000000..a47d40eb3 --- /dev/null +++ b/rpc/src/v1/types/call_request.rs @@ -0,0 +1,106 @@ +// 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 util::hash::Address; +use util::numbers::U256; +use v1::types::Bytes; + +#[derive(Debug, Default, PartialEq, Deserialize)] +pub struct CallRequest { + pub from: Option
, + pub to: Option
, + #[serde(rename="gasPrice")] + pub gas_price: Option, + pub gas: Option, + pub value: Option, + pub data: Option, + pub nonce: Option, +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + use rustc_serialize::hex::FromHex; + use serde_json; + use util::numbers::{Uint, U256}; + use util::hash::Address; + use ethcore::transaction::{Transaction, Action}; + use v1::types::Bytes; + use super::*; + + #[test] + fn transaction_request_deserialize() { + let s = r#"{ + "from":"0x0000000000000000000000000000000000000001", + "to":"0x0000000000000000000000000000000000000002", + "gasPrice":"0x1", + "gas":"0x2", + "value":"0x3", + "data":"0x123456", + "nonce":"0x4" + }"#; + let deserialized: CallRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, CallRequest { + from: Some(Address::from(1)), + to: Some(Address::from(2)), + gas_price: Some(U256::from(1)), + gas: Some(U256::from(2)), + value: Some(U256::from(3)), + data: Some(Bytes::new(vec![0x12, 0x34, 0x56])), + nonce: Some(U256::from(4)), + }); + } + + #[test] + fn transaction_request_deserialize2() { + let s = r#"{ + "from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a", + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + }"#; + let deserialized: CallRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, CallRequest { + from: Some(Address::from_str("b60e8dd61c5d32be8058bb8eb970870f07233155").unwrap()), + to: Some(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + gas_price: Some(U256::from_str("9184e72a000").unwrap()), + gas: Some(U256::from_str("76c0").unwrap()), + value: Some(U256::from_str("9184e72a").unwrap()), + data: Some(Bytes::new("d46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675".from_hex().unwrap())), + nonce: None + }); + } + + #[test] + fn transaction_request_deserialize_empty() { + let s = r#"{"from":"0x0000000000000000000000000000000000000001"}"#; + let deserialized: CallRequest = serde_json::from_str(s).unwrap(); + + assert_eq!(deserialized, CallRequest { + from: Some(Address::from(1)), + to: None, + gas_price: None, + gas: None, + value: None, + data: None, + nonce: None, + }); + } +} diff --git a/rpc/src/v1/types/log.rs b/rpc/src/v1/types/log.rs index 0f5fdee15..c8dfb1aec 100644 --- a/rpc/src/v1/types/log.rs +++ b/rpc/src/v1/types/log.rs @@ -20,19 +20,19 @@ use v1::types::Bytes; #[derive(Debug, Serialize)] pub struct Log { - address: Address, - topics: Vec, - data: Bytes, + pub address: Address, + pub topics: Vec, + pub data: Bytes, #[serde(rename="blockHash")] - block_hash: H256, + pub block_hash: H256, #[serde(rename="blockNumber")] - block_number: U256, + pub block_number: U256, #[serde(rename="transactionHash")] - transaction_hash: H256, + pub transaction_hash: H256, #[serde(rename="transactionIndex")] - transaction_index: U256, + pub transaction_index: U256, #[serde(rename="logIndex")] - log_index: U256, + pub log_index: U256, } impl From for Log { diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index 0121e4aea..06b07b146 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -24,6 +24,7 @@ mod optionals; mod sync; mod transaction; mod transaction_request; +mod call_request; mod receipt; pub use self::block::{Block, BlockTransactions}; @@ -36,5 +37,6 @@ pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; pub use self::transaction_request::TransactionRequest; +pub use self::call_request::CallRequest; pub use self::receipt::Receipt; diff --git a/rpc/src/v1/types/receipt.rs b/rpc/src/v1/types/receipt.rs index fa34d5df5..4bcfa3eb5 100644 --- a/rpc/src/v1/types/receipt.rs +++ b/rpc/src/v1/types/receipt.rs @@ -53,4 +53,42 @@ impl From for Receipt { } } +#[cfg(test)] +mod tests { + use serde_json; + use std::str::FromStr; + use util::numbers::*; + use v1::types::{Bytes, Log, Receipt}; + + #[test] + fn receipt_serialization() { + let s = r#"{"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","cumulativeGasUsed":"0x20","gasUsed":"0x10","contractAddress":null,"logs":[{"address":"0x33990122638b9132ca29c723bdf037f1a891a70c","topics":["0xa6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc","0x4861736852656700000000000000000000000000000000000000000000000000"],"data":"0x","blockHash":"0xed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5","blockNumber":"0x04510c","transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x00","logIndex":"0x01"}]}"#; + + let receipt = Receipt { + transaction_hash: H256::zero(), + transaction_index: U256::zero(), + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: U256::from(0x4510c), + cumulative_gas_used: U256::from(0x20), + gas_used: U256::from(0x10), + contract_address: None, + logs: vec![Log { + address: Address::from_str("33990122638b9132ca29c723bdf037f1a891a70c").unwrap(), + topics: vec![ + H256::from_str("a6697e974e6a320f454390be03f74955e8978f1a6971ea6730542e37b66179bc").unwrap(), + H256::from_str("4861736852656700000000000000000000000000000000000000000000000000").unwrap() + ], + data: Bytes::new(vec![]), + block_hash: H256::from_str("ed76641c68a1c641aee09a94b3b471f4dc0316efe5ac19cf488e2674cf8d05b5").unwrap(), + block_number: U256::from(0x4510c), + transaction_hash: H256::new(), + transaction_index: U256::zero(), + log_index: U256::one() + }] + }; + + let serialized = serde_json::to_string(&receipt).unwrap(); + assert_eq!(serialized, s); + } +} diff --git a/rpc/src/v1/types/transaction_request.rs b/rpc/src/v1/types/transaction_request.rs index ed4dc19a2..a9ed8a3f4 100644 --- a/rpc/src/v1/types/transaction_request.rs +++ b/rpc/src/v1/types/transaction_request.rs @@ -15,8 +15,7 @@ // along with Parity. If not, see . use util::hash::Address; -use util::numbers::{Uint, U256}; -use ethcore::transaction::{Action, Transaction}; +use util::numbers::U256; use v1::types::Bytes; #[derive(Debug, Default, PartialEq, Deserialize)] @@ -31,19 +30,6 @@ pub struct TransactionRequest { pub nonce: Option, } -impl Into for TransactionRequest { - fn into(self) -> Transaction { - Transaction { - nonce: self.nonce.unwrap_or_else(U256::zero), - action: self.to.map_or(Action::Create, Action::Call), - gas: self.gas.unwrap_or_else(U256::zero), - gas_price: self.gas_price.unwrap_or_else(U256::zero), - value: self.value.unwrap_or_else(U256::zero), - data: self.data.map_or_else(Vec::new, |d| d.to_vec()), - } - } -} - #[cfg(test)] mod tests { use std::str::FromStr; @@ -55,50 +41,6 @@ mod tests { use v1::types::Bytes; use super::*; - #[test] - fn transaction_request_into_transaction() { - let tr = TransactionRequest { - from: Address::default(), - to: Some(Address::from(10)), - gas_price: Some(U256::from(20)), - gas: Some(U256::from(10_000)), - value: Some(U256::from(1)), - data: Some(Bytes::new(vec![10, 20])), - nonce: Some(U256::from(12)), - }; - - assert_eq!(Transaction { - nonce: U256::from(12), - action: Action::Call(Address::from(10)), - gas: U256::from(10_000), - gas_price: U256::from(20), - value: U256::from(1), - data: vec![10, 20], - }, tr.into()); - } - - #[test] - fn empty_transaction_request_into_transaction() { - let tr = TransactionRequest { - from: Address::default(), - to: None, - gas_price: None, - gas: None, - value: None, - data: None, - nonce: None, - }; - - assert_eq!(Transaction { - nonce: U256::zero(), - action: Action::Create, - gas: U256::zero(), - gas_price: U256::zero(), - value: U256::zero(), - data: vec![], - }, tr.into()); - } - #[test] fn transaction_request_deserialize() { let s = r#"{ diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 66e9f2edb..e5096a317 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -20,6 +20,7 @@ use numbers::*; use bytes::*; use secp256k1::{key, Secp256k1}; use rand::os::OsRng; +use sha3::Hashable; /// Secret key for secp256k1 EC operations. 256 bit generic "hash" data. pub type Secret = H256; @@ -135,15 +136,22 @@ impl KeyPair { public: p, }) } + /// Returns public key pub fn public(&self) -> &Public { &self.public } + /// Returns private key pub fn secret(&self) -> &Secret { &self.secret } + /// Returns address. + pub fn address(&self) -> Address { + Address::from(self.public.sha3()) + } + /// Sign a message with our secret key. pub fn sign(&self, message: &H256) -> Result { ec::sign(&self.secret, message) } }