eth_hashrate && eth_submitHashrate tests

This commit is contained in:
debris 2016-03-14 14:18:29 +01:00
parent acd39843d4
commit 0de73609d2
7 changed files with 203 additions and 36 deletions

View File

@ -87,22 +87,22 @@ impl TestBlockChainClient {
} }
/// Set the balance of account `address` to `balance`. /// 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); self.balances.write().unwrap().insert(address, balance);
} }
/// Set `code` at `address`. /// 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); self.code.write().unwrap().insert(address, code);
} }
/// Set storage `position` to `value` for account `address`. /// 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); self.storage.write().unwrap().insert((address, position), value);
} }
/// Add blocks to test client. /// 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(); let len = self.numbers.read().unwrap().len();
for n in len..(len + count) { for n in len..(len + count) {
let mut header = BlockHeader::new(); let mut header = BlockHeader::new();

View File

@ -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 <http://www.gnu.org/licenses/>.
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<HashMap<H256, U256>>,
}
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()
}
}

View File

@ -16,6 +16,8 @@
mod poll_manager; mod poll_manager;
mod poll_filter; mod poll_filter;
pub mod external_miner;
pub use self::poll_manager::PollManager; pub use self::poll_manager::PollManager;
pub use self::poll_filter::PollFilter; pub use self::poll_filter::PollFilter;
pub use self::external_miner::{ExternalMinerService, ExternalMiner};

View File

@ -15,8 +15,8 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Eth rpc implementation. //! Eth rpc implementation.
use std::collections::{HashMap, HashSet}; use std::collections::HashSet;
use std::sync::{Arc, Weak, Mutex, RwLock}; use std::sync::{Arc, Weak, Mutex};
use std::ops::Deref; use std::ops::Deref;
use ethsync::{SyncProvider, SyncState}; use ethsync::{SyncProvider, SyncState};
use ethminer::{MinerService}; use ethminer::{MinerService};
@ -25,42 +25,59 @@ use util::numbers::*;
use util::sha3::*; use util::sha3::*;
use util::rlp::encode; use util::rlp::encode;
use ethcore::client::*; use ethcore::client::*;
use ethcore::block::{IsBlock}; use ethcore::block::IsBlock;
use ethcore::views::*; use ethcore::views::*;
use ethcore::ethereum::Ethash; use ethcore::ethereum::Ethash;
use ethcore::ethereum::denominations::shannon; use ethcore::ethereum::denominations::shannon;
use ethcore::transaction::Transaction as EthTransaction; use ethcore::transaction::Transaction as EthTransaction;
use v1::traits::{Eth, EthFilter}; use v1::traits::{Eth, EthFilter};
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log}; 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; use util::keys::store::AccountProvider;
/// Eth rpc implementation. /// Eth rpc implementation.
pub struct EthClient<C, S, A, M> pub struct EthClient<C, S, A, M, EM = ExternalMiner>
where C: BlockChainClient, where C: BlockChainClient,
S: SyncProvider, S: SyncProvider,
A: AccountProvider, A: AccountProvider,
M: MinerService { M: MinerService,
EM: ExternalMinerService {
client: Weak<C>, client: Weak<C>,
sync: Weak<S>, sync: Weak<S>,
accounts: Weak<A>, accounts: Weak<A>,
miner: Weak<M>, miner: Weak<M>,
hashrates: RwLock<HashMap<H256, u64>>, external_miner: EM,
} }
impl<C, S, A, M> EthClient<C, S, A, M> impl<C, S, A, M> EthClient<C, S, A, M, ExternalMiner>
where C: BlockChainClient, where C: BlockChainClient,
S: SyncProvider, S: SyncProvider,
A: AccountProvider, A: AccountProvider,
M: MinerService { M: MinerService {
/// Creates new EthClient. /// Creates new EthClient.
pub fn new(client: &Arc<C>, sync: &Arc<S>, accounts: &Arc<A>, miner: &Arc<M>) -> Self { pub fn new(client: &Arc<C>, sync: &Arc<S>, accounts: &Arc<A>, miner: &Arc<M>) -> Self {
EthClient::new_with_external_miner(client, sync, accounts, miner, ExternalMiner::default())
}
}
impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
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<C>, sync: &Arc<S>, accounts: &Arc<A>, miner: &Arc<M>, em: EM)
-> EthClient<C, S, A, M, EM> {
EthClient { EthClient {
client: Arc::downgrade(client), client: Arc::downgrade(client),
sync: Arc::downgrade(sync), sync: Arc::downgrade(sync),
miner: Arc::downgrade(miner), miner: Arc::downgrade(miner),
accounts: Arc::downgrade(accounts), accounts: Arc::downgrade(accounts),
hashrates: RwLock::new(HashMap::new()), external_miner: em,
} }
} }
@ -110,11 +127,12 @@ impl<C, S, A, M> EthClient<C, S, A, M>
} }
} }
impl<C, S, A, M> Eth for EthClient<C, S, A, M> impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
where C: BlockChainClient + 'static, where C: BlockChainClient + 'static,
S: SyncProvider + 'static, S: SyncProvider + 'static,
A: AccountProvider + 'static, A: AccountProvider + 'static,
M: MinerService + 'static { M: MinerService + 'static,
EM: ExternalMinerService + 'static {
fn protocol_version(&self, params: Params) -> Result<Value, Error> { fn protocol_version(&self, params: Params) -> Result<Value, Error> {
match params { match params {
@ -152,7 +170,7 @@ impl<C, S, A, M> Eth for EthClient<C, S, A, M>
// TODO: return real value of mining once it's implemented. // TODO: return real value of mining once it's implemented.
fn is_mining(&self, params: Params) -> Result<Value, Error> { fn is_mining(&self, params: Params) -> Result<Value, Error> {
match params { 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()) _ => Err(Error::invalid_params())
} }
} }
@ -160,7 +178,7 @@ impl<C, S, A, M> Eth for EthClient<C, S, A, M>
// TODO: return real hashrate once we have mining // TODO: return real hashrate once we have mining
fn hashrate(&self, params: Params) -> Result<Value, Error> { fn hashrate(&self, params: Params) -> Result<Value, Error> {
match params { 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()) _ => Err(Error::invalid_params())
} }
} }
@ -318,8 +336,8 @@ impl<C, S, A, M> Eth for EthClient<C, S, A, M>
fn submit_hashrate(&self, params: Params) -> Result<Value, Error> { fn submit_hashrate(&self, params: Params) -> Result<Value, Error> {
// TODO: Index should be U256. // TODO: Index should be U256.
from_params::<(Index, H256)>(params).and_then(|(rate, id)| { from_params::<(U256, H256)>(params).and_then(|(rate, id)| {
self.hashrates.write().unwrap().insert(id, rate.value() as u64); self.external_miner.submit_hashrate(rate, id);
to_value(&true) to_value(&true)
}) })
} }

