Merge branch 'ethminer_crate' into rpc_pending_filter

Conflicts:
	miner/src/miner.rs
	parity/main.rs
This commit is contained in:
Tomasz Drwięga
2016-03-11 19:27:09 +01:00
61 changed files with 1393 additions and 893 deletions

View File

@@ -19,6 +19,8 @@
#![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))]
#![cfg_attr(feature="nightly", plugin(serde_macros, clippy))]
#[macro_use]
extern crate log;
extern crate rustc_serialize;
extern crate serde;
extern crate serde_json;

View File

@@ -29,31 +29,37 @@ 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, 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 util::keys::store::AccountProvider;
/// Eth rpc implementation.
pub struct EthClient<C, S, M>
pub struct EthClient<C, S, A, M>
where C: BlockChainClient,
S: SyncProvider,
A: AccountProvider,
M: MinerService {
client: Weak<C>,
sync: Weak<S>,
accounts: Weak<A>,
miner: Weak<M>,
hashrates: RwLock<HashMap<H256, u64>>,
}
impl<C, S, M> EthClient<C, S, M>
impl<C, S, A, M> EthClient<C, S, A, M>
where C: BlockChainClient,
S: SyncProvider,
A: AccountProvider,
M: MinerService {
/// Creates new EthClient.
pub fn new(client: &Arc<C>, sync: &Arc<S>, miner: &Arc<M>) -> Self {
pub fn new(client: &Arc<C>, sync: &Arc<S>, accounts: &Arc<A>, miner: &Arc<M>) -> Self {
EthClient {
client: Arc::downgrade(client),
sync: Arc::downgrade(sync),
miner: Arc::downgrade(miner),
accounts: Arc::downgrade(accounts),
hashrates: RwLock::new(HashMap::new()),
}
}
@@ -104,10 +110,12 @@ impl<C, S, M> EthClient<C, S, M>
}
}
impl<C, S, M> Eth for EthClient<C, S, M>
impl<C, S, A, M> Eth for EthClient<C, S, A, M>
where C: BlockChainClient + 'static,
S: SyncProvider + 'static,
A: AccountProvider + 'static,
M: MinerService + 'static {
fn protocol_version(&self, params: Params) -> Result<Value, Error> {
match params {
Params::None => to_value(&U256::from(take_weak!(self.sync).status().protocol_version)),
@@ -171,7 +179,7 @@ impl<C, S, M> Eth for EthClient<C, S, M>
}
}
fn block_transaction_count(&self, params: Params) -> Result<Value, Error> {
fn block_transaction_count_by_hash(&self, params: Params) -> Result<Value, Error> {
from_params::<(H256,)>(params)
.and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) {
Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()),
@@ -179,6 +187,17 @@ impl<C, S, M> Eth for EthClient<C, S, M>
})
}
fn block_transaction_count_by_number(&self, params: Params) -> Result<Value, Error> {
from_params::<(BlockNumber,)>(params)
.and_then(|(block_number,)| match block_number {
BlockNumber::Pending => to_value(&take_weak!(self.miner).status().transaction_queue_pending),
_ => match take_weak!(self.client).block(block_number.into()) {
Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()),
None => Ok(Value::Null)
}
})
}
fn block_uncles_count(&self, params: Params) -> Result<Value, Error> {
from_params::<(H256,)>(params)
.and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) {
@@ -267,6 +286,33 @@ impl<C, S, M> Eth for EthClient<C, S, M>
to_value(&true)
})
}
fn send_transaction(&self, params: Params) -> Result<Value, Error> {
from_params::<(TransactionRequest, )>(params)
.and_then(|(transaction_request, )| {
let accounts = take_weak!(self.accounts);
match accounts.account_secret(&transaction_request.from) {
Ok(secret) => {
let miner = take_weak!(self.miner);
let client = take_weak!(self.client);
let transaction: EthTransaction = transaction_request.into();
let signed_transaction = transaction.sign(&secret);
let hash = signed_transaction.hash();
let import = miner.import_transactions(vec![signed_transaction], |a: &Address| client.nonce(a));
match import {
Ok(_) => to_value(&hash),
Err(e) => {
warn!("Error sending transaction: {:?}", e);
to_value(&U256::zero())
}
}
},
Err(_) => { to_value(&U256::zero()) }
}
})
}
}
/// Eth filter rpc implementation.

