diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs
index 140b8d91f..55c473d1e 100644
--- a/ethcore/src/client/test_client.rs
+++ b/ethcore/src/client/test_client.rs
@@ -87,22 +87,22 @@ impl TestBlockChainClient {
}
/// Set the balance of account `address` to `balance`.
- pub fn set_balance(&mut self, address: Address, balance: U256) {
+ pub fn set_balance(&self, address: Address, balance: U256) {
self.balances.write().unwrap().insert(address, balance);
}
/// Set `code` at `address`.
- pub fn set_code(&mut self, address: Address, code: Bytes) {
+ pub fn set_code(&self, address: Address, code: Bytes) {
self.code.write().unwrap().insert(address, code);
}
/// Set storage `position` to `value` for account `address`.
- pub fn set_storage(&mut self, address: Address, position: H256, value: H256) {
+ pub fn set_storage(&self, address: Address, position: H256, value: H256) {
self.storage.write().unwrap().insert((address, position), value);
}
/// Add blocks to test client.
- pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) {
+ pub fn add_blocks(&self, count: usize, with: EachBlockWith) {
let len = self.numbers.read().unwrap().len();
for n in len..(len + count) {
let mut header = BlockHeader::new();
diff --git a/rpc/src/v1/helpers/external_miner.rs b/rpc/src/v1/helpers/external_miner.rs
new file mode 100644
index 000000000..4cbda8928
--- /dev/null
+++ b/rpc/src/v1/helpers/external_miner.rs
@@ -0,0 +1,59 @@
+// 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 std::collections::HashMap;
+use std::sync::RwLock;
+use util::numbers::U256;
+use util::hash::H256;
+
+/// External miner interface.
+pub trait ExternalMinerService: Send + Sync {
+ /// Submit hashrate for given miner.
+ fn submit_hashrate(&self, hashrate: U256, id: H256);
+
+ /// Total hashrate.
+ fn hashrate(&self) -> U256;
+
+ /// Returns true if external miner is mining.
+ fn is_mining(&self) -> bool;
+}
+
+/// External Miner.
+pub struct ExternalMiner {
+ hashrates: RwLock>,
+}
+
+impl Default for ExternalMiner {
+ fn default() -> Self {
+ ExternalMiner {
+ hashrates: RwLock::new(HashMap::new()),
+ }
+ }
+}
+
+impl ExternalMinerService for ExternalMiner {
+ fn submit_hashrate(&self, hashrate: U256, id: H256) {
+ self.hashrates.write().unwrap().insert(id, hashrate);
+ }
+
+ fn hashrate(&self) -> U256 {
+ self.hashrates.read().unwrap().iter().fold(U256::from(0), |sum, (_, v)| sum + *v)
+ }
+
+ fn is_mining(&self) -> bool {
+ !self.hashrates.read().unwrap().is_empty()
+ }
+}
diff --git a/rpc/src/v1/helpers/mod.rs b/rpc/src/v1/helpers/mod.rs
index b1a5c05ba..8c574cff6 100644
--- a/rpc/src/v1/helpers/mod.rs
+++ b/rpc/src/v1/helpers/mod.rs
@@ -16,6 +16,8 @@
mod poll_manager;
mod poll_filter;
+pub mod external_miner;
pub use self::poll_manager::PollManager;
pub use self::poll_filter::PollFilter;
+pub use self::external_miner::{ExternalMinerService, ExternalMiner};
diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs
index 0e8b8d863..9ceea2e25 100644
--- a/rpc/src/v1/impls/eth.rs
+++ b/rpc/src/v1/impls/eth.rs
@@ -15,8 +15,8 @@
// along with Parity. If not, see .
//! Eth rpc implementation.
-use std::collections::{HashMap, HashSet};
-use std::sync::{Arc, Weak, Mutex, RwLock};
+use std::collections::HashSet;
+use std::sync::{Arc, Weak, Mutex};
use std::ops::Deref;
use ethsync::{SyncProvider, SyncState};
use ethminer::{MinerService};
@@ -25,42 +25,59 @@ use util::numbers::*;
use util::sha3::*;
use util::rlp::encode;
use ethcore::client::*;
-use ethcore::block::{IsBlock};
+use ethcore::block::IsBlock;
use ethcore::views::*;
use ethcore::ethereum::Ethash;
use ethcore::ethereum::denominations::shannon;
use ethcore::transaction::Transaction as EthTransaction;
use v1::traits::{Eth, EthFilter};
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log};
-use v1::helpers::{PollFilter, PollManager};
+use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner};
use util::keys::store::AccountProvider;
/// Eth rpc implementation.
-pub struct EthClient
+pub struct EthClient
where C: BlockChainClient,
S: SyncProvider,
A: AccountProvider,
- M: MinerService {
+ M: MinerService,
+ EM: ExternalMinerService {
client: Weak,
sync: Weak,
accounts: Weak,
miner: Weak,
- hashrates: RwLock>,
+ external_miner: EM,
}
-impl EthClient
+impl EthClient
where C: BlockChainClient,
S: SyncProvider,
A: AccountProvider,
M: MinerService {
+
/// Creates new EthClient.
pub fn new(client: &Arc, sync: &Arc, accounts: &Arc, miner: &Arc) -> Self {
+ EthClient::new_with_external_miner(client, sync, accounts, miner, ExternalMiner::default())
+ }
+}
+
+
+impl EthClient
+ where C: BlockChainClient,
+ S: SyncProvider,
+ A: AccountProvider,
+ M: MinerService,
+ EM: ExternalMinerService {
+
+ /// Creates new EthClient with custom external miner.
+ pub fn new_with_external_miner(client: &Arc, sync: &Arc, accounts: &Arc, miner: &Arc, em: EM)
+ -> EthClient {
EthClient {
client: Arc::downgrade(client),
sync: Arc::downgrade(sync),
miner: Arc::downgrade(miner),
accounts: Arc::downgrade(accounts),
- hashrates: RwLock::new(HashMap::new()),
+ external_miner: em,
}
}
@@ -110,11 +127,12 @@ impl EthClient
}
}
-impl Eth for EthClient
+impl Eth for EthClient
where C: BlockChainClient + 'static,
S: SyncProvider + 'static,
A: AccountProvider + 'static,
- M: MinerService + 'static {
+ M: MinerService + 'static,
+ EM: ExternalMinerService + 'static {
fn protocol_version(&self, params: Params) -> Result {
match params {
@@ -152,7 +170,7 @@ impl Eth for EthClient
// TODO: return real value of mining once it's implemented.
fn is_mining(&self, params: Params) -> Result {
match params {
- Params::None => to_value(&!self.hashrates.read().unwrap().is_empty()),
+ Params::None => to_value(&self.external_miner.is_mining()),
_ => Err(Error::invalid_params())
}
}
@@ -160,7 +178,7 @@ impl Eth for EthClient
// TODO: return real hashrate once we have mining
fn hashrate(&self, params: Params) -> Result {
match params {
- Params::None => to_value(&self.hashrates.read().unwrap().iter().fold(0u64, |sum, (_, v)| sum + v)),
+ Params::None => to_value(&self.external_miner.hashrate()),
_ => Err(Error::invalid_params())
}
}
@@ -318,8 +336,8 @@ impl Eth for EthClient
fn submit_hashrate(&self, params: Params) -> Result {
// TODO: Index should be U256.
- from_params::<(Index, H256)>(params).and_then(|(rate, id)| {
- self.hashrates.write().unwrap().insert(id, rate.value() as u64);
+ from_params::<(U256, H256)>(params).and_then(|(rate, id)| {
+ self.external_miner.submit_hashrate(rate, id);
to_value(&true)
})
}
diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs
index 35c227e40..e07390165 100644
--- a/rpc/src/v1/tests/eth.rs
+++ b/rpc/src/v1/tests/eth.rs
@@ -15,20 +15,16 @@
// along with Parity. If not, see .
use std::collections::HashMap;
-use std::sync::Arc;
+use std::sync::{Arc, RwLock};
use jsonrpc_core::IoHandler;
use util::hash::{Address, H256};
use util::numbers::U256;
use ethcore::client::{TestBlockChainClient, EachBlockWith};
use v1::{Eth, EthClient};
-use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService};
+use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner};
fn blockchain_client() -> Arc {
- let mut client = TestBlockChainClient::new();
- client.add_blocks(10, EachBlockWith::Nothing);
- client.set_balance(Address::from(1), U256::from(5));
- client.set_storage(Address::from(1), H256::from(4), H256::from(7));
- client.set_code(Address::from(1), vec![0xff, 0x21]);
+ let client = TestBlockChainClient::new();
Arc::new(client)
}
@@ -51,10 +47,11 @@ fn miner_service() -> Arc {
}
struct EthTester {
- _client: Arc,
+ client: Arc,
_sync: Arc,
_accounts_provider: Arc,
_miner: Arc,
+ hashrates: Arc>>,
pub io: IoHandler,
}
@@ -64,15 +61,18 @@ impl Default for EthTester {
let sync = sync_provider();
let ap = accounts_provider();
let miner = miner_service();
- let eth = EthClient::new(&client, &sync, &ap, &miner).to_delegate();
+ let hashrates = Arc::new(RwLock::new(HashMap::new()));
+ let external_miner = TestExternalMiner::new(hashrates.clone());
+ let eth = EthClient::new_with_external_miner(&client, &sync, &ap, &miner, external_miner).to_delegate();
let io = IoHandler::new();
io.add_delegate(eth);
EthTester {
- _client: client,
+ client: client,
_sync: sync,
_accounts_provider: ap,
_miner: miner,
- io: io
+ io: io,
+ hashrates: hashrates,
}
}
}
@@ -92,9 +92,35 @@ fn rpc_eth_syncing() {
}
#[test]
-#[ignore]
fn rpc_eth_hashrate() {
- unimplemented!()
+ let tester = EthTester::default();
+ tester.hashrates.write().unwrap().insert(H256::from(0), U256::from(0xfffa));
+ tester.hashrates.write().unwrap().insert(H256::from(0), U256::from(0xfffb));
+ tester.hashrates.write().unwrap().insert(H256::from(1), U256::from(0x1));
+
+ let request = r#"{"jsonrpc": "2.0", "method": "eth_hashrate", "params": [], "id": 1}"#;
+ let response = r#"{"jsonrpc":"2.0","result":"0xfffc","id":1}"#;
+
+ assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
+}
+
+#[test]
+fn rpc_eth_submit_hashrate() {
+ let tester = EthTester::default();
+
+ let request = r#"{
+ "jsonrpc": "2.0",
+ "method": "eth_submitHashrate",
+ "params": [
+ "0x0000000000000000000000000000000000000000000000000000000000500000",
+ "0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c"],
+ "id": 1
+ }"#;
+ let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
+
+ assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
+ assert_eq!(tester.hashrates.read().unwrap().get(&H256::from("0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c")).cloned(),
+ Some(U256::from(0x500_000)));
}
#[test]
@@ -127,14 +153,20 @@ fn rpc_eth_accounts() {
#[test]
fn rpc_eth_block_number() {
+ let tester = EthTester::default();
+ tester.client.add_blocks(10, EachBlockWith::Nothing);
+
let request = r#"{"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x0a","id":1}"#;
- assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned()));
+ assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
}
#[test]
fn rpc_eth_balance() {
+ let tester = EthTester::default();
+ tester.client.set_balance(Address::from(1), U256::from(5));
+
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_getBalance",
@@ -143,11 +175,14 @@ fn rpc_eth_balance() {
}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x05","id":1}"#;
- assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned()));
+ assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
}
#[test]
fn rpc_eth_storage_at() {
+ let tester = EthTester::default();
+ tester.client.set_storage(Address::from(1), H256::from(4), H256::from(7));
+
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_getStorageAt",
@@ -156,7 +191,7 @@ fn rpc_eth_storage_at() {
}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x07","id":1}"#;
- assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned()));
+ assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
}
#[test]
@@ -226,6 +261,9 @@ fn rpc_eth_uncle_count_by_block_number() {
#[test]
fn rpc_eth_code() {
+ let tester = EthTester::default();
+ tester.client.set_code(Address::from(1), vec![0xff, 0x21]);
+
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_getCode",
@@ -234,7 +272,7 @@ fn rpc_eth_code() {
}"#;
let response = r#"{"jsonrpc":"2.0","result":"0xff21","id":1}"#;
- assert_eq!(EthTester::default().io.handle_request(request), Some(response.to_owned()));
+ assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
}
#[test]
diff --git a/rpc/src/v1/tests/helpers/external_miner.rs b/rpc/src/v1/tests/helpers/external_miner.rs
new file mode 100644
index 000000000..a5111b302
--- /dev/null
+++ b/rpc/src/v1/tests/helpers/external_miner.rs
@@ -0,0 +1,48 @@
+// 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 std::collections::HashMap;
+use std::sync::{Arc, RwLock};
+use util::numbers::U256;
+use util::hash::H256;
+use v1::helpers::ExternalMinerService;
+
+/// Test ExternalMinerService;
+pub struct TestExternalMiner {
+ pub hashrates: Arc>>
+}
+
+impl TestExternalMiner {
+ pub fn new(hashrates: Arc>>) -> Self {
+ TestExternalMiner {
+ hashrates: hashrates,
+ }
+ }
+}
+
+impl ExternalMinerService for TestExternalMiner {
+ fn submit_hashrate(&self, hashrate: U256, id: H256) {
+ self.hashrates.write().unwrap().insert(id, hashrate);
+ }
+
+ fn hashrate(&self) -> U256 {
+ self.hashrates.read().unwrap().iter().fold(U256::from(0), |sum, (_, v)| sum + *v)
+ }
+
+ fn is_mining(&self) -> bool {
+ !self.hashrates.read().unwrap().is_empty()
+ }
+}
diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs
index fc429982e..fc652e7d6 100644
--- a/rpc/src/v1/tests/helpers/mod.rs
+++ b/rpc/src/v1/tests/helpers/mod.rs
@@ -17,7 +17,9 @@
mod account_provider;
mod sync_provider;
mod miner_service;
+mod external_miner;
pub use self::account_provider::{TestAccount, TestAccountProvider};
pub use self::sync_provider::{Config, TestSyncProvider};
pub use self::miner_service::{TestMinerService};
+pub use self::external_miner::TestExternalMiner;