View File

@ -15,20 +15,16 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::{Arc, RwLock};
use jsonrpc_core::IoHandler; use jsonrpc_core::IoHandler;
use util::hash::{Address, H256}; use util::hash::{Address, H256};
use util::numbers::U256; use util::numbers::U256;
use ethcore::client::{TestBlockChainClient, EachBlockWith}; use ethcore::client::{TestBlockChainClient, EachBlockWith};
use v1::{Eth, EthClient}; 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<TestBlockChainClient> { fn blockchain_client() -> Arc<TestBlockChainClient> {
let mut client = TestBlockChainClient::new(); let 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]);
Arc::new(client) Arc::new(client)
} }
@ -51,10 +47,11 @@ fn miner_service() -> Arc<TestMinerService> {
} }
struct EthTester { struct EthTester {
_client: Arc<TestBlockChainClient>, client: Arc<TestBlockChainClient>,
_sync: Arc<TestSyncProvider>, _sync: Arc<TestSyncProvider>,
_accounts_provider: Arc<TestAccountProvider>, _accounts_provider: Arc<TestAccountProvider>,
_miner: Arc<TestMinerService>, _miner: Arc<TestMinerService>,
hashrates: Arc<RwLock<HashMap<H256, U256>>>,
pub io: IoHandler, pub io: IoHandler,
} }
@ -64,15 +61,18 @@ impl Default for EthTester {
let sync = sync_provider(); let sync = sync_provider();
let ap = accounts_provider(); let ap = accounts_provider();
let miner = miner_service(); 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(); let io = IoHandler::new();
io.add_delegate(eth); io.add_delegate(eth);
EthTester { EthTester {
_client: client, client: client,
_sync: sync, _sync: sync,
_accounts_provider: ap, _accounts_provider: ap,
_miner: miner, _miner: miner,
io: io io: io,
hashrates: hashrates,
} }
} }
} }
@ -92,9 +92,35 @@ fn rpc_eth_syncing() {
} }
#[test] #[test]
#[ignore]
fn rpc_eth_hashrate() { 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] #[test]
@ -127,14 +153,20 @@ fn rpc_eth_accounts() {
#[test] #[test]
fn rpc_eth_block_number() { 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 request = r#"{"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x0a","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] #[test]
fn rpc_eth_balance() { fn rpc_eth_balance() {
let tester = EthTester::default();
tester.client.set_balance(Address::from(1), U256::from(5));
let request = r#"{ let request = r#"{
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "eth_getBalance", "method": "eth_getBalance",
@ -143,11 +175,14 @@ fn rpc_eth_balance() {
}"#; }"#;
let response = r#"{"jsonrpc":"2.0","result":"0x05","id":1}"#; 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] #[test]
fn rpc_eth_storage_at() { 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#"{ let request = r#"{
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "eth_getStorageAt", "method": "eth_getStorageAt",
@ -156,7 +191,7 @@ fn rpc_eth_storage_at() {
}"#; }"#;
let response = r#"{"jsonrpc":"2.0","result":"0x07","id":1}"#; 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] #[test]
@ -226,6 +261,9 @@ fn rpc_eth_uncle_count_by_block_number() {
#[test] #[test]
fn rpc_eth_code() { fn rpc_eth_code() {
let tester = EthTester::default();
tester.client.set_code(Address::from(1), vec![0xff, 0x21]);
let request = r#"{ let request = r#"{
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "eth_getCode", "method": "eth_getCode",
@ -234,7 +272,7 @@ fn rpc_eth_code() {
}"#; }"#;
let response = r#"{"jsonrpc":"2.0","result":"0xff21","id":1}"#; 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] #[test]

View File

@ -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 <http://www.gnu.org/licenses/>.
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<RwLock<HashMap<H256, U256>>>
}
impl TestExternalMiner {
pub fn new(hashrates: Arc<RwLock<HashMap<H256, U256>>>) -> 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()
}
}

View File

@ -17,7 +17,9 @@
mod account_provider; mod account_provider;
mod sync_provider; mod sync_provider;
mod miner_service; mod miner_service;
mod external_miner;
pub use self::account_provider::{TestAccount, TestAccountProvider}; pub use self::account_provider::{TestAccount, TestAccountProvider};
pub use self::sync_provider::{Config, TestSyncProvider}; pub use self::sync_provider::{Config, TestSyncProvider};
pub use self::miner_service::{TestMinerService}; pub use self::miner_service::{TestMinerService};
pub use self::external_miner::TestExternalMiner;