View File

@@ -36,10 +36,15 @@ impl<S> NetClient<S> where S: SyncProvider {
impl<S> Net for NetClient<S> where S: SyncProvider + 'static {
fn version(&self, _: Params) -> Result<Value, Error> {
Ok(Value::U64(take_weak!(self.sync).status().protocol_version as u64))
Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned()))
}
fn peer_count(&self, _params: Params) -> Result<Value, Error> {
Ok(Value::U64(take_weak!(self.sync).status().num_peers as u64))
Ok(Value::String(format!("0x{:x}", take_weak!(self.sync).status().num_peers as u64).to_owned()))
}
fn is_listening(&self, _: Params) -> Result<Value, Error> {
// right now (11 march 2016), we are always listening for incoming connections
Ok(Value::Bool(true))
}
}

View File

@@ -20,30 +20,28 @@ use jsonrpc_core::*;
use v1::traits::Personal;
use util::keys::store::*;
use util::Address;
use std::sync::RwLock;
/// Account management (personal) rpc implementation.
pub struct PersonalClient {
secret_store: Weak<RwLock<SecretStore>>,
accounts: Weak<AccountProvider>,
}
impl PersonalClient {
/// Creates new PersonalClient
pub fn new(store: &Arc<RwLock<SecretStore>>) -> Self {
pub fn new(store: &Arc<AccountProvider>) -> Self {
PersonalClient {
secret_store: Arc::downgrade(store),
accounts: Arc::downgrade(store),
}
}
}
impl Personal for PersonalClient {
fn accounts(&self, _: Params) -> Result<Value, Error> {
let store_wk = take_weak!(self.secret_store);
let store = store_wk.read().unwrap();
let store = take_weak!(self.accounts);
match store.accounts() {
Ok(account_list) => {
Ok(Value::Array(account_list.iter()
.map(|&(account, _)| Value::String(format!("{:?}", account)))
.map(|&account| Value::String(format!("{:?}", account)))
.collect::<Vec<Value>>())
)
}
@@ -54,8 +52,7 @@ impl Personal for PersonalClient {
fn new_account(&self, params: Params) -> Result<Value, Error> {
from_params::<(String, )>(params).and_then(
|(pass, )| {
let store_wk = take_weak!(self.secret_store);
let mut store = store_wk.write().unwrap();
let store = take_weak!(self.accounts);
match store.new_account(&pass) {
Ok(address) => Ok(Value::String(format!("{:?}", address))),
Err(_) => Err(Error::internal_error())
@@ -67,8 +64,7 @@ impl Personal for PersonalClient {
fn unlock_account(&self, params: Params) -> Result<Value, Error> {
from_params::<(Address, String, u64)>(params).and_then(
|(account, account_pass, _)|{
let store_wk = take_weak!(self.secret_store);
let store = store_wk.read().unwrap();
let store = take_weak!(self.accounts);
match store.unlock_account(&account, &account_pass) {
Ok(_) => Ok(Value::Bool(true)),
Err(_) => Ok(Value::Bool(false)),

View File

@@ -21,9 +21,10 @@
pub mod traits;
mod impls;
mod types;
mod helpers;
#[cfg(test)]
mod tests;
mod helpers;
pub use self::traits::{Web3, Eth, EthFilter, Personal, Net};
pub use self::impls::*;

View File

@@ -0,0 +1,19 @@
// 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/>.
mod sync_provider;
pub use self::sync_provider::{Config, TestSyncProvider};

View File

@@ -0,0 +1,52 @@
// 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 ethsync::{SyncProvider, SyncStatus, SyncState};
pub struct Config {
pub protocol_version: u8,
pub num_peers: usize,
}
pub struct TestSyncProvider {
status: SyncStatus,
}
impl TestSyncProvider {
pub fn new(config: Config) -> Self {
TestSyncProvider {
status: SyncStatus {
state: SyncState::NotSynced,
protocol_version: config.protocol_version,
start_block_number: 0,
last_imported_block_number: None,
highest_block_number: None,
blocks_total: 0,
blocks_received: 0,
num_peers: config.num_peers,
num_active_peers: 0,
mem_used: 0,
},
}
}
}
impl SyncProvider for TestSyncProvider {
fn status(&self) -> SyncStatus {
self.status.clone()
}
}

View File

@@ -1 +1,20 @@
//TODO: load custom blockchain state and test
// 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/>.
//!TODO: load custom blockchain state and test
mod net;
mod helpers;

66
rpc/src/v1/tests/net.rs Normal file
View File

@@ -0,0 +1,66 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use jsonrpc_core::IoHandler;
use v1::{Net, NetClient};
use v1::tests::helpers::{Config, TestSyncProvider};
fn sync_provider() -> Arc<TestSyncProvider> {
Arc::new(TestSyncProvider::new(Config {
protocol_version: 65,
num_peers: 120,
}))
}
#[test]
fn rpc_net_version() {
let sync = sync_provider();
let net = NetClient::new(&sync).to_delegate();
let io = IoHandler::new();
io.add_delegate(net);
let request = r#"{"jsonrpc": "2.0", "method": "net_version", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"65","id":1}"#;
assert_eq!(io.handle_request(request), Some(response.to_string()));
}
#[test]
fn rpc_net_peer_count() {
let sync = sync_provider();
let net = NetClient::new(&sync).to_delegate();
let io = IoHandler::new();
io.add_delegate(net);
let request = r#"{"jsonrpc": "2.0", "method": "net_peerCount", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x78","id":1}"#;
assert_eq!(io.handle_request(request), Some(response.to_string()));
}
#[test]
fn rpc_net_listening() {
let sync = sync_provider();
let net = NetClient::new(&sync).to_delegate();
let io = IoHandler::new();
io.add_delegate(net);
let request = r#"{"jsonrpc": "2.0", "method": "net_listening", "params": [], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#;
assert_eq!(io.handle_request(request), Some(response.to_string()));
}

View File

@@ -55,12 +55,15 @@ pub trait Eth: Sized + Send + Sync + 'static {
/// Returns block with given number.
fn block_by_number(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
/// Returns the number of transactions sent from given address at given time (block number).
fn transaction_count(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
/// Returns the number of transactions in a block.
fn block_transaction_count(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
/// Returns the number of transactions in a block given block hash.
fn block_transaction_count_by_hash(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
/// Returns the number of transactions in a block given block number.
fn block_transaction_count_by_number(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
/// Returns the number of uncles in a given block.
fn block_uncles_count(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
@@ -130,8 +133,8 @@ pub trait Eth: Sized + Send + Sync + 'static {
delegate.add_method("eth_balance", Eth::balance);
delegate.add_method("eth_getStorageAt", Eth::storage_at);
delegate.add_method("eth_getTransactionCount", Eth::transaction_count);
delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count);
delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count);
delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count_by_hash);
delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count_by_number);
delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count);
delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count);
delegate.add_method("eth_code", Eth::code_at);

View File

@@ -15,10 +15,12 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use rustc_serialize::hex::ToHex;
use serde::{Serialize, Serializer};
use serde::{Serialize, Serializer, Deserialize, Deserializer, Error};
use serde::de::Visitor;
use util::common::FromHex;
/// Wrapper structure around vector of bytes.
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct Bytes(Vec<u8>);
impl Bytes {
@@ -26,6 +28,7 @@ impl Bytes {
pub fn new(bytes: Vec<u8>) -> Bytes {
Bytes(bytes)
}
pub fn to_vec(self) -> Vec<u8> { let Bytes(x) = self; x }
}
impl Default for Bytes {
@@ -36,7 +39,7 @@ impl Default for Bytes {
}
impl Serialize for Bytes {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer {
let mut serialized = "0x".to_owned();
serialized.push_str(self.0.to_hex().as_ref());
@@ -44,6 +47,32 @@ impl Serialize for Bytes {
}
}
impl Deserialize for Bytes {
fn deserialize<D>(deserializer: &mut D) -> Result<Bytes, D::Error>
where D: Deserializer {
deserializer.deserialize(BytesVisitor)
}
}
struct BytesVisitor;
impl Visitor for BytesVisitor {
type Value = Bytes;
fn visit_str<E>(&mut self, value: &str) -> Result<Self::Value, E> where E: Error {
if value.len() >= 2 && &value[0..2] == "0x" {
Ok(Bytes::new(FromHex::from_hex(&value[2..]).unwrap_or_else(|_| vec![])))
} else {
Err(Error::custom("invalid hex"))
}
}
fn visit_string<E>(&mut self, value: String) -> Result<Self::Value, E> where E: Error {
self.visit_str(value.as_ref())
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -23,6 +23,7 @@ mod log;
mod optionals;
mod sync;
mod transaction;
mod transaction_request;
pub use self::block::{Block, BlockTransactions};
pub use self::block_number::BlockNumber;
@@ -33,3 +34,5 @@ pub use self::log::Log;
pub use self::optionals::OptionalValue;
pub use self::sync::{SyncStatus, SyncInfo};
pub use self::transaction::Transaction;
pub use self::transaction_request::TransactionRequest;

View File

@@ -17,6 +17,7 @@
use util::numbers::*;
use ethcore::transaction::{LocalizedTransaction, Action};
use v1::types::{Bytes, OptionalValue};
use serde::Error;
#[derive(Debug, Default, Serialize)]
pub struct Transaction {

View File

@@ -0,0 +1,139 @@
// 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 util::hash::Address;
use util::numbers::{Uint, U256};
use ethcore::transaction::{Action, Transaction};
use v1::types::Bytes;
#[derive(Debug, Default, PartialEq, Deserialize)]
pub struct TransactionRequest {
pub from: Address,
pub to: Option<Address>,
#[serde(rename="gasPrice")]
pub gas_price: Option<U256>,
pub gas: Option<U256>,
pub value: Option<U256>,
pub data: Option<Bytes>,
pub nonce: Option<U256>,
}
impl Into<Transaction> for TransactionRequest {
fn into(self) -> Transaction {
Transaction {
nonce: self.nonce.unwrap_or_else(U256::zero),
action: self.to.map_or(Action::Create, Action::Call),
gas: self.gas.unwrap_or_else(U256::zero),
gas_price: self.gas_price.unwrap_or_else(U256::zero),
value: self.value.unwrap_or_else(U256::zero),
data: self.data.map_or_else(Vec::new, |d| d.to_vec()),
}
}
}
#[cfg(test)]
mod tests {
use serde_json;
use util::numbers::{Uint, U256};
use util::hash::Address;
use ethcore::transaction::{Transaction, Action};
use v1::types::Bytes;
use super::*;
#[test]
fn transaction_request_into_transaction() {
let tr = TransactionRequest {
from: Address::default(),
to: Some(Address::from(10)),
gas_price: Some(U256::from(20)),
gas: Some(U256::from(10_000)),
value: Some(U256::from(1)),
data: Some(Bytes::new(vec![10, 20])),
nonce: Some(U256::from(12)),
};
assert_eq!(Transaction {
nonce: U256::from(12),
action: Action::Call(Address::from(10)),
gas: U256::from(10_000),
gas_price: U256::from(20),
value: U256::from(1),
data: vec![10, 20],
}, tr.into());
}
#[test]
fn empty_transaction_request_into_transaction() {
let tr = TransactionRequest {
from: Address::default(),
to: None,
gas_price: None,
gas: None,
value: None,
data: None,
nonce: None,
};
assert_eq!(Transaction {
nonce: U256::zero(),
action: Action::Create,
gas: U256::zero(),
gas_price: U256::zero(),
value: U256::zero(),
data: vec![],
}, tr.into());
}
#[test]
fn transaction_request_deserialize() {
let s = r#"{
"from":"0x0000000000000000000000000000000000000001",
"to":"0x0000000000000000000000000000000000000002",
"gasPrice":"0x1",
"gas":"0x2",
"value":"0x3",
"data":"0x123456",
"nonce":"0x4"
}"#;
let deserialized: TransactionRequest = serde_json::from_str(s).unwrap();
assert_eq!(deserialized, TransactionRequest {
from: Address::from(1),
to: Some(Address::from(2)),
gas_price: Some(U256::from(1)),
gas: Some(U256::from(2)),
value: Some(U256::from(3)),
data: Some(Bytes::new(vec![0x12, 0x34, 0x56])),
nonce: Some(U256::from(4)),
});
}
#[test]
fn transaction_request_deserialize_empty() {
let s = r#"{"from":"0x0000000000000000000000000000000000000001"}"#;
let deserialized: TransactionRequest = serde_json::from_str(s).unwrap();
assert_eq!(deserialized, TransactionRequest {
from: Address::from(1),
to: None,
gas_price: None,
gas: None,
value: None,
data: None,
nonce: None,
});
}
}