From 56b020987e550ea52f255b37cddaec52fb8c8487 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 24 May 2016 12:21:40 +0200 Subject: [PATCH 01/25] refine tests for call deserialization --- json/src/bytes.rs | 9 +++++++++ json/src/vm/call.rs | 37 ++++++++++++++++++++++++++++++++++--- rpc/src/v1/impls/ethcore.rs | 2 +- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/json/src/bytes.rs b/json/src/bytes.rs index 812b109f7..18dc73844 100644 --- a/json/src/bytes.rs +++ b/json/src/bytes.rs @@ -19,6 +19,7 @@ use rustc_serialize::hex::FromHex; use serde::{Deserialize, Deserializer, Error}; use serde::de::Visitor; +use std::ops::Deref; /// Lenient bytes json deserialization for test json files. #[derive(Default, Debug, PartialEq, Clone)] @@ -30,6 +31,14 @@ impl Into> for Bytes { } } +impl Deref for Bytes { + type Target = Vec; + + fn deref(&self) -> &Vec { + &self.0 + } +} + impl Deserialize for Bytes { fn deserialize(deserializer: &mut D) -> Result where D: Deserializer { diff --git a/json/src/vm/call.rs b/json/src/vm/call.rs index 2fe6265aa..1947fd25c 100644 --- a/json/src/vm/call.rs +++ b/json/src/vm/call.rs @@ -39,16 +39,47 @@ pub struct Call { mod tests { use serde_json; use vm::Call; + use util::numbers::U256; + use uint::Uint; + use util::hash::Address as Hash160; + use hash::Address; + use maybe::MaybeEmpty; + use std::str::FromStr; #[test] - fn call_deserialization() { + fn call_deserialization_empty_dest() { let s = r#"{ "data" : "0x1111222233334444555566667777888899990000aaaabbbbccccddddeeeeffff", "destination" : "", "gasLimit" : "0x1748766aa5", "value" : "0x00" }"#; - let _deserialized: Call = serde_json::from_str(s).unwrap(); - // TODO: validate all fields + let call: Call = serde_json::from_str(s).unwrap(); + + assert_eq!(&call.data[..], + &[0x11, 0x11, 0x22, 0x22, 0x33, 0x33, 0x44, 0x44, 0x55, 0x55, 0x66, 0x66, 0x77, 0x77, + 0x88, 0x88, 0x99, 0x99, 0x00, 0x00, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0xdd, 0xdd, + 0xee, 0xee, 0xff, 0xff]); + + assert_eq!(call.destination, MaybeEmpty::None); + assert_eq!(call.gas_limit, Uint(U256::from(0x1748766aa5u64))); + assert_eq!(call.value, Uint(U256::from(0))); + } + + #[test] + fn call_deserialization_full_dest() { + let s = r#"{ + "data" : "0x1234", + "destination" : "5a39ed1020c04d4d84539975b893a4e7c53eab6c", + "gasLimit" : "0x1748766aa5", + "value" : "0x00" + }"#; + + let call: Call = serde_json::from_str(s).unwrap(); + + assert_eq!(&call.data[..], &[0x12, 0x34]); + assert_eq!(call.destination, MaybeEmpty::Some(Address(Hash160::from_str("5a39ed1020c04d4d84539975b893a4e7c53eab6c").unwrap()))); + assert_eq!(call.gas_limit, Uint(U256::from(0x1748766aa5u64))); + assert_eq!(call.value, Uint(U256::from(0))); } } diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index de458a53f..f5d6f1fda 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -22,7 +22,7 @@ use std::sync::{Arc, Weak}; use std::ops::Deref; use std::collections::BTreeMap; use jsonrpc_core::*; -use ethminer::{MinerService}; +use ethminer::MinerService; use v1::traits::Ethcore; use v1::types::Bytes; From 152bb6f21b8abde53865ee7080ff2d55dc8d58dc Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 24 May 2016 16:56:09 +0200 Subject: [PATCH 02/25] create integration test harness for eth RPC API --- rpc/Cargo.toml | 4 + rpc/src/lib.rs | 5 ++ rpc/src/v1/tests/eth.rs | 0 rpc/src/v1/tests/helpers/sync_provider.rs | 4 +- rpc/src/v1/tests/integration/eth.rs | 100 ++++++++++++++++++++++ rpc/src/v1/tests/integration/mod.rs | 21 +++++ rpc/src/v1/tests/mod.rs | 2 +- 7 files changed, 133 insertions(+), 3 deletions(-) delete mode 100644 rpc/src/v1/tests/eth.rs create mode 100644 rpc/src/v1/tests/integration/eth.rs create mode 100644 rpc/src/v1/tests/integration/mod.rs diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 2cdbb0a2b..23fef5d06 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -29,6 +29,10 @@ json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" } serde_codegen = { version = "0.7.0", optional = true } syntex = "^0.32.0" +[dev-dependencies] +ethjson = { path = "../json" } +ethcore-devtools = { path = "../devtools" } + [features] default = ["serde_codegen"] nightly = ["serde_macros"] diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 7d9818615..24d58819c 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -33,6 +33,11 @@ extern crate ethminer; extern crate transient_hashmap; extern crate json_ipc_server as ipc; +#[cfg(test)] +extern crate ethjson; +#[cfg(test)] +extern crate ethcore_devtools as devtools; + use std::sync::Arc; use std::net::SocketAddr; use self::jsonrpc_core::{IoHandler, IoDelegate}; diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs deleted file mode 100644 index e69de29bb..000000000 diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index fc81586dd..114b5b08f 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -16,9 +16,9 @@ //! Test implementation of SyncProvider. -use util::{U256}; +use util::U256; use ethsync::{SyncProvider, SyncStatus, SyncState}; -use std::sync::{RwLock}; +use std::sync::RwLock; /// TestSyncProvider config. pub struct Config { diff --git a/rpc/src/v1/tests/integration/eth.rs b/rpc/src/v1/tests/integration/eth.rs new file mode 100644 index 000000000..d402f2b08 --- /dev/null +++ b/rpc/src/v1/tests/integration/eth.rs @@ -0,0 +1,100 @@ +// Copyright 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 . + +//! rpc integration tests. +use std::collections::HashMap; +use std::sync::Arc; + +use ethjson::blockchain::test::Test; +use ethcore::client::{BlockChainClient, Client, ClientConfig}; +use ethcore::spec::Genesis; +use ethcore::block::Block; +use ethcore::ethereum; +use ethminer::ExternalMiner; +use devtools::RandomTempPath; +use util::io::IoChannel; +use util::hash::{Address, FixedHash}; +use util::numbers::U256; +use util::keys::{TestAccount, TestAccountProvider}; +use jsonrpc_core::IoHandler; + +use v1::traits::eth::Eth; +use v1::impls::EthClient; +use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; + +use super::RPC_CHAIN; + +#[test] +fn harness_works() { + eth_harness(|_| {}); +} + +fn account_provider() -> Arc { + let mut accounts = HashMap::new(); + accounts.insert(Address::from(1), TestAccount::new("test")); + let ap = TestAccountProvider::new(accounts); + Arc::new(ap) +} + +fn sync_provider() -> Arc { + Arc::new(TestSyncProvider::new(Config { + network_id: U256::from(3), + num_peers: 120, + })) +} + +fn miner_service() -> Arc { + Arc::new(TestMinerService::default()) +} + +// this harness will create a handler which tests can send specially-crafted +// JSONRPC requests to. +fn eth_harness(mut cb: F) -> U + where F: FnMut(&IoHandler) -> U { + let chains = Test::load(RPC_CHAIN).unwrap(); + let chain = chains.into_iter().next().unwrap().1; + let genesis = Genesis::from(chain.genesis()); + let mut spec = ethereum::new_frontier_test(); + let state = chain.pre_state.clone().into(); + spec.set_genesis_state(state); + spec.overwrite_genesis_params(genesis); + assert!(spec.is_state_root_valid()); + + let dir = RandomTempPath::new(); + let client = Client::new(ClientConfig::default(), spec, dir.as_path(), IoChannel::disconnected()).unwrap(); + let sync_provider = sync_provider(); + let miner_service = miner_service(); + let account_provider = account_provider(); + let external_miner = Arc::new(ExternalMiner::default()); + + for b in &chain.blocks_rlp() { + if Block::is_good(&b) { + let _ = client.import_block(b.clone()); + client.flush_queue(); + client.import_verified_blocks(&IoChannel::disconnected()); + } + } + + assert!(client.chain_info().best_block_hash == chain.best_block.into()); + + let eth_client = EthClient::new(&client, &sync_provider, &account_provider, + &miner_service, &external_miner); + + let handler = IoHandler::new(); + let delegate = eth_client.to_delegate(); + handler.add_delegate(delegate); + cb(&handler) +} diff --git a/rpc/src/v1/tests/integration/mod.rs b/rpc/src/v1/tests/integration/mod.rs new file mode 100644 index 000000000..8a67d78dd --- /dev/null +++ b/rpc/src/v1/tests/integration/mod.rs @@ -0,0 +1,21 @@ +// Copyright 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 . + +//! Integration tests for the JSONRPC APIs + +mod eth; + +const RPC_CHAIN: &'static [u8] = include_bytes!("../../../../../ethcore/res/ethereum/tests/BlockchainTests/bcRPC_API_Test.json"); \ No newline at end of file diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index f5e7d1404..78a6a674f 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -5,4 +5,4 @@ pub mod helpers; #[cfg(test)] mod mocked; #[cfg(test)] -mod eth; \ No newline at end of file +mod integration; From d370a86b4325210820d269ed45377ac6580fc43a Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 24 May 2016 19:20:07 +0200 Subject: [PATCH 03/25] More flexible chain extraction, get_balance test --- rpc/src/v1/tests/integration/eth.rs | 42 ++++++++++++++++++++++------- rpc/src/v1/tests/integration/mod.rs | 35 ++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 11 deletions(-) diff --git a/rpc/src/v1/tests/integration/eth.rs b/rpc/src/v1/tests/integration/eth.rs index d402f2b08..a2640203f 100644 --- a/rpc/src/v1/tests/integration/eth.rs +++ b/rpc/src/v1/tests/integration/eth.rs @@ -18,7 +18,6 @@ use std::collections::HashMap; use std::sync::Arc; -use ethjson::blockchain::test::Test; use ethcore::client::{BlockChainClient, Client, ClientConfig}; use ethcore::spec::Genesis; use ethcore::block::Block; @@ -30,16 +29,43 @@ use util::hash::{Address, FixedHash}; use util::numbers::U256; use util::keys::{TestAccount, TestAccountProvider}; use jsonrpc_core::IoHandler; +use ethjson::blockchain::BlockChain; use v1::traits::eth::Eth; use v1::impls::EthClient; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; -use super::RPC_CHAIN; - #[test] fn harness_works() { - eth_harness(|_| {}); + let chain: BlockChain = extract_chain!("BlockchainTests/bcUncleTest"); + chain_harness(chain, |_| {}); +} + +#[test] +fn eth_get_balance() { + let chain = extract_chain!("BlockchainTests/bcWalletTest", "wallet2outOf3txs"); + chain_harness(chain, |handler| { + // final account state + let req_latest = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["0xaaaf5374fce5edbc8e2a8697c15331677e6ebaaa", "latest"], + "id": 1 + }"#; + let res_latest = r#"{"jsonrpc":"2.0","result":"0x09","id":1}"#; + assert_eq!(&handler.handle_request(req_latest).unwrap(), res_latest); + + // non-existant account + let req_new_acc = r#"{ + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": ["0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"], + "id": 3 + }"#; + + let res_new_acc = r#"{"jsonrpc":"2.0","result":"0x00","id":3}"#; + assert_eq!(&handler.handle_request(req_new_acc).unwrap(), res_new_acc); + }); } fn account_provider() -> Arc { @@ -60,12 +86,10 @@ fn miner_service() -> Arc { Arc::new(TestMinerService::default()) } -// this harness will create a handler which tests can send specially-crafted -// JSONRPC requests to. -fn eth_harness(mut cb: F) -> U +// given a blockchain, this harness will create an EthClient wrapping it +// which tests can pass specially crafted requests to. +fn chain_harness(chain: BlockChain, mut cb: F) -> U where F: FnMut(&IoHandler) -> U { - let chains = Test::load(RPC_CHAIN).unwrap(); - let chain = chains.into_iter().next().unwrap().1; let genesis = Genesis::from(chain.genesis()); let mut spec = ethereum::new_frontier_test(); let state = chain.pre_state.clone().into(); diff --git a/rpc/src/v1/tests/integration/mod.rs b/rpc/src/v1/tests/integration/mod.rs index 8a67d78dd..4a845c074 100644 --- a/rpc/src/v1/tests/integration/mod.rs +++ b/rpc/src/v1/tests/integration/mod.rs @@ -16,6 +16,37 @@ //! Integration tests for the JSONRPC APIs -mod eth; +// extract a chain from the given JSON file, +// stored in ethcore/res/ethereum/tests/. +// +// usage: +// `extract_chain!("Folder/File")` will load Folder/File.json and extract +// the first block chain stored within. +// +// `extract_chain!("Folder/File", "with_name")` will load Folder/File.json and +// extract the chain with that name. This will panic if no chain by that name +// is found. +macro_rules! extract_chain { + ($file:expr, $name:expr) => {{ + const RAW_DATA: &'static [u8] = + include_bytes!(concat!("../../../../../ethcore/res/ethereum/tests/", $file, ".json")); + let mut chain = None; + for (name, c) in ::ethjson::blockchain::Test::load(RAW_DATA).unwrap() { + if name == $name { + chain = Some(c); + break; + } + } + chain.unwrap() + }}; -const RPC_CHAIN: &'static [u8] = include_bytes!("../../../../../ethcore/res/ethereum/tests/BlockchainTests/bcRPC_API_Test.json"); \ No newline at end of file + ($file:expr) => {{ + const RAW_DATA: &'static [u8] = + include_bytes!(concat!("../../../../../ethcore/res/ethereum/tests/", $file, ".json")); + + ::ethjson::blockchain::Test::load(RAW_DATA) + .unwrap().into_iter().next().unwrap().1 + }}; +} + +mod eth; \ No newline at end of file From cf18c4bb0ac89f507deec985d1de69b3b9a8ad7f Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 12:30:55 +0200 Subject: [PATCH 04/25] make MinerService object-safe --- miner/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index e9ac7aba2..a1780efff 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -107,12 +107,12 @@ pub trait MinerService : Send + Sync { /// Imports transactions to transaction queue. fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Vec> - where T: Fn(&Address) -> AccountDetails; + where T: Fn(&Address) -> AccountDetails, Self: Sized; /// Imports own (node owner) transaction to queue. fn import_own_transaction(&self, chain: &BlockChainClient, transaction: SignedTransaction, fetch_account: T) -> Result - where T: Fn(&Address) -> AccountDetails; + where T: Fn(&Address) -> AccountDetails, Self: Sized; /// Returns hashes of transactions currently in pending fn pending_transactions_hashes(&self) -> Vec; @@ -131,7 +131,8 @@ pub trait MinerService : Send + Sync { fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error>; /// Get the sealing work package and if `Some`, apply some transform. - fn map_sealing_work(&self, chain: &BlockChainClient, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T; + fn map_sealing_work(&self, chain: &BlockChainClient, f: F) -> Option + where F: FnOnce(&ClosedBlock) -> T, Self: Sized; /// Query pending transactions for hash. fn transaction(&self, hash: &H256) -> Option; From 688790f13f5025d87c532b21109ae6fbdb07906b Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 12:44:27 +0200 Subject: [PATCH 05/25] re-export AccountProvider trait --- util/src/keys/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/util/src/keys/mod.rs b/util/src/keys/mod.rs index 5d718affc..38fa51eca 100644 --- a/util/src/keys/mod.rs +++ b/util/src/keys/mod.rs @@ -21,4 +21,5 @@ pub mod store; mod geth_import; mod test_account_provider; +pub use self::store::AccountProvider; pub use self::test_account_provider::{TestAccount, TestAccountProvider}; From f67486e31f883926ac2af21867b2e8cb5388ea43 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 13:22:17 +0200 Subject: [PATCH 06/25] have miner service update the pending nonces on transaction import --- rpc/src/v1/tests/helpers/miner_service.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 5d57d5d61..36296613c 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -115,12 +115,18 @@ impl MinerService for TestMinerService { } /// Imports transactions to transaction queue. - fn import_transactions(&self, transactions: Vec, _fetch_account: T) -> + fn import_transactions(&self, transactions: Vec, fetch_account: T) -> Vec> where T: Fn(&Address) -> AccountDetails { // lets assume that all txs are valid self.imported_transactions.lock().unwrap().extend_from_slice(&transactions); + for transaction in &transactions { + if let Ok(ref sender) = transaction.sender() { + let nonce = self.last_nonce(sender).unwrap_or(fetch_account(sender).nonce); + self.last_nonces.write().unwrap().insert(sender.clone(), nonce + U256::from(1)); + } + } transactions .iter() .map(|_| Ok(TransactionImportResult::Current)) @@ -128,9 +134,16 @@ impl MinerService for TestMinerService { } /// Imports transactions to transaction queue. - fn import_own_transaction(&self, _chain: &BlockChainClient, transaction: SignedTransaction, _fetch_account: T) -> + fn import_own_transaction(&self, chain: &BlockChainClient, transaction: SignedTransaction, _fetch_account: T) -> Result where T: Fn(&Address) -> AccountDetails { + + // keep the pending nonces up to date + if let Ok(ref sender) = transaction.sender() { + let nonce = self.last_nonce(sender).unwrap_or(chain.latest_nonce(sender)); + self.last_nonces.write().unwrap().insert(sender.clone(), nonce + U256::from(1)); + } + // lets assume that all txs are valid self.imported_transactions.lock().unwrap().push(transaction); @@ -200,7 +213,9 @@ impl MinerService for TestMinerService { } fn nonce(&self, _chain: &BlockChainClient, address: &Address) -> U256 { - self.latest_closed_block.lock().unwrap().as_ref().map_or_else(U256::zero, |b| b.block().fields().state.nonce(address).clone()) + // we assume all transactions are in a pending block, ignoring the + // reality of gas limits. + self.last_nonce(address).unwrap_or(U256::zero()) } fn code(&self, _chain: &BlockChainClient, address: &Address) -> Option { From 1de7ea090c3aa27fd3084910c3ce9d79fee57172 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 13:23:24 +0200 Subject: [PATCH 07/25] add informative comment on transaction::Action --- ethcore/src/types/transaction.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ethcore/src/types/transaction.rs b/ethcore/src/types/transaction.rs index 842decd88..a6b4c1781 100644 --- a/ethcore/src/types/transaction.rs +++ b/ethcore/src/types/transaction.rs @@ -36,6 +36,7 @@ pub enum Action { /// Create creates new contract. Create, /// Calls contract at given address. + /// In the case of a transfer, this is the receiver's address.' Call(Address), } From 4c55e4968ef0fba267e9df2cc433a80133b31b83 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 13:27:03 +0200 Subject: [PATCH 08/25] add eth_blockNumber, eth_TransactionCount integration tests. also adds an EthTester struct for more test flexibility. --- rpc/src/v1/tests/integration/eth.rs | 123 +++++++++++++++++++++++++--- 1 file changed, 113 insertions(+), 10 deletions(-) diff --git a/rpc/src/v1/tests/integration/eth.rs b/rpc/src/v1/tests/integration/eth.rs index a2640203f..3c897dbb3 100644 --- a/rpc/src/v1/tests/integration/eth.rs +++ b/rpc/src/v1/tests/integration/eth.rs @@ -17,17 +17,19 @@ //! rpc integration tests. use std::collections::HashMap; use std::sync::Arc; +use std::str::FromStr; use ethcore::client::{BlockChainClient, Client, ClientConfig}; use ethcore::spec::Genesis; use ethcore::block::Block; use ethcore::ethereum; -use ethminer::ExternalMiner; +use ethcore::transaction::{Transaction, Action}; +use ethminer::{MinerService, ExternalMiner}; use devtools::RandomTempPath; use util::io::IoChannel; use util::hash::{Address, FixedHash}; -use util::numbers::U256; -use util::keys::{TestAccount, TestAccountProvider}; +use util::numbers::{Uint, U256}; +use util::keys::{AccountProvider, TestAccount, TestAccountProvider}; use jsonrpc_core::IoHandler; use ethjson::blockchain::BlockChain; @@ -35,6 +37,13 @@ use v1::traits::eth::Eth; use v1::impls::EthClient; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; +struct EthTester { + _client: Arc, + _miner: Arc, + accounts: Arc, + handler: IoHandler, +} + #[test] fn harness_works() { let chain: BlockChain = extract_chain!("BlockchainTests/bcUncleTest"); @@ -44,7 +53,7 @@ fn harness_works() { #[test] fn eth_get_balance() { let chain = extract_chain!("BlockchainTests/bcWalletTest", "wallet2outOf3txs"); - chain_harness(chain, |handler| { + chain_harness(chain, |tester| { // final account state let req_latest = r#"{ "jsonrpc": "2.0", @@ -52,8 +61,8 @@ fn eth_get_balance() { "params": ["0xaaaf5374fce5edbc8e2a8697c15331677e6ebaaa", "latest"], "id": 1 }"#; - let res_latest = r#"{"jsonrpc":"2.0","result":"0x09","id":1}"#; - assert_eq!(&handler.handle_request(req_latest).unwrap(), res_latest); + let res_latest = r#"{"jsonrpc":"2.0","result":"0x09","id":1}"#.to_owned(); + assert_eq!(tester.handler.handle_request(req_latest).unwrap(), res_latest); // non-existant account let req_new_acc = r#"{ @@ -63,8 +72,94 @@ fn eth_get_balance() { "id": 3 }"#; - let res_new_acc = r#"{"jsonrpc":"2.0","result":"0x00","id":3}"#; - assert_eq!(&handler.handle_request(req_new_acc).unwrap(), res_new_acc); + let res_new_acc = r#"{"jsonrpc":"2.0","result":"0x00","id":3}"#.to_owned(); + assert_eq!(tester.handler.handle_request(req_new_acc).unwrap(), res_new_acc); + }); +} + +#[test] +fn eth_block_number() { + let chain = extract_chain!("BlockchainTests/bcRPC_API_Test"); + chain_harness(chain, |tester| { + let req_number = r#"{ + "jsonrpc": "2.0", + "method": "eth_blockNumber", + "params": [], + "id": 1 + }"#; + + let res_number = r#"{"jsonrpc":"2.0","result":"0x20","id":1}"#.to_owned(); + assert_eq!(tester.handler.handle_request(req_number).unwrap(), res_number); + }); +} + +#[cfg(test)] +#[test] +fn eth_transaction_count() { + let chain = extract_chain!("BlockchainTests/bcRPC_API_Test"); + chain_harness(chain, |tester| { + let address = tester.accounts.new_account("123").unwrap(); + + let req_before = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], + "id": 15 + }"#; + + let res_before = r#"{"jsonrpc":"2.0","result":"0x00","id":15}"#; + + + assert_eq!(tester.handler.handle_request(&req_before).unwrap(), res_before); + + let t = Transaction { + nonce: U256::zero(), + gas_price: U256::from(0x9184e72a000u64), + gas: U256::from(0x76c0), + action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + value: U256::from(0x9184e72au64), + data: vec![] + }.fake_sign(address.clone()); + + let req_send_trans = r#"{ + "jsonrpc": "2.0", + "method": "eth_sendTransaction", + "params": [{ + "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a" + }], + "id": 16 + }"#; + + // dispatch the transaction. + tester.handler.handle_request(&req_send_trans).unwrap(); + + // we have submitted the transaction -- but this shouldn't be reflected in a "latest" query. + let req_after_latest = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "latest"], + "id": 17 + }"#; + + let res_after_latest = r#"{"jsonrpc":"2.0","result":"0x00","id":17}"#; + + assert_eq!(&tester.handler.handle_request(&req_after_latest).unwrap(), res_after_latest); + + // the pending transactions should have been updated. + let req_after_pending = r#"{ + "jsonrpc": "2.0", + "method": "eth_getTransactionCount", + "params": [""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", "pending"], + "id": 18 + }"#; + + let res_after_pending = r#"{"jsonrpc":"2.0","result":"0x01","id":18}"#; + + assert_eq!(&tester.handler.handle_request(&req_after_pending).unwrap(), res_after_pending); }); } @@ -89,7 +184,7 @@ fn miner_service() -> Arc { // given a blockchain, this harness will create an EthClient wrapping it // which tests can pass specially crafted requests to. fn chain_harness(chain: BlockChain, mut cb: F) -> U - where F: FnMut(&IoHandler) -> U { + where F: FnMut(&EthTester) -> U { let genesis = Genesis::from(chain.genesis()); let mut spec = ethereum::new_frontier_test(); let state = chain.pre_state.clone().into(); @@ -120,5 +215,13 @@ fn chain_harness(chain: BlockChain, mut cb: F) -> U let handler = IoHandler::new(); let delegate = eth_client.to_delegate(); handler.add_delegate(delegate); - cb(&handler) + + let tester = EthTester { + _miner: miner_service, + _client: client, + accounts: account_provider, + handler: handler, + }; + + cb(&tester) } From 7ee23240f08a4ecf5d5f053c45498c76eedae787 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Wed, 25 May 2016 15:14:02 +0200 Subject: [PATCH 09/25] fix travis test build --- Cargo.lock | 2 ++ rpc/Cargo.toml | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4dbcd1825..1a5b61a3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -326,7 +326,9 @@ dependencies = [ "clippy 0.0.69 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.2.0", "ethcore 1.2.0", + "ethcore-devtools 1.2.0", "ethcore-util 1.2.0", + "ethjson 0.1.0", "ethminer 1.2.0", "ethsync 1.2.0", "json-ipc-server 0.1.0 (git+https://github.com/ethcore/json-ipc-server.git)", diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 23fef5d06..61b51cf88 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -19,6 +19,8 @@ ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } ethsync = { path = "../sync" } ethminer = { path = "../miner" } +ethjson = { path = "../json" } +ethcore-devtools = { path = "../devtools" } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } @@ -29,10 +31,6 @@ json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" } serde_codegen = { version = "0.7.0", optional = true } syntex = "^0.32.0" -[dev-dependencies] -ethjson = { path = "../json" } -ethcore-devtools = { path = "../devtools" } - [features] default = ["serde_codegen"] nightly = ["serde_macros"] From e7791c220a3ea76e3d8dd6fb017b8bd9ee856dad Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 26 May 2016 13:26:07 +0200 Subject: [PATCH 10/25] rebase fixes and address style concern --- rpc/src/v1/tests/helpers/miner_service.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 36296613c..600f88508 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -121,11 +121,9 @@ impl MinerService for TestMinerService { // lets assume that all txs are valid self.imported_transactions.lock().unwrap().extend_from_slice(&transactions); - for transaction in &transactions { - if let Ok(ref sender) = transaction.sender() { - let nonce = self.last_nonce(sender).unwrap_or(fetch_account(sender).nonce); - self.last_nonces.write().unwrap().insert(sender.clone(), nonce + U256::from(1)); - } + for sender in transactions.iter().filter_map(|t| t.sender().ok()) { + let nonce = self.last_nonce(&sender).unwrap_or(fetch_account(&sender).nonce); + self.last_nonces.write().unwrap().insert(sender, nonce + U256::from(1)); } transactions .iter() From 9d4cd7b73e657c99e1704033e69f9ab414d9482e Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Thu, 26 May 2016 13:30:19 +0200 Subject: [PATCH 11/25] assert the transaction is being signed correctly --- rpc/src/v1/tests/integration/eth.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/tests/integration/eth.rs b/rpc/src/v1/tests/integration/eth.rs index 3c897dbb3..386b72cf7 100644 --- a/rpc/src/v1/tests/integration/eth.rs +++ b/rpc/src/v1/tests/integration/eth.rs @@ -99,6 +99,7 @@ fn eth_transaction_count() { let chain = extract_chain!("BlockchainTests/bcRPC_API_Test"); chain_harness(chain, |tester| { let address = tester.accounts.new_account("123").unwrap(); + let secret = tester.accounts.account_secret(&address).unwrap(); let req_before = r#"{ "jsonrpc": "2.0", @@ -119,7 +120,7 @@ fn eth_transaction_count() { action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), value: U256::from(0x9184e72au64), data: vec![] - }.fake_sign(address.clone()); + }.sign(&secret); let req_send_trans = r#"{ "jsonrpc": "2.0", @@ -134,8 +135,10 @@ fn eth_transaction_count() { "id": 16 }"#; + let res_send_trans = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":16}"#; + // dispatch the transaction. - tester.handler.handle_request(&req_send_trans).unwrap(); + assert_eq!(tester.handler.handle_request(&req_send_trans).unwrap(), res_send_trans); // we have submitted the transaction -- but this shouldn't be reflected in a "latest" query. let req_after_latest = r#"{ From c021ecd13bd9a0005086be311cd68e7c95ae5528 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 27 May 2016 18:40:48 +0200 Subject: [PATCH 12/25] move "integration" tests out into main module --- rpc/src/v1/tests/{integration => }/eth.rs | 1 - rpc/src/v1/tests/helpers/mod.rs | 2 +- rpc/src/v1/tests/integration/mod.rs | 52 ----------------------- rpc/src/v1/tests/mocked/mod.rs | 3 +- rpc/src/v1/tests/mod.rs | 35 ++++++++++++++- 5 files changed, 37 insertions(+), 56 deletions(-) rename rpc/src/v1/tests/{integration => }/eth.rs (99%) delete mode 100644 rpc/src/v1/tests/integration/mod.rs diff --git a/rpc/src/v1/tests/integration/eth.rs b/rpc/src/v1/tests/eth.rs similarity index 99% rename from rpc/src/v1/tests/integration/eth.rs rename to rpc/src/v1/tests/eth.rs index 386b72cf7..eac5bafcb 100644 --- a/rpc/src/v1/tests/integration/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -110,7 +110,6 @@ fn eth_transaction_count() { let res_before = r#"{"jsonrpc":"2.0","result":"0x00","id":15}"#; - assert_eq!(tester.handler.handle_request(&req_before).unwrap(), res_before); let t = Transaction { diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs index 9b321af98..1b8f9e256 100644 --- a/rpc/src/v1/tests/helpers/mod.rs +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -20,4 +20,4 @@ mod sync_provider; mod miner_service; pub use self::sync_provider::{Config, TestSyncProvider}; -pub use self::miner_service::{TestMinerService}; +pub use self::miner_service::TestMinerService; diff --git a/rpc/src/v1/tests/integration/mod.rs b/rpc/src/v1/tests/integration/mod.rs deleted file mode 100644 index 4a845c074..000000000 --- a/rpc/src/v1/tests/integration/mod.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 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 . - -//! Integration tests for the JSONRPC APIs - -// extract a chain from the given JSON file, -// stored in ethcore/res/ethereum/tests/. -// -// usage: -// `extract_chain!("Folder/File")` will load Folder/File.json and extract -// the first block chain stored within. -// -// `extract_chain!("Folder/File", "with_name")` will load Folder/File.json and -// extract the chain with that name. This will panic if no chain by that name -// is found. -macro_rules! extract_chain { - ($file:expr, $name:expr) => {{ - const RAW_DATA: &'static [u8] = - include_bytes!(concat!("../../../../../ethcore/res/ethereum/tests/", $file, ".json")); - let mut chain = None; - for (name, c) in ::ethjson::blockchain::Test::load(RAW_DATA).unwrap() { - if name == $name { - chain = Some(c); - break; - } - } - chain.unwrap() - }}; - - ($file:expr) => {{ - const RAW_DATA: &'static [u8] = - include_bytes!(concat!("../../../../../ethcore/res/ethereum/tests/", $file, ".json")); - - ::ethjson::blockchain::Test::load(RAW_DATA) - .unwrap().into_iter().next().unwrap().1 - }}; -} - -mod eth; \ No newline at end of file diff --git a/rpc/src/v1/tests/mocked/mod.rs b/rpc/src/v1/tests/mocked/mod.rs index 98caf6e08..dc09d998d 100644 --- a/rpc/src/v1/tests/mocked/mod.rs +++ b/rpc/src/v1/tests/mocked/mod.rs @@ -14,7 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! RPC serialization tests. +//! RPC mocked tests. Most of these test that the RPC server is serializing and forwarding +//! method calls properly. mod eth; mod net; diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index 78a6a674f..3455bfd1f 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -2,7 +2,40 @@ pub mod helpers; +// extract a chain from the given JSON file, +// stored in ethcore/res/ethereum/tests/. +// +// usage: +// `extract_chain!("Folder/File")` will load Folder/File.json and extract +// the first block chain stored within. +// +// `extract_chain!("Folder/File", "with_name")` will load Folder/File.json and +// extract the chain with that name. This will panic if no chain by that name +// is found. +macro_rules! extract_chain { + ($file:expr, $name:expr) => {{ + const RAW_DATA: &'static [u8] = + include_bytes!(concat!("../../../../ethcore/res/ethereum/tests/", $file, ".json")); + let mut chain = None; + for (name, c) in ::ethjson::blockchain::Test::load(RAW_DATA).unwrap() { + if name == $name { + chain = Some(c); + break; + } + } + chain.unwrap() + }}; + + ($file:expr) => {{ + const RAW_DATA: &'static [u8] = + include_bytes!(concat!("../../../../ethcore/res/ethereum/tests/", $file, ".json")); + + ::ethjson::blockchain::Test::load(RAW_DATA) + .unwrap().into_iter().next().unwrap().1 + }}; +} + #[cfg(test)] mod mocked; #[cfg(test)] -mod integration; +mod eth; From ea08dd76a520bc385e451be06e5f55d7efd644c8 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sat, 28 May 2016 21:48:42 +0200 Subject: [PATCH 13/25] remove all possible unsafe code in crypto (#1168) * use #[repr(C)] for all hash types * use a zeroed buffer in crypto::ec::sign * eliminate most usages of unsafe in crypto::ecdh::agree * eliminate all possible unsafety in crypto module --- util/src/crypto.rs | 54 +++++++++++++++++++++++++++------------------- util/src/hash.rs | 1 + 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/util/src/crypto.rs b/util/src/crypto.rs index 3eff70717..b92bb2bae 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -38,13 +38,10 @@ lazy_static! { impl Signature { /// Create a new signature from the R, S and V componenets. pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Signature { - use std::ptr; let mut ret: Signature = Signature::new(); - unsafe { - let retslice: &mut [u8] = &mut ret; - ptr::copy(r.as_ptr(), retslice.as_mut_ptr(), 32); - ptr::copy(s.as_ptr(), retslice.as_mut_ptr().offset(32), 32); - } + (&mut ret[0..32]).copy_from_slice(r); + (&mut ret[32..64]).copy_from_slice(s); + ret[64] = v; ret } @@ -145,7 +142,10 @@ impl KeyPair { let (sec, publ) = try!(context.generate_keypair(&mut rng)); let serialized = publ.serialize_vec(context, false); let p: Public = Public::from_slice(&serialized[1..65]); - let s: Secret = unsafe { ::std::mem::transmute(sec) }; + + let mut s = Secret::new(); + s.copy_from_slice(&sec[0..32]); + Ok(KeyPair { secret: s, public: p, @@ -193,12 +193,14 @@ pub mod ec { /// Returns siganture of message hash. pub fn sign(secret: &Secret, message: &H256) -> Result { // TODO: allow creation of only low-s signatures. - use secp256k1::*; + use secp256k1::{Message, key}; + let context = &crypto::SECP256K1; + // no way to create from raw byte array. let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) }; let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec)); let (rec_id, data) = s.serialize_compact(context); - let mut signature: crypto::Signature = unsafe { ::std::mem::uninitialized() }; + let mut signature = crypto::Signature::new(); signature.clone_from_slice(&data); signature[64] = rec_id.to_i32() as u8; @@ -217,10 +219,12 @@ pub mod ec { let rsig = try!(RecoverableSignature::from_compact(context, &signature[0..64], try!(RecoveryId::from_i32(signature[64] as i32)))); let sig = rsig.to_standard(context); - let mut pdata: [u8; 65] = [4u8; 65]; - let ptr = pdata[1..].as_mut_ptr(); - let src = public.as_ptr(); - unsafe { ::std::ptr::copy_nonoverlapping(src, ptr, 64) }; + let pdata: [u8; 65] = { + let mut temp = [4u8; 65]; + (&mut temp[1..65]).copy_from_slice(public); + temp + }; + let publ = try!(key::PublicKey::from_slice(context, &pdata)); match context.verify(&try!(Message::from_slice(&message)), &sig, &publ) { Ok(_) => Ok(true), @@ -252,21 +256,27 @@ pub mod ec { /// ECDH functions #[cfg_attr(feature="dev", allow(similar_names))] pub mod ecdh { - use crypto::*; - use crypto::{self}; + use hash::FixedHash; + use crypto::{self, Secret, Public, CryptoError}; /// Agree on a shared secret - pub fn agree(secret: &Secret, public: &Public, ) -> Result { - use secp256k1::*; + pub fn agree(secret: &Secret, public: &Public) -> Result { + use secp256k1::{ecdh, key}; + let context = &crypto::SECP256K1; - let mut pdata: [u8; 65] = [4u8; 65]; - let ptr = pdata[1..].as_mut_ptr(); - let src = public.as_ptr(); - unsafe { ::std::ptr::copy_nonoverlapping(src, ptr, 64) }; + let pdata = { + let mut temp = [4u8; 65]; + (&mut temp[1..65]).copy_from_slice(&public[0..64]); + temp + }; + let publ = try!(key::PublicKey::from_slice(context, &pdata)); + // no way to create SecretKey from raw byte array. let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) }; let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec); - let s: Secret = unsafe { ::std::mem::transmute(shared) }; + + let mut s = crypto::Secret::new(); + s.copy_from_slice(&shared[0..32]); Ok(s) } } diff --git a/util/src/hash.rs b/util/src/hash.rs index e1b82b14c..ba96f812c 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -75,6 +75,7 @@ pub fn clean_0x(s: &str) -> &str { macro_rules! impl_hash { ($from: ident, $size: expr) => { #[derive(Eq)] + #[repr(C)] /// Unformatted binary data of fixed length. pub struct $from (pub [u8; $size]); From a8cf0ddf50835d28198e38e70b8ae67ed0e4c1d4 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 29 May 2016 13:09:51 +0200 Subject: [PATCH 14/25] json ipc server version bump --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 5dff43d04..79e174cd3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -578,7 +578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "json-ipc-server" version = "0.1.0" -source = "git+https://github.com/ethcore/json-ipc-server.git#fdcba83d00b127c7419fe21406a5b81998f686eb" +source = "git+https://github.com/ethcore/json-ipc-server.git#4a5e18c321a93eddd67efc4865013efaac9c8d19" dependencies = [ "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", From 7dfd7e883f5ee15d18260ac77cecf8911b7edb82 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 29 May 2016 13:22:45 +0200 Subject: [PATCH 15/25] another bump --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 79e174cd3..ba5edef97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -578,7 +578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "json-ipc-server" version = "0.1.0" -source = "git+https://github.com/ethcore/json-ipc-server.git#4a5e18c321a93eddd67efc4865013efaac9c8d19" +source = "git+https://github.com/ethcore/json-ipc-server.git#4f9226c4f84dcce2385a188374e3b5fc66b63e68" dependencies = [ "bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", From 1176f6acec6a99e008521f541b857adfe8676e47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sun, 29 May 2016 13:25:31 +0200 Subject: [PATCH 16/25] fixing test --- signer/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/signer/src/lib.rs b/signer/src/lib.rs index a39fe68f0..f3a963ac7 100644 --- a/signer/src/lib.rs +++ b/signer/src/lib.rs @@ -33,10 +33,11 @@ //! ``` //! extern crate ethcore_signer; //! -//! use ethcore_signer::Server; +//! use ethcore_signer::ServerBuilder; //! //! fn main() { -//! let _server = Server::start("127.0.0.1:8084".parse().unwrap()); +//! let builder = ServerBuilder::new(); +//! let _server = builder.start("127.0.0.1:8084".parse().unwrap()).unwrap(); //! } //! ``` From fb2ea765d5bcf4bec02f5e65fd0f48dd19f36b13 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Fri, 27 May 2016 20:04:41 +0200 Subject: [PATCH 17/25] remove default implementations using rpc_unimplemented!() --- rpc/src/v1/traits/eth.rs | 86 +++++++++++++++++------------------ rpc/src/v1/traits/ethcore.rs | 34 +++++++------- rpc/src/v1/traits/net.rs | 6 +-- rpc/src/v1/traits/personal.rs | 8 ++-- rpc/src/v1/traits/rpc.rs | 4 +- rpc/src/v1/traits/traces.rs | 8 ++-- rpc/src/v1/traits/web3.rs | 4 +- 7 files changed, 75 insertions(+), 75 deletions(-) diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index a28f72c5c..1577053f4 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -21,115 +21,115 @@ use jsonrpc_core::*; /// Eth rpc interface. pub trait Eth: Sized + Send + Sync + 'static { /// Returns protocol version. - fn protocol_version(&self, _: Params) -> Result { rpc_unimplemented!() } + fn protocol_version(&self, _: Params) -> Result; /// Returns an object with data about the sync status or false. (wtf?) - fn syncing(&self, _: Params) -> Result { rpc_unimplemented!() } + fn syncing(&self, _: Params) -> Result; /// Returns the number of hashes per second that the node is mining with. - fn hashrate(&self, _: Params) -> Result { rpc_unimplemented!() } + fn hashrate(&self, _: Params) -> Result; /// Returns block author. - fn author(&self, _: Params) -> Result { rpc_unimplemented!() } + fn author(&self, _: Params) -> Result; /// Returns true if client is actively mining new blocks. - fn is_mining(&self, _: Params) -> Result { rpc_unimplemented!() } + fn is_mining(&self, _: Params) -> Result; /// Returns current gas_price. - fn gas_price(&self, _: Params) -> Result { rpc_unimplemented!() } + fn gas_price(&self, _: Params) -> Result; /// Returns accounts list. - fn accounts(&self, _: Params) -> Result { rpc_unimplemented!() } + fn accounts(&self, _: Params) -> Result; /// Returns highest block number. - fn block_number(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_number(&self, _: Params) -> Result; /// Returns balance of the given account. - fn balance(&self, _: Params) -> Result { rpc_unimplemented!() } + fn balance(&self, _: Params) -> Result; /// Returns content of the storage at given address. - fn storage_at(&self, _: Params) -> Result { rpc_unimplemented!() } + fn storage_at(&self, _: Params) -> Result; /// Returns block with given hash. - fn block_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_by_hash(&self, _: Params) -> Result; /// Returns block with given number. - fn block_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_by_number(&self, _: Params) -> Result; /// Returns the number of transactions sent from given address at given time (block number). - fn transaction_count(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_count(&self, _: Params) -> Result; /// Returns the number of transactions in a block with given hash. - fn block_transaction_count_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_transaction_count_by_hash(&self, _: Params) -> Result; /// Returns the number of transactions in a block with given block number. - fn block_transaction_count_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_transaction_count_by_number(&self, _: Params) -> Result; /// Returns the number of uncles in a block with given hash. - fn block_uncles_count_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_uncles_count_by_hash(&self, _: Params) -> Result; /// Returns the number of uncles in a block with given block number. - fn block_uncles_count_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_uncles_count_by_number(&self, _: Params) -> Result; /// Returns the code at given address at given time (block number). - fn code_at(&self, _: Params) -> Result { rpc_unimplemented!() } + fn code_at(&self, _: Params) -> Result; /// Signs the data with given address signature. - fn sign(&self, _: Params) -> Result { rpc_unimplemented!() } + fn sign(&self, _: Params) -> Result; /// Sends transaction. - fn send_transaction(&self, _: Params) -> Result { rpc_unimplemented!() } + fn send_transaction(&self, _: Params) -> Result; /// Sends signed transaction. - fn send_raw_transaction(&self, _: Params) -> Result { rpc_unimplemented!() } + fn send_raw_transaction(&self, _: Params) -> Result; /// Call contract. - fn call(&self, _: Params) -> Result { rpc_unimplemented!() } + fn call(&self, _: Params) -> Result; /// Estimate gas needed for execution of given contract. - fn estimate_gas(&self, _: Params) -> Result { rpc_unimplemented!() } + fn estimate_gas(&self, _: Params) -> Result; /// Get transaction by it's hash. - fn transaction_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_by_hash(&self, _: Params) -> Result; /// Returns transaction at given block hash and index. - fn transaction_by_block_hash_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_by_block_hash_and_index(&self, _: Params) -> Result; /// Returns transaction by given block number and index. - fn transaction_by_block_number_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_by_block_number_and_index(&self, _: Params) -> Result; /// Returns transaction receipt. - fn transaction_receipt(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_receipt(&self, _: Params) -> Result; /// Returns an uncles at given block and index. - fn uncle_by_block_hash_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + fn uncle_by_block_hash_and_index(&self, _: Params) -> Result; /// Returns an uncles at given block and index. - fn uncle_by_block_number_and_index(&self, _: Params) -> Result { rpc_unimplemented!() } + fn uncle_by_block_number_and_index(&self, _: Params) -> Result; /// Returns available compilers. - fn compilers(&self, _: Params) -> Result { rpc_unimplemented!() } + fn compilers(&self, _: Params) -> Result; /// Compiles lll code. - fn compile_lll(&self, _: Params) -> Result { rpc_unimplemented!() } + fn compile_lll(&self, _: Params) -> Result; /// Compiles solidity. - fn compile_solidity(&self, _: Params) -> Result { rpc_unimplemented!() } + fn compile_solidity(&self, _: Params) -> Result; /// Compiles serpent. - fn compile_serpent(&self, _: Params) -> Result { rpc_unimplemented!() } + fn compile_serpent(&self, _: Params) -> Result; /// Returns logs matching given filter object. - fn logs(&self, _: Params) -> Result { rpc_unimplemented!() } + fn logs(&self, _: Params) -> Result; /// Returns the hash of the current block, the seedHash, and the boundary condition to be met. - fn work(&self, _: Params) -> Result { rpc_unimplemented!() } + fn work(&self, _: Params) -> Result; /// Used for submitting a proof-of-work solution. - fn submit_work(&self, _: Params) -> Result { rpc_unimplemented!() } + fn submit_work(&self, _: Params) -> Result; /// Used for submitting mining hashrate. - fn submit_hashrate(&self, _: Params) -> Result { rpc_unimplemented!() } + fn submit_hashrate(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { @@ -179,22 +179,22 @@ pub trait Eth: Sized + Send + Sync + 'static { // TODO: do filters api properly pub trait EthFilter: Sized + Send + Sync + 'static { /// Returns id of new filter. - fn new_filter(&self, _: Params) -> Result { rpc_unimplemented!() } + fn new_filter(&self, _: Params) -> Result; /// Returns id of new block filter. - fn new_block_filter(&self, _: Params) -> Result { rpc_unimplemented!() } + fn new_block_filter(&self, _: Params) -> Result; /// Returns id of new block filter. - fn new_pending_transaction_filter(&self, _: Params) -> Result { rpc_unimplemented!() } + fn new_pending_transaction_filter(&self, _: Params) -> Result; /// Returns filter changes since last poll. - fn filter_changes(&self, _: Params) -> Result { rpc_unimplemented!() } + fn filter_changes(&self, _: Params) -> Result; /// Returns all logs matching given filter (in a range 'from' - 'to'). - fn filter_logs(&self, _: Params) -> Result { rpc_unimplemented!() } + fn filter_logs(&self, _: Params) -> Result; /// Uninstalls filter. - fn uninstall_filter(&self, _: Params) -> Result { rpc_unimplemented!() } + fn uninstall_filter(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { diff --git a/rpc/src/v1/traits/ethcore.rs b/rpc/src/v1/traits/ethcore.rs index 2a2159bd9..3646f6c5a 100644 --- a/rpc/src/v1/traits/ethcore.rs +++ b/rpc/src/v1/traits/ethcore.rs @@ -22,55 +22,55 @@ use jsonrpc_core::*; pub trait Ethcore: Sized + Send + Sync + 'static { /// Sets new minimal gas price for mined blocks. - fn set_min_gas_price(&self, _: Params) -> Result { rpc_unimplemented!() } + fn set_min_gas_price(&self, _: Params) -> Result; /// Sets new gas floor target for mined blocks. - fn set_gas_floor_target(&self, _: Params) -> Result { rpc_unimplemented!() } + fn set_gas_floor_target(&self, _: Params) -> Result; /// Sets new extra data for mined blocks. - fn set_extra_data(&self, _: Params) -> Result { rpc_unimplemented!() } + fn set_extra_data(&self, _: Params) -> Result; /// Sets new author for mined block. - fn set_author(&self, _: Params) -> Result { rpc_unimplemented!() } + fn set_author(&self, _: Params) -> Result; /// Sets the limits for transaction queue. - fn set_transactions_limit(&self, _: Params) -> Result { rpc_unimplemented!() } + fn set_transactions_limit(&self, _: Params) -> Result; /// Returns current transactions limit. - fn transactions_limit(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transactions_limit(&self, _: Params) -> Result; /// Returns mining extra data. - fn extra_data(&self, _: Params) -> Result { rpc_unimplemented!() } + fn extra_data(&self, _: Params) -> Result; /// Returns mining gas floor target. - fn gas_floor_target(&self, _: Params) -> Result { rpc_unimplemented!() } + fn gas_floor_target(&self, _: Params) -> Result; /// Returns minimal gas price for transaction to be included in queue. - fn min_gas_price(&self, _: Params) -> Result { rpc_unimplemented!() } + fn min_gas_price(&self, _: Params) -> Result; /// Returns latest logs - fn dev_logs(&self, _: Params) -> Result { rpc_unimplemented!() } + fn dev_logs(&self, _: Params) -> Result; /// Returns logs levels - fn dev_logs_levels(&self, _: Params) -> Result { rpc_unimplemented!() } + fn dev_logs_levels(&self, _: Params) -> Result; /// Returns chain name - fn net_chain(&self, _: Params) -> Result { rpc_unimplemented!() } + fn net_chain(&self, _: Params) -> Result; /// Returns max peers - fn net_max_peers(&self, _: Params) -> Result { rpc_unimplemented!() } + fn net_max_peers(&self, _: Params) -> Result; /// Returns network port - fn net_port(&self, _: Params) -> Result { rpc_unimplemented!() } + fn net_port(&self, _: Params) -> Result; /// Returns rpc settings - fn rpc_settings(&self, _: Params) -> Result { rpc_unimplemented!() } + fn rpc_settings(&self, _: Params) -> Result; /// Returns node name - fn node_name(&self, _: Params) -> Result { rpc_unimplemented!() } + fn node_name(&self, _: Params) -> Result; /// Returns default extra data - fn default_extra_data(&self, _: Params) -> Result { rpc_unimplemented!() } + fn default_extra_data(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. diff --git a/rpc/src/v1/traits/net.rs b/rpc/src/v1/traits/net.rs index 732d6efb2..56fba3e32 100644 --- a/rpc/src/v1/traits/net.rs +++ b/rpc/src/v1/traits/net.rs @@ -21,14 +21,14 @@ use jsonrpc_core::*; /// Net rpc interface. pub trait Net: Sized + Send + Sync + 'static { /// Returns protocol version. - fn version(&self, _: Params) -> Result { rpc_unimplemented!() } + fn version(&self, _: Params) -> Result; /// Returns number of peers connected to node. - fn peer_count(&self, _: Params) -> Result { rpc_unimplemented!() } + fn peer_count(&self, _: Params) -> Result; /// Returns true if client is actively listening for network connections. /// Otherwise false. - fn is_listening(&self, _: Params) -> Result { rpc_unimplemented!() } + fn is_listening(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { diff --git a/rpc/src/v1/traits/personal.rs b/rpc/src/v1/traits/personal.rs index 0619d7ada..d66161c54 100644 --- a/rpc/src/v1/traits/personal.rs +++ b/rpc/src/v1/traits/personal.rs @@ -22,16 +22,16 @@ use jsonrpc_core::*; pub trait Personal: Sized + Send + Sync + 'static { /// Lists all stored accounts - fn accounts(&self, _: Params) -> Result { rpc_unimplemented!() } + fn accounts(&self, _: Params) -> Result; /// Creates new account (it becomes new current unlocked account) - fn new_account(&self, _: Params) -> Result { rpc_unimplemented!() } + fn new_account(&self, _: Params) -> Result; /// Unlocks specified account for use (can only be one unlocked account at one moment) - fn unlock_account(&self, _: Params) -> Result { rpc_unimplemented!() } + fn unlock_account(&self, _: Params) -> Result; /// Sends transaction and signs it in single call. The account is not unlocked in such case. - fn sign_and_send_transaction(&self, _: Params) -> Result { rpc_unimplemented!() } + fn sign_and_send_transaction(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { diff --git a/rpc/src/v1/traits/rpc.rs b/rpc/src/v1/traits/rpc.rs index 5c981c8a1..669d0d8c6 100644 --- a/rpc/src/v1/traits/rpc.rs +++ b/rpc/src/v1/traits/rpc.rs @@ -23,10 +23,10 @@ use jsonrpc_core::*; pub trait Rpc: Sized + Send + Sync + 'static { /// Returns supported modules for Geth 1.3.6 - fn modules(&self, _: Params) -> Result { rpc_unimplemented!() } + fn modules(&self, _: Params) -> Result; /// Returns supported modules for Geth 1.4.0 - fn rpc_modules(&self, _: Params) -> Result { rpc_unimplemented!() } + fn rpc_modules(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { diff --git a/rpc/src/v1/traits/traces.rs b/rpc/src/v1/traits/traces.rs index b42feede5..54d04b954 100644 --- a/rpc/src/v1/traits/traces.rs +++ b/rpc/src/v1/traits/traces.rs @@ -21,16 +21,16 @@ use jsonrpc_core::*; /// Traces specific rpc interface. pub trait Traces: Sized + Send + Sync + 'static { /// Returns traces matching given filter. - fn filter(&self, _: Params) -> Result { rpc_unimplemented!() } + fn filter(&self, _: Params) -> Result; /// Returns transaction trace at given index. - fn trace(&self, _: Params) -> Result { rpc_unimplemented!() } + fn trace(&self, _: Params) -> Result; /// Returns all traces of given transaction. - fn transaction_traces(&self, _: Params) -> Result { rpc_unimplemented!() } + fn transaction_traces(&self, _: Params) -> Result; /// Returns all traces produced at given block. - fn block_traces(&self, _: Params) -> Result { rpc_unimplemented!() } + fn block_traces(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { diff --git a/rpc/src/v1/traits/web3.rs b/rpc/src/v1/traits/web3.rs index c7b21a1a1..335911025 100644 --- a/rpc/src/v1/traits/web3.rs +++ b/rpc/src/v1/traits/web3.rs @@ -21,10 +21,10 @@ use jsonrpc_core::*; /// Web3 rpc interface. pub trait Web3: Sized + Send + Sync + 'static { /// Returns current client version. - fn client_version(&self, _: Params) -> Result { rpc_unimplemented!() } + fn client_version(&self, _: Params) -> Result; /// Returns sha3 of the given data - fn sha3(&self, _: Params) -> Result { rpc_unimplemented!() } + fn sha3(&self, _: Params) -> Result; /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { From 191bae5cd47a1804a96b216fc61511239f37c05f Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sat, 28 May 2016 15:25:37 +0200 Subject: [PATCH 18/25] add stubs for missing eth_* rpc methods --- rpc/src/v1/impls/eth.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 7627dd61e..026459d9f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -494,6 +494,16 @@ impl Eth for EthClient where }) } + fn sign(&self, params: Params) -> Result { + from_params::<(Address, Bytes)>(params).and_then(|(addr, data)| { + let accounts = take_weak!(self.accounts); + match accounts.account_secret(&addr) { + Ok(secret) => rpc_unimplemented!(), + Err(_) => rpc_unimplemented!(), + } + }) + } + fn send_transaction(&self, params: Params) -> Result { from_params::<(TransactionRequest, )>(params) .and_then(|(request, )| { @@ -542,6 +552,18 @@ impl Eth for EthClient where to_value(&r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0))) }) } + + fn compile_lll(&self, _: params) -> Result { + rpc_unimplemented!() + } + + fn compile_serpent(&self, _: params) -> Result { + rpc_unimplemented!() + } + + fn compile_solidity(&self, _: params) -> Result { + rpc_unimplemented!() + } } /// Eth filter rpc implementation. From 7cea3eb5ed8757e816ad4afb6590fb7748ed51c9 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 29 May 2016 14:53:50 +0200 Subject: [PATCH 19/25] move rpc_unimplemented into impls module --- rpc/src/v1/impls/mod.rs | 4 ++++ rpc/src/v1/traits/mod.rs | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index b79772103..94b4fecc1 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -25,6 +25,10 @@ macro_rules! take_weak { } } +macro_rules! rpc_unimplemented { + () => (Err(Error::internal_error())) +} + mod web3; mod eth; mod net; diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs index bebf95bb7..0728fd06a 100644 --- a/rpc/src/v1/traits/mod.rs +++ b/rpc/src/v1/traits/mod.rs @@ -16,10 +16,6 @@ //! Ethereum rpc interfaces. -macro_rules! rpc_unimplemented { - () => (Err(Error::internal_error())) -} - pub mod web3; pub mod eth; pub mod net; From be1ec93271b5cefd9f4dd3c39d4b35c21da89b83 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 29 May 2016 15:46:57 +0200 Subject: [PATCH 20/25] implement eth_sign --- rpc/src/v1/impls/eth.rs | 16 ++++++---------- rpc/src/v1/tests/eth.rs | 2 +- rpc/src/v1/tests/mocked/eth.rs | 30 +++++++++++++++++++++++------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 026459d9f..100770ae1 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -27,6 +27,7 @@ use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; use util::rlp::{encode, decode, UntrustedRlp, View}; +use util::keys::store::AccountProvider; use ethcore::client::{BlockChainClient, BlockID, TransactionID, UncleID}; use ethcore::block::IsBlock; use ethcore::views::*; @@ -39,7 +40,6 @@ use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt}; use v1::helpers::{PollFilter, PollManager}; use v1::impls::{dispatch_transaction, sign_and_dispatch}; -use util::keys::store::AccountProvider; use serde; /// Eth rpc implementation. @@ -495,12 +495,8 @@ impl Eth for EthClient where } fn sign(&self, params: Params) -> Result { - from_params::<(Address, Bytes)>(params).and_then(|(addr, data)| { - let accounts = take_weak!(self.accounts); - match accounts.account_secret(&addr) { - Ok(secret) => rpc_unimplemented!(), - Err(_) => rpc_unimplemented!(), - } + from_params::<(Address, H256)>(params).and_then(|(addr, msg)| { + to_value(&take_weak!(self.accounts).sign(&addr, &msg).unwrap_or(H520::zero())) }) } @@ -553,15 +549,15 @@ impl Eth for EthClient where }) } - fn compile_lll(&self, _: params) -> Result { + fn compile_lll(&self, _: Params) -> Result { rpc_unimplemented!() } - fn compile_serpent(&self, _: params) -> Result { + fn compile_serpent(&self, _: Params) -> Result { rpc_unimplemented!() } - fn compile_solidity(&self, _: params) -> Result { + fn compile_solidity(&self, _: Params) -> Result { rpc_unimplemented!() } } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index eac5bafcb..80a856aca 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -27,7 +27,7 @@ use ethcore::transaction::{Transaction, Action}; use ethminer::{MinerService, ExternalMiner}; use devtools::RandomTempPath; use util::io::IoChannel; -use util::hash::{Address, FixedHash}; +use util::hash::Address; use util::numbers::{Uint, U256}; use util::keys::{AccountProvider, TestAccount, TestAccountProvider}; use jsonrpc_core::IoHandler; diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 32a2cd99a..9f6f9881f 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -20,7 +20,7 @@ use std::sync::{Arc, RwLock}; use jsonrpc_core::IoHandler; use util::hash::{Address, H256, FixedHash}; use util::numbers::{Uint, U256}; -use util::keys::{TestAccount, TestAccountProvider}; +use util::keys::{AccountProvider, TestAccount, TestAccountProvider}; use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionID}; use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::receipt::LocalizedReceipt; @@ -129,6 +129,28 @@ fn rpc_eth_submit_hashrate() { Some(U256::from(0x500_000))); } +#[test] +fn rpc_eth_sign() { + let tester = EthTester::default(); + + let account = tester.accounts_provider.new_account("abcd").unwrap(); + let message = H256::from("0x0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f"); + let signed = tester.accounts_provider.sign(&account, &message).unwrap(); + + let req = r#"{ + "jsonrpc": "2.0", + "method": "eth_sign", + "params": [ + ""#.to_owned() + &format!("0x{:?}", account) + r#"", + "0x0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f" + ], + "id": 1 + }"#; + let res = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", signed) + r#"","id":1}"#; + + assert_eq!(tester.io.handle_request(&req), Some(res)); +} + #[test] #[ignore] fn rpc_eth_author() { @@ -527,12 +549,6 @@ fn rpc_eth_send_raw_transaction() { unimplemented!() } -#[test] -#[ignore] -fn rpc_eth_sign() { - unimplemented!() -} - #[test] fn rpc_eth_transaction_receipt() { let receipt = LocalizedReceipt { From 89659606dd9a98ccbef87db96d63439ea388de1c Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 29 May 2016 17:07:39 +0200 Subject: [PATCH 21/25] add mocked test for eth_sendRawTransaction --- rpc/src/v1/impls/mod.rs | 22 ++++++----------- rpc/src/v1/tests/mocked/eth.rs | 44 ++++++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 94b4fecc1..7ee8b8b8a 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -59,22 +59,14 @@ fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedT where C: BlockChainClient, M: MinerService { let hash = signed_transaction.hash(); - let import = { - miner.import_own_transaction(client, signed_transaction, |a: &Address| { - AccountDetails { - nonce: client.latest_nonce(&a), - balance: client.latest_balance(&a), - } - }) - }; - - match import { - Ok(_) => to_value(&hash), - Err(e) => { - warn!("Error sending transaction: {:?}", e); - to_value(&H256::zero()) + let import = miner.import_own_transaction(client, signed_transaction, |a: &Address| { + AccountDetails { + nonce: client.latest_nonce(&a), + balance: client.latest_balance(&a), } - } + }); + + to_value(&import.map(|_| hash).unwrap_or(H256::zero())) } fn sign_and_dispatch(client: &Weak, miner: &Weak, request: TransactionRequest, secret: H256) -> Result diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 9f6f9881f..031616450 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -28,6 +28,7 @@ use ethcore::transaction::{Transaction, Action}; use ethminer::ExternalMiner; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; +use rustc_serialize::hex::ToHex; fn blockchain_client() -> Arc { let client = TestBlockChainClient::new(); @@ -215,18 +216,22 @@ fn rpc_eth_balance() { assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } -#[ignore] //TODO: propert test #[test] fn rpc_eth_balance_pending() { let tester = EthTester::default(); + tester.client.set_balance(Address::from(1), U256::from(5)); let request = r#"{ "jsonrpc": "2.0", "method": "eth_getBalance", - "params": ["0x0000000000000000000000000000000000000001", "latest"], + "params": ["0x0000000000000000000000000000000000000001", "pending"], "id": 1 }"#; - let response = r#"{"jsonrpc":"2.0","result":"0x","id":1}"#; + + // the TestMinerService doesn't communicate with the the TestBlockChainClient in any way. + // if this returns zero, we know that the "pending" call is being properly forwarded to the + // miner. + let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#; assert_eq!(tester.io.handle_request(request), Some(response.to_owned())); } @@ -525,7 +530,7 @@ fn rpc_eth_send_transaction() { let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; - assert_eq!(tester.io.handle_request(request.as_ref()), Some(response)); + assert_eq!(tester.io.handle_request(&request), Some(response)); tester.miner.last_nonces.write().unwrap().insert(address.clone(), U256::zero()); @@ -540,13 +545,38 @@ fn rpc_eth_send_transaction() { let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; - assert_eq!(tester.io.handle_request(request.as_ref()), Some(response)); + assert_eq!(tester.io.handle_request(&request), Some(response)); } #[test] -#[ignore] fn rpc_eth_send_raw_transaction() { - unimplemented!() + let tester = EthTester::default(); + let address = tester.accounts_provider.new_account("abcd").unwrap(); + let secret = tester.accounts_provider.account_secret(&address).unwrap(); + + let t = Transaction { + nonce: U256::zero(), + gas_price: U256::from(0x9184e72a000u64), + gas: U256::from(0x76c0), + action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + value: U256::from(0x9184e72au64), + data: vec![] + }.sign(&secret); + + let rlp = ::util::rlp::encode(&t).to_vec().to_hex(); + + let req = r#"{ + "jsonrpc": "2.0", + "method": "eth_sendRawTransaction", + "params": [ + "0x"#.to_owned() + &rlp + r#"" + ], + "id": 1 + }"#; + + let res = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", t.hash()) + r#"","id":1}"#; + + assert_eq!(tester.io.handle_request(&req), Some(res)); } #[test] From bbe6a287f896f327c5eb475cd8444725b50be7c4 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Sun, 29 May 2016 17:18:37 +0200 Subject: [PATCH 22/25] add mocked test for eth_coinbase --- rpc/src/v1/tests/mocked/eth.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 031616450..06f1d97b3 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -25,7 +25,7 @@ use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, Transaction use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::receipt::LocalizedReceipt; use ethcore::transaction::{Transaction, Action}; -use ethminer::ExternalMiner; +use ethminer::{ExternalMiner, MinerService}; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; use rustc_serialize::hex::ToHex; @@ -153,9 +153,25 @@ fn rpc_eth_sign() { } #[test] -#[ignore] fn rpc_eth_author() { - unimplemented!() + let make_res = |addr| r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", addr) + r#"","id":1}"#; + let tester = EthTester::default(); + + let req = r#"{ + "jsonrpc": "2.0", + "method": "eth_coinbase", + "params": [], + "id": 1 + }"#; + + assert_eq!(tester.io.handle_request(req), Some(make_res(Address::zero()))); + + for i in 0..20 { + let addr = tester.accounts_provider.new_account(&format!("{}", i)).unwrap(); + tester.miner.set_author(addr.clone()); + + assert_eq!(tester.io.handle_request(req), Some(make_res(addr))); + } } #[test] From ea26deaab142f04940076f5087f857b47c50d441 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 30 May 2016 12:33:49 +0200 Subject: [PATCH 23/25] mocked test for eth_syncing --- rpc/src/v1/tests/mocked/eth.rs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 06f1d97b3..aa0955751 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -26,6 +26,7 @@ use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::receipt::LocalizedReceipt; use ethcore::transaction::{Transaction, Action}; use ethminer::{ExternalMiner, MinerService}; +use ethsync::SyncState; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService}; use rustc_serialize::hex::ToHex; @@ -93,9 +94,28 @@ fn rpc_eth_protocol_version() { } #[test] -#[ignore] fn rpc_eth_syncing() { - unimplemented!() + let request = r#"{"jsonrpc": "2.0", "method": "eth_syncing", "params": [], "id": 1}"#; + + let tester = EthTester::default(); + + let false_res = r#"{"jsonrpc":"2.0","result":false,"id":1}"#; + assert_eq!(tester.io.handle_request(request), Some(false_res.to_owned())); + + { + let mut status = tester.sync.status.write().unwrap(); + status.state = SyncState::Blocks; + status.highest_block_number = Some(2500); + + // causes TestBlockChainClient to return 1000 for its best block number. + let mut blocks = tester.client.blocks.write().unwrap(); + for i in 0..1000 { + blocks.insert(H256::from(i), Vec::new()); + } + } + + let true_res = r#"{"jsonrpc":"2.0","result":{"currentBlock":"0x03e8","highestBlock":"0x09c4","startingBlock":"0x00"},"id":1}"#; + assert_eq!(tester.io.handle_request(request), Some(true_res.to_owned())); } #[test] From 16432129b580635ef6c2380c1f916666d975259c Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 30 May 2016 13:13:48 +0200 Subject: [PATCH 24/25] move transaction import error warning into miner implementation --- miner/src/miner.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 3860a79e6..fc63aec6c 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -395,6 +395,7 @@ impl MinerService for Miner { Err(ref e) => { trace!(target: "own_tx", "Failed to import transaction {:?} (hash: {:?})", e, hash); trace!(target: "own_tx", "Status: {:?}", transaction_queue.status()); + warn!(target: "own_tx", "Error importing transaction: {:?}", e); }, } import From 76bb0729ba7cc1e3d296343d434218f45ed68155 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 30 May 2016 15:38:23 +0200 Subject: [PATCH 25/25] Updated dependencies for windows build --- Cargo.lock | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5dff43d04..38c3c45a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -299,7 +299,7 @@ version = "1.2.0" dependencies = [ "ethcore-devtools 1.2.0", "ethcore-util 1.2.0", - "nanomsg 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)", + "nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)", "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -321,7 +321,7 @@ dependencies = [ "ethcore-ipc 1.2.0", "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "nanomsg 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)", + "nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)", ] [[package]] @@ -389,7 +389,7 @@ dependencies = [ "mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rocksdb 0.4.3 (git+https://github.com/ethcore/rust-rocksdb)", + "rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)", "rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -659,14 +659,6 @@ name = "libc" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "librocksdb-sys" -version = "0.2.3" -source = "git+https://github.com/ethcore/rust-rocksdb#6b6ce93e2828182691e00da57fdfb2926226f1f1" -dependencies = [ - "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "log" version = "0.3.6" @@ -742,8 +734,8 @@ dependencies = [ [[package]] name = "nanomsg" -version = "0.5.0" -source = "git+https://github.com/ethcore/nanomsg.rs.git#9c81fb3b0f71714b173d0abf14bfd30addf8c7b1" +version = "0.5.1" +source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00" dependencies = [ "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)", @@ -752,7 +744,7 @@ dependencies = [ [[package]] name = "nanomsg-sys" version = "0.5.0" -source = "git+https://github.com/ethcore/nanomsg.rs.git#9c81fb3b0f71714b173d0abf14bfd30addf8c7b1" +source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00" dependencies = [ "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1073,11 +1065,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rocksdb" -version = "0.4.3" -source = "git+https://github.com/ethcore/rust-rocksdb#6b6ce93e2828182691e00da57fdfb2926226f1f1" +version = "0.4.5" +source = "git+https://github.com/ethcore/rust-rocksdb#9140e37ce0fdb748097f85653c01b0f7e3736ea9" dependencies = [ "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "librocksdb-sys 0.2.3 (git+https://github.com/ethcore/rust-rocksdb)", + "rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)", +] + +[[package]] +name = "rocksdb-sys" +version = "0.3.0" +source = "git+https://github.com/ethcore/rust-rocksdb#9140e37ce0fdb748097f85653c01b0f7e3736ea9" +dependencies = [ + "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]]