Backports to beta (#1919)
* RPC errors & logs (#1845) * Refactoring errors in RPC * Updating jsonrpc-core * Fixing code_at * Avoid mentioning obvious segments in proof [ci:skip] * fixed cache_manager lock order * Purging .derefs, fixing clippy warnings. (#1890) * Fixing clippy warnings * Purging derefs * Simplifying engine derefs * Simplifying more engine derefs * Adding more details to miner log * fixed #1889, .DS_Store is no longer treated as key file (#1892) * fixed #1889, .DS_Store is no longer treated as key file * ethstore filters directories, hidden files and common system files * fixed compiling * fix regression with geth dir * fix regression with geth dir * Fix ipc compilation and add ipc feature to test targets (#1902) * fix compilation and add it to the ci run * no separator? * use quotes and spaces * RocksDB version bump * Don't return deleted nodes that are not yet flushed (#1908) * polling & connection timeouts (#1910) * Peers RPC + UI displaying active/connected/max peers (#1915) * Peers API * Bumping Parity-UI * Fixing tests * Save nodes removed from backing_overlay until commit (#1917)
This commit is contained in:
96
rpc/src/v1/helpers/dispatch.rs
Normal file
96
rpc/src/v1/helpers/dispatch.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
// 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::numbers::*;
|
||||
use util::rlp::encode;
|
||||
use util::bytes::ToPretty;
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::client::MiningBlockChainClient;
|
||||
use ethcore::transaction::{Action, SignedTransaction, Transaction};
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use jsonrpc_core::{Error, Value, to_value};
|
||||
use v1::helpers::TransactionRequest;
|
||||
use v1::types::{H256 as RpcH256, H520 as RpcH520};
|
||||
use v1::helpers::errors;
|
||||
|
||||
fn prepare_transaction<C, M>(client: &C, miner: &M, request: TransactionRequest) -> Transaction where C: MiningBlockChainClient, M: MinerService {
|
||||
Transaction {
|
||||
nonce: request.nonce
|
||||
.or_else(|| miner
|
||||
.last_nonce(&request.from)
|
||||
.map(|nonce| nonce + U256::one()))
|
||||
.unwrap_or_else(|| client.latest_nonce(&request.from)),
|
||||
|
||||
action: request.to.map_or(Action::Create, Action::Call),
|
||||
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
|
||||
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)),
|
||||
value: request.value.unwrap_or_else(U256::zero),
|
||||
data: request.data.map_or_else(Vec::new, |b| b.to_vec()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<Value, Error>
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
let hash = RpcH256::from(signed_transaction.hash());
|
||||
|
||||
let import = miner.import_own_transaction(client, signed_transaction);
|
||||
|
||||
import
|
||||
.map_err(errors::from_transaction_error)
|
||||
.and_then(|_| to_value(&hash))
|
||||
}
|
||||
|
||||
pub fn signature_with_password(accounts: &AccountProvider, address: Address, hash: H256, pass: String) -> Result<Value, Error> {
|
||||
accounts.sign_with_password(address, pass, hash)
|
||||
.map_err(errors::from_password_error)
|
||||
.and_then(|hash| to_value(&RpcH520::from(hash)))
|
||||
}
|
||||
|
||||
pub fn unlock_sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, password: String) -> Result<Value, Error>
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
|
||||
let address = request.from;
|
||||
let signed_transaction = {
|
||||
let t = prepare_transaction(client, miner, request);
|
||||
let hash = t.hash();
|
||||
let signature = try!(account_provider.sign_with_password(address, password, hash).map_err(errors::from_password_error));
|
||||
t.with_signature(signature)
|
||||
};
|
||||
|
||||
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
|
||||
dispatch_transaction(&*client, &*miner, signed_transaction)
|
||||
}
|
||||
|
||||
pub fn sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, address: Address) -> Result<Value, Error>
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
|
||||
let signed_transaction = {
|
||||
let t = prepare_transaction(client, miner, request);
|
||||
let hash = t.hash();
|
||||
let signature = try!(account_provider.sign(address, hash).map_err(errors::from_signing_error));
|
||||
t.with_signature(signature)
|
||||
};
|
||||
|
||||
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
|
||||
dispatch_transaction(&*client, &*miner, signed_transaction)
|
||||
}
|
||||
|
||||
pub fn default_gas_price<C, M>(client: &C, miner: &M) -> U256 where C: MiningBlockChainClient, M: MinerService {
|
||||
client
|
||||
.gas_price_statistics(100, 8)
|
||||
.map(|x| x[4])
|
||||
.unwrap_or_else(|_| miner.sensible_gas_price())
|
||||
}
|
||||
188
rpc/src/v1/helpers/errors.rs
Normal file
188
rpc/src/v1/helpers/errors.rs
Normal file
@@ -0,0 +1,188 @@
|
||||
// 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/>.
|
||||
|
||||
//! RPC Error codes and error objects
|
||||
|
||||
macro_rules! rpc_unimplemented {
|
||||
() => (Err(::v1::helpers::errors::unimplemented()))
|
||||
}
|
||||
|
||||
use std::fmt;
|
||||
use ethcore::error::Error as EthcoreError;
|
||||
use ethcore::account_provider::{Error as AccountError};
|
||||
use jsonrpc_core::{Error, ErrorCode, Value};
|
||||
|
||||
mod codes {
|
||||
// NOTE [ToDr] Codes from [-32099, -32000]
|
||||
pub const UNSUPPORTED_REQUEST: i64 = -32000;
|
||||
pub const NO_WORK: i64 = -32001;
|
||||
pub const NO_AUTHOR: i64 = -32002;
|
||||
pub const UNKNOWN_ERROR: i64 = -32009;
|
||||
pub const TRANSACTION_ERROR: i64 = -32010;
|
||||
pub const ACCOUNT_LOCKED: i64 = -32020;
|
||||
pub const PASSWORD_INVALID: i64 = -32021;
|
||||
pub const ACCOUNT_ERROR: i64 = -32023;
|
||||
pub const SIGNER_DISABLED: i64 = -32030;
|
||||
pub const REQUEST_REJECTED: i64 = -32040;
|
||||
pub const REQUEST_NOT_FOUND: i64 = -32041;
|
||||
pub const COMPILATION_ERROR: i64 = -32050;
|
||||
}
|
||||
|
||||
pub fn unimplemented() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
|
||||
message: "This request is not implemented yet. Please create an issue on Github repo.".into(),
|
||||
data: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_not_found() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::REQUEST_NOT_FOUND),
|
||||
message: "Request not found.".into(),
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_rejected() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::REQUEST_REJECTED),
|
||||
message: "Request has been rejected.".into(),
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn account<T: fmt::Debug>(error: &str, details: T) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::ACCOUNT_ERROR),
|
||||
message: error.into(),
|
||||
data: Some(Value::String(format!("{:?}", details))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compilation<T: fmt::Debug>(error: T) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::COMPILATION_ERROR),
|
||||
message: "Error while compiling code.".into(),
|
||||
data: Some(Value::String(format!("{:?}", error))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn internal<T: fmt::Debug>(error: &str, data: T) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::InternalError,
|
||||
message: format!("Internal error occurred: {}", error),
|
||||
data: Some(Value::String(format!("{:?}", data))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn invalid_params<T: fmt::Debug>(param: &str, details: T) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::InvalidParams,
|
||||
message: format!("Couldn't parse parameters: {}", param),
|
||||
data: Some(Value::String(format!("{:?}", details))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state_pruned() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
|
||||
message: "This request is not supported because your node is running with state pruning. Run with --pruning=archive.".into(),
|
||||
data: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn no_work() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::NO_WORK),
|
||||
message: "Still syncing.".into(),
|
||||
data: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn no_author() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::NO_AUTHOR),
|
||||
message: "Author not configured. Run Parity with --author to configure.".into(),
|
||||
data: None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn signer_disabled() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::SIGNER_DISABLED),
|
||||
message: "Trusted Signer is disabled. This API is not available.".into(),
|
||||
data: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_signing_error(error: AccountError) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::ACCOUNT_LOCKED),
|
||||
message: "Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.".into(),
|
||||
data: Some(Value::String(format!("{:?}", error))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_password_error(error: AccountError) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::PASSWORD_INVALID),
|
||||
message: "Account password is invalid or account does not exist.".into(),
|
||||
data: Some(Value::String(format!("{:?}", error))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_transaction_error(error: EthcoreError) -> Error {
|
||||
use ethcore::error::TransactionError::*;
|
||||
|
||||
if let EthcoreError::Transaction(e) = error {
|
||||
let msg = match e {
|
||||
AlreadyImported => "Transaction with the same hash was already imported.".into(),
|
||||
Old => "Transaction nonce is too low. Try incrementing the nonce.".into(),
|
||||
TooCheapToReplace => {
|
||||
"Transaction fee is too low. There is another transaction with same nonce in the queue. Try increasing the fee or incrementing the nonce.".into()
|
||||
},
|
||||
LimitReached => {
|
||||
"There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into()
|
||||
},
|
||||
InsufficientGasPrice { minimal, got } => {
|
||||
format!("Transaction fee is too low. It does not satisfy your node's minimal fee (minimal: {}, got: {}). Try increasing the fee.", minimal, got)
|
||||
},
|
||||
InsufficientBalance { balance, cost } => {
|
||||
format!("Insufficient funds. Account you try to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance)
|
||||
},
|
||||
GasLimitExceeded { limit, got } => {
|
||||
format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got)
|
||||
},
|
||||
InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(),
|
||||
};
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::TRANSACTION_ERROR),
|
||||
message: msg,
|
||||
data: None,
|
||||
}
|
||||
} else {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(codes::UNKNOWN_ERROR),
|
||||
message: "Unknown error when sending transaction.".into(),
|
||||
data: Some(Value::String(format!("{:?}", error))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#[macro_use]
|
||||
pub mod errors;
|
||||
pub mod dispatch;
|
||||
pub mod params;
|
||||
mod poll_manager;
|
||||
mod poll_filter;
|
||||
mod requests;
|
||||
|
||||
@@ -22,10 +22,6 @@ pub struct NetworkSettings {
|
||||
pub name: String,
|
||||
/// Name of the chain we are connected to
|
||||
pub chain: String,
|
||||
/// Min number of peers
|
||||
pub min_peers: u32,
|
||||
/// Max number of peers
|
||||
pub max_peers: u32,
|
||||
/// Networking port
|
||||
pub network_port: u16,
|
||||
/// Is JSON-RPC server enabled?
|
||||
@@ -41,8 +37,6 @@ impl Default for NetworkSettings {
|
||||
NetworkSettings {
|
||||
name: "".into(),
|
||||
chain: "homestead".into(),
|
||||
min_peers: 25,
|
||||
max_peers: 50,
|
||||
network_port: 30303,
|
||||
rpc_enabled: true,
|
||||
rpc_interface: "local".into(),
|
||||
|
||||
53
rpc/src/v1/helpers/params.rs
Normal file
53
rpc/src/v1/helpers/params.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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/>.
|
||||
|
||||
//! Parameters parsing helpers
|
||||
|
||||
use serde;
|
||||
use jsonrpc_core::{Error, Params, from_params};
|
||||
use v1::types::BlockNumber;
|
||||
use v1::helpers::errors;
|
||||
|
||||
pub fn expect_no_params(params: Params) -> Result<(), Error> {
|
||||
match params {
|
||||
Params::None => Ok(()),
|
||||
p => Err(errors::invalid_params("No parameters were expected", p)),
|
||||
}
|
||||
}
|
||||
|
||||
fn params_len(params: &Params) -> usize {
|
||||
match params {
|
||||
&Params::Array(ref vec) => vec.len(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize request parameters with optional second parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
|
||||
pub fn from_params_default_second<F>(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)),
|
||||
_ => from_params::<(F, BlockNumber)>(params),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize request parameters with optional third parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
|
||||
pub fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)),
|
||||
_ => from_params::<(F1, F2, BlockNumber)>(params)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ use std::process::{Command, Stdio};
|
||||
use std::thread;
|
||||
use std::time::{Instant, Duration};
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::ops::Deref;
|
||||
use ethsync::{SyncProvider, SyncState};
|
||||
use ethcore::miner::{MinerService, ExternalMinerService};
|
||||
use jsonrpc_core::*;
|
||||
@@ -43,8 +42,9 @@ use ethcore::filter::Filter as EthcoreFilter;
|
||||
use self::ethash::SeedHashCompute;
|
||||
use v1::traits::Eth;
|
||||
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, Index, Filter, Log, Receipt, H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256};
|
||||
use v1::helpers::CallRequest as CRequest;
|
||||
use v1::impls::{default_gas_price, dispatch_transaction, error_codes, from_params_default_second, from_params_default_third};
|
||||
use v1::helpers::{CallRequest as CRequest, errors};
|
||||
use v1::helpers::dispatch::{default_gas_price, dispatch_transaction};
|
||||
use v1::helpers::params::{expect_no_params, from_params_default_second, from_params_default_third};
|
||||
|
||||
/// Eth RPC options
|
||||
pub struct EthClientOptions {
|
||||
@@ -214,30 +214,6 @@ pub fn pending_logs<M>(miner: &M, filter: &EthcoreFilter) -> Vec<Log> where M: M
|
||||
|
||||
const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6.
|
||||
|
||||
fn make_unsupported_err() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::UNSUPPORTED_REQUEST_CODE),
|
||||
message: "Unsupported request.".into(),
|
||||
data: None
|
||||
}
|
||||
}
|
||||
|
||||
fn no_work_err() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::NO_WORK_CODE),
|
||||
message: "Still syncing.".into(),
|
||||
data: None
|
||||
}
|
||||
}
|
||||
|
||||
fn no_author_err() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::NO_AUTHOR_CODE),
|
||||
message: "Author not configured. Run parity with --author to configure.".into(),
|
||||
data: None
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, S: ?Sized, M, EM> EthClient<C, S, M, EM> where
|
||||
C: MiningBlockChainClient + 'static,
|
||||
S: SyncProvider + 'static,
|
||||
@@ -265,94 +241,80 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
|
||||
fn protocol_version(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned())),
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
|
||||
Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned()))
|
||||
}
|
||||
|
||||
fn syncing(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => {
|
||||
let status = take_weak!(self.sync).status();
|
||||
let res = match status.state {
|
||||
SyncState::Idle => SyncStatus::None,
|
||||
SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks | SyncState::ChainHead => {
|
||||
let current_block = U256::from(take_weak!(self.client).chain_info().best_block_number);
|
||||
let highest_block = U256::from(status.highest_block_number.unwrap_or(status.start_block_number));
|
||||
try!(expect_no_params(params));
|
||||
|
||||
if highest_block > current_block + U256::from(6) {
|
||||
let info = SyncInfo {
|
||||
starting_block: status.start_block_number.into(),
|
||||
current_block: current_block.into(),
|
||||
highest_block: highest_block.into(),
|
||||
};
|
||||
SyncStatus::Info(info)
|
||||
} else {
|
||||
SyncStatus::None
|
||||
}
|
||||
}
|
||||
};
|
||||
to_value(&res)
|
||||
let status = take_weak!(self.sync).status();
|
||||
let res = match status.state {
|
||||
SyncState::Idle => SyncStatus::None,
|
||||
SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks | SyncState::ChainHead => {
|
||||
let current_block = U256::from(take_weak!(self.client).chain_info().best_block_number);
|
||||
let highest_block = U256::from(status.highest_block_number.unwrap_or(status.start_block_number));
|
||||
|
||||
if highest_block > current_block + U256::from(6) {
|
||||
let info = SyncInfo {
|
||||
starting_block: status.start_block_number.into(),
|
||||
current_block: current_block.into(),
|
||||
highest_block: highest_block.into(),
|
||||
};
|
||||
SyncStatus::Info(info)
|
||||
} else {
|
||||
SyncStatus::None
|
||||
}
|
||||
}
|
||||
_ => Err(Error::invalid_params()),
|
||||
}
|
||||
};
|
||||
to_value(&res)
|
||||
}
|
||||
|
||||
fn author(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => to_value(&RpcH160::from(take_weak!(self.miner).author())),
|
||||
_ => Err(Error::invalid_params()),
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
|
||||
to_value(&RpcH160::from(take_weak!(self.miner).author()))
|
||||
}
|
||||
|
||||
fn is_mining(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => to_value(&(take_weak!(self.miner).is_sealing())),
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
|
||||
to_value(&(take_weak!(self.miner).is_sealing()))
|
||||
}
|
||||
|
||||
fn hashrate(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => to_value(&RpcU256::from(self.external_miner.hashrate())),
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
|
||||
to_value(&RpcU256::from(self.external_miner.hashrate()))
|
||||
}
|
||||
|
||||
fn gas_price(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => {
|
||||
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
|
||||
to_value(&RpcU256::from(default_gas_price(&*client, &*miner)))
|
||||
}
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
|
||||
to_value(&RpcU256::from(default_gas_price(&*client, &*miner)))
|
||||
}
|
||||
|
||||
fn accounts(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => {
|
||||
let store = take_weak!(self.accounts);
|
||||
let accounts = try!(store.accounts().map_err(|_| Error::internal_error()));
|
||||
to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
|
||||
},
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let store = take_weak!(self.accounts);
|
||||
let accounts = try!(store.accounts().map_err(|e| errors::internal("Could not fetch accounts.", e)));
|
||||
to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
|
||||
}
|
||||
|
||||
fn block_number(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => to_value(&RpcU256::from(take_weak!(self.client).chain_info().best_block_number)),
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
|
||||
to_value(&RpcU256::from(take_weak!(self.client).chain_info().best_block_number))
|
||||
}
|
||||
|
||||
fn balance(&self, params: Params) -> Result<Value, Error> {
|
||||
@@ -361,8 +323,11 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
.and_then(|(address, block_number,)| {
|
||||
let address: Address = RpcH160::into(address);
|
||||
match block_number {
|
||||
BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).balance(take_weak!(self.client).deref(), &address))),
|
||||
id => to_value(&RpcU256::from(try!(take_weak!(self.client).balance(&address, id.into()).ok_or_else(make_unsupported_err)))),
|
||||
BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).balance(&*take_weak!(self.client), &address))),
|
||||
id => match take_weak!(self.client).balance(&address, id.into()) {
|
||||
Some(balance) => to_value(&RpcU256::from(balance)),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -377,7 +342,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).storage_at(&*take_weak!(self.client), &address, &H256::from(position)))),
|
||||
id => match take_weak!(self.client).storage_at(&address, &H256::from(position), id.into()) {
|
||||
Some(s) => to_value(&RpcH256::from(s)),
|
||||
None => Err(make_unsupported_err()), // None is only returned on unsupported requests.
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -390,8 +355,11 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
.and_then(|(address, block_number,)| {
|
||||
let address: Address = RpcH160::into(address);
|
||||
match block_number {
|
||||
BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).nonce(take_weak!(self.client).deref(), &address))),
|
||||
id => to_value(&take_weak!(self.client).nonce(&address, id.into()).map(RpcU256::from)),
|
||||
BlockNumber::Pending => to_value(&RpcU256::from(take_weak!(self.miner).nonce(&*take_weak!(self.client), &address))),
|
||||
id => match take_weak!(self.client).nonce(&address, id.into()) {
|
||||
Some(nonce) => to_value(&RpcU256::from(nonce)),
|
||||
None => Err(errors::state_pruned()),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -440,9 +408,11 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
.and_then(|(address, block_number,)| {
|
||||
let address: Address = RpcH160::into(address);
|
||||
match block_number {
|
||||
BlockNumber::Pending => to_value(&take_weak!(self.miner).code(take_weak!(self.client).deref(), &address).map_or_else(Bytes::default, Bytes::new)),
|
||||
BlockNumber::Latest => to_value(&take_weak!(self.client).code(&address).map_or_else(Bytes::default, Bytes::new)),
|
||||
_ => Err(Error::invalid_params()),
|
||||
BlockNumber::Pending => to_value(&take_weak!(self.miner).code(&*take_weak!(self.client), &address).map_or_else(Bytes::default, Bytes::new)),
|
||||
_ => match take_weak!(self.client).code(&address, block_number.into()) {
|
||||
Some(code) => to_value(&code.map_or_else(Bytes::default, Bytes::new)),
|
||||
None => Err(errors::state_pruned()),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -515,16 +485,13 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
|
||||
fn compilers(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => {
|
||||
let mut compilers = vec![];
|
||||
if Command::new(SOLC).output().is_ok() {
|
||||
compilers.push("solidity".to_owned())
|
||||
}
|
||||
to_value(&compilers)
|
||||
}
|
||||
_ => Err(Error::invalid_params())
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let mut compilers = vec![];
|
||||
if Command::new(SOLC).output().is_ok() {
|
||||
compilers.push("solidity".to_owned())
|
||||
}
|
||||
to_value(&compilers)
|
||||
}
|
||||
|
||||
fn logs(&self, params: Params) -> Result<Value, Error> {
|
||||
@@ -539,7 +506,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
.collect::<Vec<Log>>();
|
||||
|
||||
if include_pending {
|
||||
let pending = pending_logs(take_weak!(self.miner).deref(), &filter);
|
||||
let pending = pending_logs(&*take_weak!(self.miner), &filter);
|
||||
logs.extend(pending);
|
||||
}
|
||||
|
||||
@@ -549,45 +516,42 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
|
||||
fn work(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => {
|
||||
let client = take_weak!(self.client);
|
||||
// check if we're still syncing and return empty strings in that case
|
||||
{
|
||||
//TODO: check if initial sync is complete here
|
||||
//let sync = take_weak!(self.sync);
|
||||
if /*sync.status().state != SyncState::Idle ||*/ client.queue_info().total_queue_size() > MAX_QUEUE_SIZE_TO_MINE_ON {
|
||||
trace!(target: "miner", "Syncing. Cannot give any work.");
|
||||
return Err(no_work_err());
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
|
||||
// Otherwise spin until our submitted block has been included.
|
||||
let timeout = Instant::now() + Duration::from_millis(1000);
|
||||
while Instant::now() < timeout && client.queue_info().total_queue_size() > 0 {
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
let client = take_weak!(self.client);
|
||||
// check if we're still syncing and return empty strings in that case
|
||||
{
|
||||
//TODO: check if initial sync is complete here
|
||||
//let sync = take_weak!(self.sync);
|
||||
if /*sync.status().state != SyncState::Idle ||*/ client.queue_info().total_queue_size() > MAX_QUEUE_SIZE_TO_MINE_ON {
|
||||
trace!(target: "miner", "Syncing. Cannot give any work.");
|
||||
return Err(errors::no_work());
|
||||
}
|
||||
|
||||
let miner = take_weak!(self.miner);
|
||||
if miner.author().is_zero() {
|
||||
warn!(target: "miner", "Cannot give work package - no author is configured. Use --author to configure!");
|
||||
return Err(no_author_err())
|
||||
}
|
||||
miner.map_sealing_work(client.deref(), |b| {
|
||||
let pow_hash = b.hash();
|
||||
let target = Ethash::difficulty_to_boundary(b.block().header().difficulty());
|
||||
let seed_hash = self.seed_compute.lock().get_seedhash(b.block().header().number());
|
||||
|
||||
if self.options.send_block_number_in_get_work {
|
||||
let block_number = RpcU256::from(b.block().header().number());
|
||||
to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target), block_number))
|
||||
} else {
|
||||
to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target)))
|
||||
}
|
||||
}).unwrap_or(Err(Error::internal_error())) // no work found.
|
||||
},
|
||||
_ => Err(Error::invalid_params())
|
||||
// Otherwise spin until our submitted block has been included.
|
||||
let timeout = Instant::now() + Duration::from_millis(1000);
|
||||
while Instant::now() < timeout && client.queue_info().total_queue_size() > 0 {
|
||||
thread::sleep(Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
|
||||
let miner = take_weak!(self.miner);
|
||||
if miner.author().is_zero() {
|
||||
warn!(target: "miner", "Cannot give work package - no author is configured. Use --author to configure!");
|
||||
return Err(errors::no_author())
|
||||
}
|
||||
miner.map_sealing_work(&*client, |b| {
|
||||
let pow_hash = b.hash();
|
||||
let target = Ethash::difficulty_to_boundary(b.block().header().difficulty());
|
||||
let seed_hash = self.seed_compute.lock().get_seedhash(b.block().header().number());
|
||||
|
||||
if self.options.send_block_number_in_get_work {
|
||||
let block_number = RpcU256::from(b.block().header().number());
|
||||
to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target), block_number))
|
||||
} else {
|
||||
to_value(&(RpcH256::from(pow_hash), RpcH256::from(seed_hash), RpcH256::from(target)))
|
||||
}
|
||||
}).unwrap_or(Err(Error::internal_error())) // no work found.
|
||||
}
|
||||
|
||||
fn submit_work(&self, params: Params) -> Result<Value, Error> {
|
||||
@@ -600,7 +564,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
let miner = take_weak!(self.miner);
|
||||
let client = take_weak!(self.client);
|
||||
let seal = vec![encode(&mix_hash).to_vec(), encode(&nonce).to_vec()];
|
||||
let r = miner.submit_seal(client.deref(), pow_hash, seal);
|
||||
let r = miner.submit_seal(&*client, pow_hash, seal);
|
||||
to_value(&r.is_ok())
|
||||
})
|
||||
}
|
||||
@@ -627,13 +591,12 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
|
||||
fn call(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
trace!(target: "jsonrpc", "call: {:?}", params);
|
||||
from_params_default_second(params)
|
||||
.and_then(|(request, block_number,)| {
|
||||
let request = CallRequest::into(request);
|
||||
let signed = try!(self.sign_call(request));
|
||||
let r = match block_number {
|
||||
BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, Default::default()),
|
||||
BlockNumber::Pending => take_weak!(self.miner).call(&*take_weak!(self.client), &signed, Default::default()),
|
||||
block_number => take_weak!(self.client).call(&signed, block_number.into(), Default::default()),
|
||||
};
|
||||
to_value(&r.map(|e| Bytes(e.output)).unwrap_or(Bytes::new(vec![])))
|
||||
@@ -647,7 +610,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
let request = CallRequest::into(request);
|
||||
let signed = try!(self.sign_call(request));
|
||||
let r = match block_number {
|
||||
BlockNumber::Pending => take_weak!(self.miner).call(take_weak!(self.client).deref(), &signed, Default::default()),
|
||||
BlockNumber::Pending => take_weak!(self.miner).call(&*take_weak!(self.client), &signed, Default::default()),
|
||||
block => take_weak!(self.client).call(&signed, block.into(), Default::default()),
|
||||
};
|
||||
to_value(&RpcU256::from(r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0))))
|
||||
@@ -675,17 +638,23 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::null())
|
||||
.spawn();
|
||||
if let Ok(mut child) = maybe_child {
|
||||
if let Ok(_) = child.stdin.as_mut().expect("we called child.stdin(Stdio::piped()) before spawn; qed").write_all(code.as_bytes()) {
|
||||
if let Ok(output) = child.wait_with_output() {
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
if let Some(hex) = s.lines().skip_while(|ref l| !l.contains("Binary")).skip(1).next() {
|
||||
return to_value(&Bytes::new(hex.from_hex().unwrap_or(vec![])));
|
||||
}
|
||||
|
||||
maybe_child
|
||||
.map_err(errors::compilation)
|
||||
.and_then(|mut child| {
|
||||
try!(child.stdin.as_mut()
|
||||
.expect("we called child.stdin(Stdio::piped()) before spawn; qed")
|
||||
.write_all(code.as_bytes())
|
||||
.map_err(errors::compilation));
|
||||
let output = try!(child.wait_with_output().map_err(errors::compilation));
|
||||
|
||||
let s = String::from_utf8_lossy(&output.stdout);
|
||||
if let Some(hex) = s.lines().skip_while(|ref l| !l.contains("Binary")).skip(1).next() {
|
||||
to_value(&Bytes::new(hex.from_hex().unwrap_or(vec![])))
|
||||
} else {
|
||||
Err(errors::compilation("Unexpected output."))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Error::invalid_params())
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
//! Eth Filter RPC implementation
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::collections::HashSet;
|
||||
use jsonrpc_core::*;
|
||||
@@ -27,6 +26,7 @@ use util::Mutex;
|
||||
use v1::traits::EthFilter;
|
||||
use v1::types::{BlockNumber, Index, Filter, Log, H256 as RpcH256, U256 as RpcU256};
|
||||
use v1::helpers::{PollFilter, PollManager};
|
||||
use v1::helpers::params::expect_no_params;
|
||||
use v1::impls::eth::pending_logs;
|
||||
|
||||
/// Eth filter rpc implementation.
|
||||
@@ -76,28 +76,22 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
|
||||
|
||||
fn new_block_filter(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => {
|
||||
let mut polls = self.polls.lock();
|
||||
let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number));
|
||||
to_value(&RpcU256::from(id))
|
||||
},
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let mut polls = self.polls.lock();
|
||||
let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number));
|
||||
to_value(&RpcU256::from(id))
|
||||
}
|
||||
|
||||
fn new_pending_transaction_filter(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => {
|
||||
let mut polls = self.polls.lock();
|
||||
let pending_transactions = take_weak!(self.miner).pending_transactions_hashes();
|
||||
let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions));
|
||||
try!(expect_no_params(params));
|
||||
|
||||
to_value(&RpcU256::from(id))
|
||||
},
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
let mut polls = self.polls.lock();
|
||||
let pending_transactions = take_weak!(self.miner).pending_transactions_hashes();
|
||||
let id = polls.create_poll(PollFilter::PendingTransaction(pending_transactions));
|
||||
|
||||
to_value(&RpcU256::from(id))
|
||||
}
|
||||
|
||||
fn filter_changes(&self, params: Params) -> Result<Value, Error> {
|
||||
@@ -165,7 +159,7 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
|
||||
|
||||
// additionally retrieve pending logs
|
||||
if include_pending {
|
||||
let pending_logs = pending_logs(take_weak!(self.miner).deref(), &filter);
|
||||
let pending_logs = pending_logs(&*take_weak!(self.miner), &filter);
|
||||
|
||||
// remove logs about which client was already notified about
|
||||
let new_pending_logs: Vec<_> = pending_logs.iter()
|
||||
@@ -206,7 +200,7 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
|
||||
.collect::<Vec<Log>>();
|
||||
|
||||
if include_pending {
|
||||
logs.extend(pending_logs(take_weak!(self.miner).deref(), &filter));
|
||||
logs.extend(pending_logs(&*take_weak!(self.miner), &filter));
|
||||
}
|
||||
|
||||
to_value(&logs)
|
||||
|
||||
@@ -23,10 +23,10 @@ use ethcore::client::MiningBlockChainClient;
|
||||
use util::{U256, Address, H256, Mutex};
|
||||
use transient_hashmap::TransientHashMap;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use v1::helpers::{SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationsQueue, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest};
|
||||
use v1::helpers::{errors, SigningQueue, ConfirmationPromise, ConfirmationResult, ConfirmationsQueue, ConfirmationPayload, TransactionRequest as TRequest, FilledTransactionRequest as FilledRequest};
|
||||
use v1::helpers::dispatch::{default_gas_price, sign_and_dispatch};
|
||||
use v1::traits::EthSigning;
|
||||
use v1::types::{TransactionRequest, H160 as RpcH160, H256 as RpcH256, H520 as RpcH520, U256 as RpcU256};
|
||||
use v1::impls::{default_gas_price, sign_and_dispatch, request_rejected_error, request_not_found_error, signer_disabled_error};
|
||||
|
||||
fn fill_optional_fields<C, M>(request: TRequest, client: &C, miner: &M) -> FilledRequest
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
@@ -151,10 +151,10 @@ impl<C, M> EthSigning for EthSigningQueueClient<C, M>
|
||||
let res = match pending.get(&id) {
|
||||
Some(ref promise) => match promise.result() {
|
||||
ConfirmationResult::Waiting => { return Ok(Value::Null); }
|
||||
ConfirmationResult::Rejected => Err(request_rejected_error()),
|
||||
ConfirmationResult::Rejected => Err(errors::request_rejected()),
|
||||
ConfirmationResult::Confirmed(rpc_response) => rpc_response,
|
||||
},
|
||||
_ => { return Err(request_not_found_error()); }
|
||||
_ => { return Err(errors::request_not_found()); }
|
||||
};
|
||||
pending.remove(&id);
|
||||
res
|
||||
@@ -217,16 +217,16 @@ impl<C, M> EthSigning for EthSigningUnsafeClient<C, M> where
|
||||
|
||||
fn post_sign(&self, _: Params) -> Result<Value, Error> {
|
||||
// We don't support this in non-signer mode.
|
||||
Err(signer_disabled_error())
|
||||
Err(errors::signer_disabled())
|
||||
}
|
||||
|
||||
fn post_transaction(&self, _: Params) -> Result<Value, Error> {
|
||||
// We don't support this in non-signer mode.
|
||||
Err(signer_disabled_error())
|
||||
Err(errors::signer_disabled())
|
||||
}
|
||||
|
||||
fn check_request(&self, _: Params) -> Result<Value, Error> {
|
||||
// We don't support this in non-signer mode.
|
||||
Err(signer_disabled_error())
|
||||
Err(errors::signer_disabled())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,34 +18,48 @@
|
||||
use util::{RotatingLogger};
|
||||
use util::misc::version_data;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::ops::Deref;
|
||||
use std::collections::{BTreeMap};
|
||||
use ethcore::client::{MiningBlockChainClient};
|
||||
use jsonrpc_core::*;
|
||||
use ethsync::{SyncProvider, ManageNetwork};
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::client::{MiningBlockChainClient};
|
||||
|
||||
use jsonrpc_core::*;
|
||||
use v1::traits::Ethcore;
|
||||
use v1::types::{Bytes, U256};
|
||||
use v1::helpers::{SigningQueue, ConfirmationsQueue, NetworkSettings};
|
||||
use v1::impls::signer_disabled_error;
|
||||
use v1::types::{Bytes, U256, Peers};
|
||||
use v1::helpers::{errors, SigningQueue, ConfirmationsQueue, NetworkSettings};
|
||||
use v1::helpers::params::expect_no_params;
|
||||
|
||||
/// Ethcore implementation.
|
||||
pub struct EthcoreClient<C, M> where
|
||||
pub struct EthcoreClient<C, M, S: ?Sized> where
|
||||
C: MiningBlockChainClient,
|
||||
M: MinerService {
|
||||
M: MinerService,
|
||||
S: SyncProvider {
|
||||
|
||||
client: Weak<C>,
|
||||
miner: Weak<M>,
|
||||
sync: Weak<S>,
|
||||
net: Weak<ManageNetwork>,
|
||||
logger: Arc<RotatingLogger>,
|
||||
settings: Arc<NetworkSettings>,
|
||||
confirmations_queue: Option<Arc<ConfirmationsQueue>>,
|
||||
}
|
||||
|
||||
impl<C, M> EthcoreClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
||||
impl<C, M, S: ?Sized> EthcoreClient<C, M, S> where C: MiningBlockChainClient, M: MinerService, S: SyncProvider {
|
||||
/// Creates new `EthcoreClient`.
|
||||
pub fn new(client: &Arc<C>, miner: &Arc<M>, logger: Arc<RotatingLogger>, settings: Arc<NetworkSettings>, queue: Option<Arc<ConfirmationsQueue>>) -> Self {
|
||||
pub fn new(
|
||||
client: &Arc<C>,
|
||||
miner: &Arc<M>,
|
||||
sync: &Arc<S>,
|
||||
net: &Arc<ManageNetwork>,
|
||||
logger: Arc<RotatingLogger>,
|
||||
settings: Arc<NetworkSettings>,
|
||||
queue: Option<Arc<ConfirmationsQueue>>
|
||||
) -> Self {
|
||||
EthcoreClient {
|
||||
client: Arc::downgrade(client),
|
||||
miner: Arc::downgrade(miner),
|
||||
sync: Arc::downgrade(sync),
|
||||
net: Arc::downgrade(net),
|
||||
logger: logger,
|
||||
settings: settings,
|
||||
confirmations_queue: queue,
|
||||
@@ -59,66 +73,86 @@ impl<C, M> EthcoreClient<C, M> where C: MiningBlockChainClient, M: MinerService
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, M> Ethcore for EthcoreClient<C, M> where M: MinerService + 'static, C: MiningBlockChainClient + 'static {
|
||||
impl<C, M, S: ?Sized> Ethcore for EthcoreClient<C, M, S> where M: MinerService + 'static, C: MiningBlockChainClient + 'static, S: SyncProvider + 'static {
|
||||
|
||||
fn transactions_limit(&self, _: Params) -> Result<Value, Error> {
|
||||
fn transactions_limit(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
to_value(&take_weak!(self.miner).transactions_limit())
|
||||
}
|
||||
|
||||
fn min_gas_price(&self, _: Params) -> Result<Value, Error> {
|
||||
fn min_gas_price(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
to_value(&U256::from(take_weak!(self.miner).minimal_gas_price()))
|
||||
}
|
||||
|
||||
fn extra_data(&self, _: Params) -> Result<Value, Error> {
|
||||
fn extra_data(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
to_value(&Bytes::new(take_weak!(self.miner).extra_data()))
|
||||
}
|
||||
|
||||
fn gas_floor_target(&self, _: Params) -> Result<Value, Error> {
|
||||
fn gas_floor_target(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
to_value(&U256::from(take_weak!(self.miner).gas_floor_target()))
|
||||
}
|
||||
|
||||
fn gas_ceil_target(&self, _: Params) -> Result<Value, Error> {
|
||||
fn gas_ceil_target(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
to_value(&U256::from(take_weak!(self.miner).gas_ceil_target()))
|
||||
}
|
||||
|
||||
fn dev_logs(&self, _params: Params) -> Result<Value, Error> {
|
||||
fn dev_logs(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
let logs = self.logger.logs();
|
||||
to_value(&logs.deref().as_slice())
|
||||
to_value(&logs.as_slice())
|
||||
}
|
||||
|
||||
fn dev_logs_levels(&self, _params: Params) -> Result<Value, Error> {
|
||||
fn dev_logs_levels(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
to_value(&self.logger.levels())
|
||||
}
|
||||
|
||||
fn net_chain(&self, _params: Params) -> Result<Value, Error> {
|
||||
fn net_chain(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
to_value(&self.settings.chain)
|
||||
}
|
||||
|
||||
fn net_max_peers(&self, _params: Params) -> Result<Value, Error> {
|
||||
fn net_peers(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
to_value(&self.settings.max_peers)
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let sync_status = take_weak!(self.sync).status();
|
||||
let net_config = take_weak!(self.net).network_config();
|
||||
|
||||
to_value(&Peers {
|
||||
active: sync_status.num_active_peers,
|
||||
connected: sync_status.num_peers,
|
||||
max: sync_status.current_max_peers(net_config.min_peers, net_config.max_peers),
|
||||
})
|
||||
}
|
||||
|
||||
fn net_port(&self, _params: Params) -> Result<Value, Error> {
|
||||
fn net_port(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
to_value(&self.settings.network_port)
|
||||
}
|
||||
|
||||
fn node_name(&self, _params: Params) -> Result<Value, Error> {
|
||||
fn node_name(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
to_value(&self.settings.name)
|
||||
}
|
||||
|
||||
fn rpc_settings(&self, _params: Params) -> Result<Value, Error> {
|
||||
fn rpc_settings(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
let mut map = BTreeMap::new();
|
||||
map.insert("enabled".to_owned(), Value::Bool(self.settings.rpc_enabled));
|
||||
map.insert("interface".to_owned(), Value::String(self.settings.rpc_interface.clone()));
|
||||
@@ -128,30 +162,29 @@ impl<C, M> Ethcore for EthcoreClient<C, M> where M: MinerService + 'static, C: M
|
||||
|
||||
fn default_extra_data(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => to_value(&Bytes::new(version_data())),
|
||||
_ => Err(Error::invalid_params()),
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
to_value(&Bytes::new(version_data()))
|
||||
}
|
||||
|
||||
fn gas_price_statistics(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => match take_weak!(self.client).gas_price_statistics(100, 8) {
|
||||
Ok(stats) => to_value(&stats
|
||||
.into_iter()
|
||||
.map(|x| to_value(&U256::from(x)).expect("x must be U256; qed"))
|
||||
.collect::<Vec<_>>()),
|
||||
_ => Err(Error::internal_error()),
|
||||
},
|
||||
_ => Err(Error::invalid_params()),
|
||||
try!(expect_no_params(params));
|
||||
|
||||
match take_weak!(self.client).gas_price_statistics(100, 8) {
|
||||
Ok(stats) => to_value(&stats
|
||||
.into_iter()
|
||||
.map(|x| to_value(&U256::from(x)).expect("x must be U256; qed"))
|
||||
.collect::<Vec<_>>()),
|
||||
_ => Err(Error::internal_error()),
|
||||
}
|
||||
}
|
||||
|
||||
fn unsigned_transactions_count(&self, _params: Params) -> Result<Value, Error> {
|
||||
fn unsigned_transactions_count(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
match self.confirmations_queue {
|
||||
None => Err(signer_disabled_error()),
|
||||
None => Err(errors::signer_disabled()),
|
||||
Some(ref queue) => to_value(&queue.len()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ use jsonrpc_core::*;
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::client::MiningBlockChainClient;
|
||||
use ethsync::ManageNetwork;
|
||||
use v1::helpers::errors;
|
||||
use v1::helpers::params::expect_no_params;
|
||||
use v1::traits::EthcoreSet;
|
||||
use v1::types::{Bytes, H160, U256};
|
||||
|
||||
@@ -117,7 +119,7 @@ impl<C, M> EthcoreSet for EthcoreSetClient<C, M> where
|
||||
from_params::<(String,)>(params).and_then(|(peer,)| {
|
||||
match take_weak!(self.net).add_reserved_peer(peer) {
|
||||
Ok(()) => to_value(&true),
|
||||
Err(_) => Err(Error::invalid_params()),
|
||||
Err(e) => Err(errors::invalid_params("Peer address", e)),
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -127,29 +129,33 @@ impl<C, M> EthcoreSet for EthcoreSetClient<C, M> where
|
||||
from_params::<(String,)>(params).and_then(|(peer,)| {
|
||||
match take_weak!(self.net).remove_reserved_peer(peer) {
|
||||
Ok(()) => to_value(&true),
|
||||
Err(_) => Err(Error::invalid_params()),
|
||||
Err(e) => Err(errors::invalid_params("Peer address", e)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn drop_non_reserved_peers(&self, _: Params) -> Result<Value, Error> {
|
||||
fn drop_non_reserved_peers(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
take_weak!(self.net).deny_unreserved_peers();
|
||||
to_value(&true)
|
||||
}
|
||||
|
||||
fn accept_non_reserved_peers(&self, _: Params) -> Result<Value, Error> {
|
||||
fn accept_non_reserved_peers(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
take_weak!(self.net).accept_unreserved_peers();
|
||||
to_value(&true)
|
||||
}
|
||||
|
||||
fn start_network(&self, _: Params) -> Result<Value, Error> {
|
||||
fn start_network(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(expect_no_params(params));
|
||||
take_weak!(self.net).start_network();
|
||||
Ok(Value::Bool(true))
|
||||
}
|
||||
|
||||
fn stop_network(&self, _: Params) -> Result<Value, Error> {
|
||||
fn stop_network(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(expect_no_params(params));
|
||||
take_weak!(self.net).stop_network();
|
||||
Ok(Value::Bool(true))
|
||||
}
|
||||
|
||||
@@ -25,21 +25,17 @@ macro_rules! take_weak {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! rpc_unimplemented {
|
||||
() => (Err(Error::internal_error()))
|
||||
}
|
||||
|
||||
mod web3;
|
||||
mod eth;
|
||||
mod eth_filter;
|
||||
mod eth_signing;
|
||||
mod ethcore;
|
||||
mod ethcore_set;
|
||||
mod net;
|
||||
mod personal;
|
||||
mod personal_signer;
|
||||
mod ethcore;
|
||||
mod ethcore_set;
|
||||
mod traces;
|
||||
mod rpc;
|
||||
mod traces;
|
||||
mod web3;
|
||||
|
||||
pub use self::web3::Web3Client;
|
||||
pub use self::eth::{EthClient, EthClientOptions};
|
||||
@@ -53,202 +49,3 @@ pub use self::ethcore_set::EthcoreSetClient;
|
||||
pub use self::traces::TracesClient;
|
||||
pub use self::rpc::RpcClient;
|
||||
|
||||
use serde;
|
||||
use v1::helpers::TransactionRequest;
|
||||
use v1::types::{H256 as RpcH256, H520 as RpcH520, BlockNumber};
|
||||
use ethcore::error::Error as EthcoreError;
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::client::MiningBlockChainClient;
|
||||
use ethcore::transaction::{Action, SignedTransaction, Transaction};
|
||||
use ethcore::account_provider::{AccountProvider, Error as AccountError};
|
||||
use util::numbers::*;
|
||||
use util::rlp::encode;
|
||||
use util::bytes::ToPretty;
|
||||
use jsonrpc_core::{Error, ErrorCode, Value, to_value, from_params, Params};
|
||||
|
||||
mod error_codes {
|
||||
// NOTE [ToDr] Codes from [-32099, -32000]
|
||||
pub const UNSUPPORTED_REQUEST_CODE: i64 = -32000;
|
||||
pub const NO_WORK_CODE: i64 = -32001;
|
||||
pub const NO_AUTHOR_CODE: i64 = -32002;
|
||||
pub const UNKNOWN_ERROR: i64 = -32009;
|
||||
pub const TRANSACTION_ERROR: i64 = -32010;
|
||||
pub const ACCOUNT_LOCKED: i64 = -32020;
|
||||
pub const PASSWORD_INVALID: i64 = -32021;
|
||||
pub const SIGNER_DISABLED: i64 = -32030;
|
||||
pub const REQUEST_REJECTED: i64 = -32040;
|
||||
pub const REQUEST_NOT_FOUND: i64 = -32041;
|
||||
}
|
||||
|
||||
fn params_len(params: &Params) -> usize {
|
||||
match params {
|
||||
&Params::Array(ref vec) => vec.len(),
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize request parameters with optional second parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
|
||||
pub fn from_params_default_second<F>(params: Params) -> Result<(F, BlockNumber, ), Error> where F: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
1 => from_params::<(F, )>(params).map(|(f,)| (f, BlockNumber::Latest)),
|
||||
_ => from_params::<(F, BlockNumber)>(params),
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize request parameters with optional third parameter `BlockNumber` defaulting to `BlockNumber::Latest`.
|
||||
pub fn from_params_default_third<F1, F2>(params: Params) -> Result<(F1, F2, BlockNumber, ), Error> where F1: serde::de::Deserialize, F2: serde::de::Deserialize {
|
||||
match params_len(¶ms) {
|
||||
2 => from_params::<(F1, F2, )>(params).map(|(f1, f2)| (f1, f2, BlockNumber::Latest)),
|
||||
_ => from_params::<(F1, F2, BlockNumber)>(params)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result<Value, Error>
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
let hash = RpcH256::from(signed_transaction.hash());
|
||||
|
||||
let import = miner.import_own_transaction(client, signed_transaction);
|
||||
|
||||
import
|
||||
.map_err(transaction_error)
|
||||
.and_then(|_| to_value(&hash))
|
||||
}
|
||||
|
||||
fn signature_with_password(accounts: &AccountProvider, address: Address, hash: H256, pass: String) -> Result<Value, Error> {
|
||||
accounts.sign_with_password(address, pass, hash)
|
||||
.map_err(password_error)
|
||||
.and_then(|hash| to_value(&RpcH520::from(hash)))
|
||||
}
|
||||
|
||||
fn prepare_transaction<C, M>(client: &C, miner: &M, request: TransactionRequest) -> Transaction where C: MiningBlockChainClient, M: MinerService {
|
||||
Transaction {
|
||||
nonce: request.nonce
|
||||
.or_else(|| miner
|
||||
.last_nonce(&request.from)
|
||||
.map(|nonce| nonce + U256::one()))
|
||||
.unwrap_or_else(|| client.latest_nonce(&request.from)),
|
||||
|
||||
action: request.to.map_or(Action::Create, Action::Call),
|
||||
gas: request.gas.unwrap_or_else(|| miner.sensible_gas_limit()),
|
||||
gas_price: request.gas_price.unwrap_or_else(|| default_gas_price(client, miner)),
|
||||
value: request.value.unwrap_or_else(U256::zero),
|
||||
data: request.data.map_or_else(Vec::new, |b| b.to_vec()),
|
||||
}
|
||||
}
|
||||
|
||||
fn unlock_sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, password: String) -> Result<Value, Error>
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
|
||||
let address = request.from;
|
||||
let signed_transaction = {
|
||||
let t = prepare_transaction(client, miner, request);
|
||||
let hash = t.hash();
|
||||
let signature = try!(account_provider.sign_with_password(address, password, hash).map_err(password_error));
|
||||
t.with_signature(signature)
|
||||
};
|
||||
|
||||
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
|
||||
dispatch_transaction(&*client, &*miner, signed_transaction)
|
||||
}
|
||||
|
||||
fn sign_and_dispatch<C, M>(client: &C, miner: &M, request: TransactionRequest, account_provider: &AccountProvider, address: Address) -> Result<Value, Error>
|
||||
where C: MiningBlockChainClient, M: MinerService {
|
||||
|
||||
let signed_transaction = {
|
||||
let t = prepare_transaction(client, miner, request);
|
||||
let hash = t.hash();
|
||||
let signature = try!(account_provider.sign(address, hash).map_err(signing_error));
|
||||
t.with_signature(signature)
|
||||
};
|
||||
|
||||
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
|
||||
dispatch_transaction(&*client, &*miner, signed_transaction)
|
||||
}
|
||||
|
||||
fn default_gas_price<C, M>(client: &C, miner: &M) -> U256 where C: MiningBlockChainClient, M: MinerService {
|
||||
client
|
||||
.gas_price_statistics(100, 8)
|
||||
.map(|x| x[4])
|
||||
.unwrap_or_else(|_| miner.sensible_gas_price())
|
||||
}
|
||||
|
||||
fn signer_disabled_error() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::SIGNER_DISABLED),
|
||||
message: "Trusted Signer is disabled. This API is not available.".into(),
|
||||
data: None
|
||||
}
|
||||
}
|
||||
|
||||
fn signing_error(error: AccountError) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::ACCOUNT_LOCKED),
|
||||
message: "Your account is locked. Unlock the account via CLI, personal_unlockAccount or use Trusted Signer.".into(),
|
||||
data: Some(Value::String(format!("{:?}", error))),
|
||||
}
|
||||
}
|
||||
|
||||
fn password_error(error: AccountError) -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::PASSWORD_INVALID),
|
||||
message: "Account password is invalid or account does not exist.".into(),
|
||||
data: Some(Value::String(format!("{:?}", error))),
|
||||
}
|
||||
}
|
||||
|
||||
/// Error returned when request is rejected (in Trusted Signer).
|
||||
pub fn request_rejected_error() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::REQUEST_REJECTED),
|
||||
message: "Request has been rejected.".into(),
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Error returned when request is not found in queue.
|
||||
pub fn request_not_found_error() -> Error {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::REQUEST_NOT_FOUND),
|
||||
message: "Request not found.".into(),
|
||||
data: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn transaction_error(error: EthcoreError) -> Error {
|
||||
use ethcore::error::TransactionError::*;
|
||||
|
||||
if let EthcoreError::Transaction(e) = error {
|
||||
let msg = match e {
|
||||
AlreadyImported => "Transaction with the same hash was already imported.".into(),
|
||||
Old => "Transaction nonce is too low. Try incrementing the nonce.".into(),
|
||||
TooCheapToReplace => {
|
||||
"Transaction fee is too low. There is another transaction with same nonce in the queue. Try increasing the fee or incrementing the nonce.".into()
|
||||
},
|
||||
LimitReached => {
|
||||
"There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into()
|
||||
},
|
||||
InsufficientGasPrice { minimal, got } => {
|
||||
format!("Transaction fee is too low. It does not satisfy your node's minimal fee (minimal: {}, got: {}). Try increasing the fee.", minimal, got)
|
||||
},
|
||||
InsufficientBalance { balance, cost } => {
|
||||
format!("Insufficient funds. Account you try to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance)
|
||||
},
|
||||
GasLimitExceeded { limit, got } => {
|
||||
format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got)
|
||||
},
|
||||
InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(),
|
||||
};
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::TRANSACTION_ERROR),
|
||||
message: msg,
|
||||
data: None,
|
||||
}
|
||||
} else {
|
||||
Error {
|
||||
code: ErrorCode::ServerError(error_codes::UNKNOWN_ERROR),
|
||||
message: "Unknown error when sending transaction.".into(),
|
||||
data: Some(Value::String(format!("{:?}", error))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use std::sync::{Arc, Weak};
|
||||
use jsonrpc_core::*;
|
||||
use ethsync::SyncProvider;
|
||||
use v1::traits::Net;
|
||||
use v1::helpers::params::expect_no_params;
|
||||
|
||||
/// Net rpc implementation.
|
||||
pub struct NetClient<S: ?Sized> where S: SyncProvider {
|
||||
@@ -35,15 +36,18 @@ impl<S: ?Sized> NetClient<S> where S: SyncProvider {
|
||||
}
|
||||
|
||||
impl<S: ?Sized> Net for NetClient<S> where S: SyncProvider + 'static {
|
||||
fn version(&self, _: Params) -> Result<Value, Error> {
|
||||
fn version(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(expect_no_params(params));
|
||||
Ok(Value::String(format!("{}", take_weak!(self.sync).status().network_id).to_owned()))
|
||||
}
|
||||
|
||||
fn peer_count(&self, _params: Params) -> Result<Value, Error> {
|
||||
fn peer_count(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(expect_no_params(params));
|
||||
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> {
|
||||
fn is_listening(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(expect_no_params(params));
|
||||
// right now (11 march 2016), we are always listening for incoming connections
|
||||
Ok(Value::Bool(true))
|
||||
}
|
||||
|
||||
@@ -20,8 +20,9 @@ use std::collections::{BTreeMap};
|
||||
use jsonrpc_core::*;
|
||||
use v1::traits::Personal;
|
||||
use v1::types::{H160 as RpcH160, TransactionRequest};
|
||||
use v1::impls::unlock_sign_and_dispatch;
|
||||
use v1::helpers::{TransactionRequest as TRequest};
|
||||
use v1::helpers::{errors, TransactionRequest as TRequest};
|
||||
use v1::helpers::params::expect_no_params;
|
||||
use v1::helpers::dispatch::unlock_sign_and_dispatch;
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use util::Address;
|
||||
use ethcore::client::MiningBlockChainClient;
|
||||
@@ -57,8 +58,10 @@ impl<C, M> PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService
|
||||
|
||||
impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
||||
|
||||
fn signer_enabled(&self, _: Params) -> Result<Value, Error> {
|
||||
fn signer_enabled(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
|
||||
self.signer_port
|
||||
.map(|v| to_value(&v))
|
||||
.unwrap_or_else(|| to_value(&false))
|
||||
@@ -66,14 +69,11 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
|
||||
|
||||
fn accounts(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
match params {
|
||||
Params::None => {
|
||||
let store = take_weak!(self.accounts);
|
||||
let accounts = try!(store.accounts().map_err(|_| Error::internal_error()));
|
||||
to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
|
||||
},
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
|
||||
let store = take_weak!(self.accounts);
|
||||
let accounts = try!(store.accounts().map_err(|e| errors::internal("Could not fetch accounts.", e)));
|
||||
to_value(&accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
|
||||
}
|
||||
|
||||
fn new_account(&self, params: Params) -> Result<Value, Error> {
|
||||
@@ -83,7 +83,7 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
|
||||
let store = take_weak!(self.accounts);
|
||||
match store.new_account(&pass) {
|
||||
Ok(address) => to_value(&RpcH160::from(address)),
|
||||
Err(_) => Err(Error::internal_error())
|
||||
Err(e) => Err(errors::account("Could not create account.", e)),
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -124,7 +124,7 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
|
||||
let store = take_weak!(self.accounts);
|
||||
from_params::<(RpcH160, _)>(params).and_then(|(addr, name)| {
|
||||
let addr: Address = addr.into();
|
||||
store.set_account_name(addr, name).map_err(|_| Error::invalid_params()).map(|_| Value::Null)
|
||||
store.set_account_name(addr, name).map_err(|e| errors::account("Could not set account name.", e)).map(|_| Value::Null)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -133,14 +133,16 @@ impl<C: 'static, M: 'static> Personal for PersonalClient<C, M> where C: MiningBl
|
||||
let store = take_weak!(self.accounts);
|
||||
from_params::<(RpcH160, _)>(params).and_then(|(addr, meta)| {
|
||||
let addr: Address = addr.into();
|
||||
store.set_account_meta(addr, meta).map_err(|_| Error::invalid_params()).map(|_| Value::Null)
|
||||
store.set_account_meta(addr, meta).map_err(|e| errors::account("Could not set account meta.", e)).map(|_| Value::Null)
|
||||
})
|
||||
}
|
||||
|
||||
fn accounts_info(&self, _: Params) -> Result<Value, Error> {
|
||||
fn accounts_info(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
let store = take_weak!(self.accounts);
|
||||
Ok(Value::Object(try!(store.accounts_info().map_err(|_| Error::invalid_params())).into_iter().map(|(a, v)| {
|
||||
let info = try!(store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e)));
|
||||
Ok(Value::Object(info.into_iter().map(|(a, v)| {
|
||||
let m = map![
|
||||
"name".to_owned() => to_value(&v.name).unwrap(),
|
||||
"meta".to_owned() => to_value(&v.meta).unwrap(),
|
||||
|
||||
@@ -23,8 +23,9 @@ use ethcore::client::MiningBlockChainClient;
|
||||
use ethcore::miner::MinerService;
|
||||
use v1::traits::PersonalSigner;
|
||||
use v1::types::{TransactionModification, ConfirmationRequest, U256};
|
||||
use v1::impls::{unlock_sign_and_dispatch, signature_with_password};
|
||||
use v1::helpers::{SigningQueue, ConfirmationsQueue, ConfirmationPayload};
|
||||
use v1::helpers::{errors, SigningQueue, ConfirmationsQueue, ConfirmationPayload};
|
||||
use v1::helpers::params::expect_no_params;
|
||||
use v1::helpers::dispatch::{unlock_sign_and_dispatch, signature_with_password};
|
||||
|
||||
/// Transactions confirmation (personal) rpc implementation.
|
||||
pub struct SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
||||
@@ -55,8 +56,9 @@ impl<C: 'static, M: 'static> SignerClient<C, M> where C: MiningBlockChainClient,
|
||||
|
||||
impl<C: 'static, M: 'static> PersonalSigner for SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
||||
|
||||
fn requests_to_confirm(&self, _params: Params) -> Result<Value, Error> {
|
||||
fn requests_to_confirm(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(self.active());
|
||||
try!(expect_no_params(params));
|
||||
let queue = take_weak!(self.queue);
|
||||
to_value(&queue.requests().into_iter().map(From::from).collect::<Vec<ConfirmationRequest>>())
|
||||
}
|
||||
@@ -91,7 +93,7 @@ impl<C: 'static, M: 'static> PersonalSigner for SignerClient<C, M> where C: Mini
|
||||
queue.request_confirmed(id, Ok(response.clone()));
|
||||
}
|
||||
result
|
||||
}).unwrap_or_else(|| Err(Error::invalid_params()))
|
||||
}).unwrap_or_else(|| Err(errors::invalid_params("Unknown RequestID", id)))
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use jsonrpc_core::*;
|
||||
use v1::traits::Rpc;
|
||||
use v1::helpers::params::expect_no_params;
|
||||
|
||||
/// RPC generic methods implementation.
|
||||
pub struct RpcClient {
|
||||
@@ -39,7 +40,8 @@ impl RpcClient {
|
||||
}
|
||||
|
||||
impl Rpc for RpcClient {
|
||||
fn rpc_modules(&self, _: Params) -> Result<Value, Error> {
|
||||
fn rpc_modules(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(expect_no_params(params));
|
||||
let modules = self.modules.iter()
|
||||
.fold(BTreeMap::new(), |mut map, (k, v)| {
|
||||
map.insert(k.to_owned(), Value::String(v.to_owned()));
|
||||
@@ -48,7 +50,8 @@ impl Rpc for RpcClient {
|
||||
Ok(Value::Object(modules))
|
||||
}
|
||||
|
||||
fn modules(&self, _: Params) -> Result<Value, Error> {
|
||||
fn modules(&self, params: Params) -> Result<Value, Error> {
|
||||
try!(expect_no_params(params));
|
||||
let modules = self.modules.iter()
|
||||
.filter(|&(k, _v)| {
|
||||
self.valid_apis.contains(k)
|
||||
|
||||
@@ -23,9 +23,9 @@ use ethcore::client::{BlockChainClient, CallAnalytics, TransactionID, TraceId};
|
||||
use ethcore::miner::MinerService;
|
||||
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
|
||||
use v1::traits::Traces;
|
||||
use v1::helpers::CallRequest as CRequest;
|
||||
use v1::helpers::{errors, CallRequest as CRequest};
|
||||
use v1::helpers::params::from_params_default_third;
|
||||
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, H256};
|
||||
use v1::impls::from_params_default_third;
|
||||
|
||||
fn to_call_analytics(flags: Vec<String>) -> CallAnalytics {
|
||||
CallAnalytics {
|
||||
@@ -144,7 +144,7 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
|
||||
Ok(e) => to_value(&TraceResults::from(e)),
|
||||
_ => Ok(Value::Null),
|
||||
},
|
||||
Err(_) => Err(Error::invalid_params()),
|
||||
Err(e) => Err(errors::invalid_params("Transaction is not valid RLP", e)),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use jsonrpc_core::*;
|
||||
use util::version;
|
||||
use v1::traits::Web3;
|
||||
use v1::types::{H256, Bytes};
|
||||
use v1::helpers::params::expect_no_params;
|
||||
use util::sha3::Hashable;
|
||||
|
||||
/// Web3 rpc implementation.
|
||||
@@ -31,10 +32,8 @@ impl Web3Client {
|
||||
|
||||
impl Web3 for Web3Client {
|
||||
fn client_version(&self, params: Params) -> Result<Value, Error> {
|
||||
match params {
|
||||
Params::None => Ok(Value::String(version().to_owned().replace("Parity/", "Parity//"))),
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
try!(expect_no_params(params));
|
||||
Ok(Value::String(version().to_owned().replace("Parity/", "Parity//")))
|
||||
}
|
||||
|
||||
fn sha3(&self, params: Params) -> Result<Value, Error> {
|
||||
|
||||
@@ -18,8 +18,9 @@
|
||||
//!
|
||||
//! Compliant with ethereum rpc.
|
||||
|
||||
mod impls;
|
||||
#[macro_use]
|
||||
mod helpers;
|
||||
mod impls;
|
||||
|
||||
pub mod traits;
|
||||
pub mod tests;
|
||||
|
||||
@@ -15,13 +15,16 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::sync::Arc;
|
||||
use util::log::RotatingLogger;
|
||||
use util::U256;
|
||||
use ethsync::ManageNetwork;
|
||||
use ethcore::client::{TestBlockChainClient};
|
||||
|
||||
use jsonrpc_core::IoHandler;
|
||||
use v1::{Ethcore, EthcoreClient};
|
||||
use v1::tests::helpers::TestMinerService;
|
||||
use v1::helpers::ConfirmationsQueue;
|
||||
use ethcore::client::{TestBlockChainClient};
|
||||
use util::log::RotatingLogger;
|
||||
use v1::helpers::NetworkSettings;
|
||||
use v1::helpers::{ConfirmationsQueue, NetworkSettings};
|
||||
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService};
|
||||
use super::manage_network::TestManageNetwork;
|
||||
|
||||
fn miner_service() -> Arc<TestMinerService> {
|
||||
Arc::new(TestMinerService::default())
|
||||
@@ -31,6 +34,13 @@ fn client_service() -> Arc<TestBlockChainClient> {
|
||||
Arc::new(TestBlockChainClient::default())
|
||||
}
|
||||
|
||||
fn sync_provider() -> Arc<TestSyncProvider> {
|
||||
Arc::new(TestSyncProvider::new(Config {
|
||||
network_id: U256::from(3),
|
||||
num_peers: 120,
|
||||
}))
|
||||
}
|
||||
|
||||
fn logger() -> Arc<RotatingLogger> {
|
||||
Arc::new(RotatingLogger::new("rpc=trace".to_owned()))
|
||||
}
|
||||
@@ -39,8 +49,6 @@ fn settings() -> Arc<NetworkSettings> {
|
||||
Arc::new(NetworkSettings {
|
||||
name: "mynode".to_owned(),
|
||||
chain: "testchain".to_owned(),
|
||||
min_peers: 25,
|
||||
max_peers: 25,
|
||||
network_port: 30303,
|
||||
rpc_enabled: true,
|
||||
rpc_interface: "all".to_owned(),
|
||||
@@ -48,16 +56,26 @@ fn settings() -> Arc<NetworkSettings> {
|
||||
})
|
||||
}
|
||||
|
||||
fn ethcore_client(client: &Arc<TestBlockChainClient>, miner: &Arc<TestMinerService>) -> EthcoreClient<TestBlockChainClient, TestMinerService> {
|
||||
EthcoreClient::new(client, miner, logger(), settings(), None)
|
||||
fn network_service() -> Arc<ManageNetwork> {
|
||||
Arc::new(TestManageNetwork)
|
||||
}
|
||||
|
||||
fn ethcore_client(
|
||||
client: &Arc<TestBlockChainClient>,
|
||||
miner: &Arc<TestMinerService>,
|
||||
sync: &Arc<TestSyncProvider>,
|
||||
net: &Arc<ManageNetwork>) -> EthcoreClient<TestBlockChainClient, TestMinerService, TestSyncProvider> {
|
||||
EthcoreClient::new(client, miner, sync, net, logger(), settings(), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_ethcore_extra_data() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_extraData", "params": [], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"0x01020304","id":1}"#;
|
||||
@@ -72,8 +90,10 @@ fn rpc_ethcore_default_extra_data() {
|
||||
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_defaultExtraData", "params": [], "id": 1}"#;
|
||||
let response = format!(r#"{{"jsonrpc":"2.0","result":"0x{}","id":1}}"#, misc::version_data().to_hex());
|
||||
@@ -85,8 +105,10 @@ fn rpc_ethcore_default_extra_data() {
|
||||
fn rpc_ethcore_gas_floor_target() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_gasFloorTarget", "params": [], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"0x3039","id":1}"#;
|
||||
@@ -98,8 +120,10 @@ fn rpc_ethcore_gas_floor_target() {
|
||||
fn rpc_ethcore_min_gas_price() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_minGasPrice", "params": [], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"0x01312d00","id":1}"#;
|
||||
@@ -111,10 +135,12 @@ fn rpc_ethcore_min_gas_price() {
|
||||
fn rpc_ethcore_dev_logs() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let logger = logger();
|
||||
logger.append("a".to_owned());
|
||||
logger.append("b".to_owned());
|
||||
let ethcore = EthcoreClient::new(&client, &miner, logger.clone(), settings(), None).to_delegate();
|
||||
let ethcore = EthcoreClient::new(&client, &miner, &sync, &net, logger.clone(), settings(), None).to_delegate();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
@@ -128,8 +154,10 @@ fn rpc_ethcore_dev_logs() {
|
||||
fn rpc_ethcore_dev_logs_levels() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogsLevels", "params":[], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"rpc=trace","id":1}"#;
|
||||
@@ -141,8 +169,10 @@ fn rpc_ethcore_dev_logs_levels() {
|
||||
fn rpc_ethcore_transactions_limit() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_transactionsLimit", "params":[], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":1024,"id":1}"#;
|
||||
@@ -154,8 +184,10 @@ fn rpc_ethcore_transactions_limit() {
|
||||
fn rpc_ethcore_net_chain() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"testchain","id":1}"#;
|
||||
@@ -164,14 +196,16 @@ fn rpc_ethcore_net_chain() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rpc_ethcore_net_max_peers() {
|
||||
fn rpc_ethcore_net_peers() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netMaxPeers", "params":[], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":25,"id":1}"#;
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPeers", "params":[], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"active":0,"connected":120,"max":50},"id":1}"#;
|
||||
|
||||
assert_eq!(io.handle_request(request), Some(response.to_owned()));
|
||||
}
|
||||
@@ -180,8 +214,10 @@ fn rpc_ethcore_net_max_peers() {
|
||||
fn rpc_ethcore_net_port() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":30303,"id":1}"#;
|
||||
@@ -193,8 +229,10 @@ fn rpc_ethcore_net_port() {
|
||||
fn rpc_ethcore_rpc_settings() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_rpcSettings", "params":[], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":{"enabled":true,"interface":"all","port":8545},"id":1}"#;
|
||||
@@ -206,8 +244,10 @@ fn rpc_ethcore_rpc_settings() {
|
||||
fn rpc_ethcore_node_name() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","result":"mynode","id":1}"#;
|
||||
@@ -219,9 +259,11 @@ fn rpc_ethcore_node_name() {
|
||||
fn rpc_ethcore_unsigned_transactions_count() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
let queue = Arc::new(ConfirmationsQueue::default());
|
||||
let ethcore = EthcoreClient::new(&client, &miner, logger(), settings(), Some(queue)).to_delegate();
|
||||
let ethcore = EthcoreClient::new(&client, &miner, &sync, &net, logger(), settings(), Some(queue)).to_delegate();
|
||||
io.add_delegate(ethcore);
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#;
|
||||
@@ -234,8 +276,10 @@ fn rpc_ethcore_unsigned_transactions_count() {
|
||||
fn rpc_ethcore_unsigned_transactions_count_when_signer_disabled() {
|
||||
let miner = miner_service();
|
||||
let client = client_service();
|
||||
let sync = sync_provider();
|
||||
let net = network_service();
|
||||
let io = IoHandler::new();
|
||||
io.add_delegate(ethcore_client(&client, &miner).to_delegate());
|
||||
io.add_delegate(ethcore_client(&client, &miner, &sync, &net).to_delegate());
|
||||
|
||||
let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#;
|
||||
let response = r#"{"jsonrpc":"2.0","error":{"code":-32030,"message":"Trusted Signer is disabled. This API is not available.","data":null},"id":1}"#;
|
||||
|
||||
@@ -45,8 +45,8 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
|
||||
/// Returns chain name
|
||||
fn net_chain(&self, _: Params) -> Result<Value, Error>;
|
||||
|
||||
/// Returns max peers
|
||||
fn net_max_peers(&self, _: Params) -> Result<Value, Error>;
|
||||
/// Returns peers details
|
||||
fn net_peers(&self, _: Params) -> Result<Value, Error>;
|
||||
|
||||
/// Returns network port
|
||||
fn net_port(&self, _: Params) -> Result<Value, Error>;
|
||||
@@ -79,7 +79,7 @@ pub trait Ethcore: Sized + Send + Sync + 'static {
|
||||
delegate.add_method("ethcore_devLogs", Ethcore::dev_logs);
|
||||
delegate.add_method("ethcore_devLogsLevels", Ethcore::dev_logs_levels);
|
||||
delegate.add_method("ethcore_netChain", Ethcore::net_chain);
|
||||
delegate.add_method("ethcore_netMaxPeers", Ethcore::net_max_peers);
|
||||
delegate.add_method("ethcore_netPeers", Ethcore::net_peers);
|
||||
delegate.add_method("ethcore_netPort", Ethcore::net_port);
|
||||
delegate.add_method("ethcore_rpcSettings", Ethcore::rpc_settings);
|
||||
delegate.add_method("ethcore_nodeName", Ethcore::node_name);
|
||||
|
||||
@@ -40,7 +40,7 @@ pub use self::filter::Filter;
|
||||
pub use self::hash::{H64, H160, H256, H520, H2048};
|
||||
pub use self::index::Index;
|
||||
pub use self::log::Log;
|
||||
pub use self::sync::{SyncStatus, SyncInfo};
|
||||
pub use self::sync::{SyncStatus, SyncInfo, Peers};
|
||||
pub use self::transaction::Transaction;
|
||||
pub use self::transaction_request::TransactionRequest;
|
||||
pub use self::receipt::Receipt;
|
||||
|
||||
@@ -31,6 +31,17 @@ pub struct SyncInfo {
|
||||
pub highest_block: U256,
|
||||
}
|
||||
|
||||
/// Peers info
|
||||
#[derive(Default, Debug, Serialize, PartialEq)]
|
||||
pub struct Peers {
|
||||
/// Number of active peers
|
||||
pub active: usize,
|
||||
/// Number of connected peers
|
||||
pub connected: usize,
|
||||
/// Max number of peers
|
||||
pub max: u32,
|
||||
}
|
||||
|
||||
/// Sync status
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SyncStatus {
|
||||
@@ -53,7 +64,7 @@ impl Serialize for SyncStatus {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serde_json;
|
||||
use super::{SyncInfo, SyncStatus};
|
||||
use super::{SyncInfo, SyncStatus, Peers};
|
||||
|
||||
#[test]
|
||||
fn test_serialize_sync_info() {
|
||||
@@ -62,6 +73,13 @@ mod tests {
|
||||
assert_eq!(serialized, r#"{"startingBlock":"0x00","currentBlock":"0x00","highestBlock":"0x00"}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_peers() {
|
||||
let t = Peers::default();
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
assert_eq!(serialized, r#"{"active":0,"connected":0,"max":0}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialize_sync_status() {
|
||||
let t = SyncStatus::None;
|
||||
|
||||
Reference in New Issue
Block a user