diff --git a/parity/configuration.rs b/parity/configuration.rs index 3f8202021..21a8569d5 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -155,7 +155,6 @@ impl Configuration { pub fn init_reserved_nodes(&self) -> Vec { use std::fs::File; - use std::io::BufRead; if let Some(ref path) = self.args.flag_reserved_peers { let mut buffer = String::new(); diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index bf21181a1..3497f21a7 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -160,7 +160,8 @@ pub fn setup_rpc(server: T, deps: Arc, apis: ApiSet server.add_delegate(SignerClient::new(&deps.secret_store, &deps.client, &deps.miner, &deps.signer_queue).to_delegate()); }, Api::Ethcore => { - server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone()).to_delegate()) + let queue = deps.signer_port.map(|_| deps.signer_queue.clone()); + server.add_delegate(EthcoreClient::new(&deps.client, &deps.miner, deps.logger.clone(), deps.settings.clone(), queue).to_delegate()) }, Api::EthcoreSet => { server.add_delegate(EthcoreSetClient::new(&deps.miner).to_delegate()) diff --git a/rpc/src/v1/helpers/signing_queue.rs b/rpc/src/v1/helpers/signing_queue.rs index dd59ce967..3d7f9e35b 100644 --- a/rpc/src/v1/helpers/signing_queue.rs +++ b/rpc/src/v1/helpers/signing_queue.rs @@ -69,6 +69,12 @@ pub trait SigningQueue: Send + Sync { /// Return copy of all the requests in the queue. fn requests(&self) -> Vec; + + /// Returns number of transactions awaiting confirmation. + fn len(&self) -> usize; + + /// Returns true if there are no transactions awaiting confirmation. + fn is_empty(&self) -> bool; } #[derive(Debug, PartialEq)] @@ -277,6 +283,16 @@ impl SigningQueue for ConfirmationsQueue { let queue = self.queue.read().unwrap(); queue.values().map(|token| token.request.clone()).collect() } + + fn len(&self) -> usize { + let queue = self.queue.read().unwrap(); + queue.len() + } + + fn is_empty(&self) -> bool { + let queue = self.queue.read().unwrap(); + queue.is_empty() + } } diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index e77f46f5d..3a8b8a4a0 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -26,6 +26,8 @@ use jsonrpc_core::*; use ethcore::miner::MinerService; use v1::traits::Ethcore; use v1::types::{Bytes}; +use v1::helpers::{SigningQueue, ConfirmationsQueue}; +use v1::impls::error_codes; /// Ethcore implementation. pub struct EthcoreClient where @@ -36,16 +38,18 @@ pub struct EthcoreClient where miner: Weak, logger: Arc, settings: Arc, + confirmations_queue: Option>, } impl EthcoreClient where C: MiningBlockChainClient, M: MinerService { /// Creates new `EthcoreClient`. - pub fn new(client: &Arc, miner: &Arc, logger: Arc, settings: Arc) -> Self { + pub fn new(client: &Arc, miner: &Arc, logger: Arc, settings: Arc, queue: Option>) -> Self { EthcoreClient { client: Arc::downgrade(client), miner: Arc::downgrade(miner), logger: logger, settings: settings, + confirmations_queue: queue, } } } @@ -120,4 +124,15 @@ impl Ethcore for EthcoreClient where M: MinerService + 'static, C: M _ => Err(Error::invalid_params()), } } + + fn unsigned_transactions_count(&self, _params: Params) -> Result { + match self.confirmations_queue { + None => Err(Error { + code: ErrorCode::ServerError(error_codes::SIGNER_DISABLED), + message: "Trusted Signer is disabled. This API is not available.".into(), + data: None + }), + Some(ref queue) => to_value(&queue.len()), + } + } } diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index efca09091..099585f60 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -71,6 +71,7 @@ mod error_codes { pub const UNKNOWN_ERROR: i64 = -32002; pub const TRANSACTION_ERROR: i64 = -32010; pub const ACCOUNT_LOCKED: i64 = -32020; + pub const SIGNER_DISABLED: i64 = -32030; } fn dispatch_transaction(client: &C, miner: &M, signed_transaction: SignedTransaction) -> Result diff --git a/rpc/src/v1/tests/mocked/ethcore.rs b/rpc/src/v1/tests/mocked/ethcore.rs index 68c33ecce..2ac7bc66d 100644 --- a/rpc/src/v1/tests/mocked/ethcore.rs +++ b/rpc/src/v1/tests/mocked/ethcore.rs @@ -15,14 +15,11 @@ // along with Parity. If not, see . use std::sync::Arc; -use std::str::FromStr; use jsonrpc_core::IoHandler; -use v1::{Ethcore, EthcoreClient, EthcoreSet, EthcoreSetClient}; -use ethcore::miner::MinerService; +use v1::{Ethcore, EthcoreClient}; use v1::tests::helpers::TestMinerService; +use v1::helpers::ConfirmationsQueue; use ethcore::client::{TestBlockChainClient}; -use util::numbers::*; -use rustc_serialize::hex::FromHex; use util::log::RotatingLogger; use util::network_settings::NetworkSettings; @@ -51,11 +48,7 @@ fn settings() -> Arc { } fn ethcore_client(client: &Arc, miner: &Arc) -> EthcoreClient { - EthcoreClient::new(client, miner, logger(), settings()) -} - -fn ethcore_set_client(miner: &Arc) -> EthcoreSetClient { - EthcoreSetClient::new(miner) + EthcoreClient::new(client, miner, logger(), settings(), None) } #[test] @@ -64,7 +57,6 @@ fn rpc_ethcore_extra_data() { let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_extraData", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"0x01020304","id":1}"#; @@ -81,7 +73,6 @@ fn rpc_ethcore_default_extra_data() { let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).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()); @@ -95,7 +86,6 @@ fn rpc_ethcore_gas_floor_target() { let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_gasFloorTarget", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"0x3039","id":1}"#; @@ -109,7 +99,6 @@ fn rpc_ethcore_min_gas_price() { let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_minGasPrice", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"0x01312d00","id":1}"#; @@ -117,66 +106,6 @@ fn rpc_ethcore_min_gas_price() { assert_eq!(io.handle_request(request), Some(response.to_owned())); } -#[test] -fn rpc_ethcore_set_min_gas_price() { - let miner = miner_service(); - let client = client_service(); - let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); - - let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; - - assert_eq!(io.handle_request(request), Some(response.to_owned())); - assert_eq!(miner.minimal_gas_price(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); -} - -#[test] -fn rpc_ethcore_set_gas_floor_target() { - let miner = miner_service(); - let client = client_service(); - let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); - - let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; - - assert_eq!(io.handle_request(request), Some(response.to_owned())); - assert_eq!(miner.gas_floor_target(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); -} - -#[test] -fn rpc_ethcore_set_extra_data() { - let miner = miner_service(); - let client = client_service(); - let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); - - let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; - - assert_eq!(io.handle_request(request), Some(response.to_owned())); - assert_eq!(miner.extra_data(), "cd1722f3947def4cf144679da39c4c32bdc35681".from_hex().unwrap()); -} - -#[test] -fn rpc_ethcore_set_author() { - let miner = miner_service(); - let client = client_service(); - let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); - - let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; - - assert_eq!(io.handle_request(request), Some(response.to_owned())); - assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); -} - #[test] fn rpc_ethcore_dev_logs() { let miner = miner_service(); @@ -184,10 +113,9 @@ fn rpc_ethcore_dev_logs() { let logger = logger(); logger.append("a".to_owned()); logger.append("b".to_owned()); - let ethcore = EthcoreClient::new(&client, &miner, logger.clone(), settings()).to_delegate(); + let ethcore = EthcoreClient::new(&client, &miner, logger.clone(), settings(), None).to_delegate(); let io = IoHandler::new(); io.add_delegate(ethcore); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_devLogs", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["b","a"],"id":1}"#; @@ -201,35 +129,18 @@ fn rpc_ethcore_dev_logs_levels() { let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).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}"#; assert_eq!(io.handle_request(request), Some(response.to_owned())); } -#[test] -fn rpc_ethcore_set_transactions_limit() { - let miner = miner_service(); - let client = client_service(); - let io = IoHandler::new(); - io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); - - let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setTransactionsLimit", "params":[10240240], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; - - assert_eq!(io.handle_request(request), Some(response.to_owned())); - assert_eq!(miner.transactions_limit(), 10_240_240); -} - #[test] fn rpc_ethcore_transactions_limit() { let miner = miner_service(); let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_transactionsLimit", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":1024,"id":1}"#; @@ -243,7 +154,6 @@ fn rpc_ethcore_net_chain() { let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netChain", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"testchain","id":1}"#; @@ -257,7 +167,6 @@ fn rpc_ethcore_net_max_peers() { let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netMaxPeers", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":25,"id":1}"#; @@ -271,7 +180,6 @@ fn rpc_ethcore_net_port() { let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_netPort", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":30303,"id":1}"#; @@ -285,7 +193,6 @@ fn rpc_ethcore_rpc_settings() { let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).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}"#; @@ -299,10 +206,37 @@ fn rpc_ethcore_node_name() { let client = client_service(); let io = IoHandler::new(); io.add_delegate(ethcore_client(&client, &miner).to_delegate()); - io.add_delegate(ethcore_set_client(&miner).to_delegate()); let request = r#"{"jsonrpc": "2.0", "method": "ethcore_nodeName", "params":[], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":"mynode","id":1}"#; assert_eq!(io.handle_request(request), Some(response.to_owned())); } + +#[test] +fn rpc_ethcore_unsigned_transactions_count() { + let miner = miner_service(); + let client = client_service(); + let io = IoHandler::new(); + let queue = Arc::new(ConfirmationsQueue::default()); + let ethcore = EthcoreClient::new(&client, &miner, logger(), settings(), Some(queue)).to_delegate(); + io.add_delegate(ethcore); + + let request = r#"{"jsonrpc": "2.0", "method": "ethcore_unsignedTransactionsCount", "params":[], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":0,"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} + +#[test] +fn rpc_ethcore_unsigned_transactions_count_when_signer_disabled() { + let miner = miner_service(); + let client = client_service(); + let io = IoHandler::new(); + io.add_delegate(ethcore_client(&client, &miner).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}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); +} diff --git a/rpc/src/v1/tests/mocked/ethcore_set.rs b/rpc/src/v1/tests/mocked/ethcore_set.rs new file mode 100644 index 000000000..9602eeeda --- /dev/null +++ b/rpc/src/v1/tests/mocked/ethcore_set.rs @@ -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 . + +use std::sync::Arc; +use std::str::FromStr; +use jsonrpc_core::IoHandler; +use v1::{EthcoreSet, EthcoreSetClient}; +use ethcore::miner::MinerService; +use v1::tests::helpers::TestMinerService; +use util::numbers::*; +use rustc_serialize::hex::FromHex; + +fn miner_service() -> Arc { + Arc::new(TestMinerService::default()) +} + +fn ethcore_set_client(miner: &Arc) -> EthcoreSetClient { + EthcoreSetClient::new(miner) +} + +#[test] +fn rpc_ethcore_set_min_gas_price() { + let miner = miner_service(); + let io = IoHandler::new(); + io.add_delegate(ethcore_set_client(&miner).to_delegate()); + + let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setMinGasPrice", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); + assert_eq!(miner.minimal_gas_price(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); +} +#[test] +fn rpc_ethcore_set_gas_floor_target() { + let miner = miner_service(); + let io = IoHandler::new(); + io.add_delegate(ethcore_set_client(&miner).to_delegate()); + + let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setGasFloorTarget", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); + assert_eq!(miner.gas_floor_target(), U256::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); +} + +#[test] +fn rpc_ethcore_set_extra_data() { + let miner = miner_service(); + let io = IoHandler::new(); + io.add_delegate(ethcore_set_client(&miner).to_delegate()); + + let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setExtraData", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); + assert_eq!(miner.extra_data(), "cd1722f3947def4cf144679da39c4c32bdc35681".from_hex().unwrap()); +} + +#[test] +fn rpc_ethcore_set_author() { + let miner = miner_service(); + let io = IoHandler::new(); + io.add_delegate(ethcore_set_client(&miner).to_delegate()); + + let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setAuthor", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681"], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); + assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); +} + +#[test] +fn rpc_ethcore_set_transactions_limit() { + let miner = miner_service(); + let io = IoHandler::new(); + io.add_delegate(ethcore_set_client(&miner).to_delegate()); + + let request = r#"{"jsonrpc": "2.0", "method": "ethcore_setTransactionsLimit", "params":[10240240], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_owned())); + assert_eq!(miner.transactions_limit(), 10_240_240); +} diff --git a/rpc/src/v1/tests/mocked/mod.rs b/rpc/src/v1/tests/mocked/mod.rs index 986dbfdef..503c75c12 100644 --- a/rpc/src/v1/tests/mocked/mod.rs +++ b/rpc/src/v1/tests/mocked/mod.rs @@ -24,4 +24,5 @@ mod web3; mod personal; mod personal_signer; mod ethcore; +mod ethcore_set; mod rpc; diff --git a/rpc/src/v1/traits/ethcore.rs b/rpc/src/v1/traits/ethcore.rs index 1dd00ff73..32855727f 100644 --- a/rpc/src/v1/traits/ethcore.rs +++ b/rpc/src/v1/traits/ethcore.rs @@ -60,6 +60,10 @@ pub trait Ethcore: Sized + Send + Sync + 'static { /// Returns distribution of gas price in latest blocks. fn gas_price_statistics(&self, _: Params) -> Result; + /// Returns number of unsigned transactions waiting in the signer queue (if signer enabled) + /// Returns error when signer is disabled + fn unsigned_transactions_count(&self, _: Params) -> Result; + /// Should be used to convert object to io delegate. fn to_delegate(self) -> IoDelegate { let mut delegate = IoDelegate::new(Arc::new(self)); @@ -77,6 +81,7 @@ pub trait Ethcore: Sized + Send + Sync + 'static { delegate.add_method("ethcore_nodeName", Ethcore::node_name); delegate.add_method("ethcore_defaultExtraData", Ethcore::default_extra_data); delegate.add_method("ethcore_gasPriceStatistics", Ethcore::gas_price_statistics); + delegate.add_method("ethcore_unsignedTransactionsCount", Ethcore::unsigned_transactions_count); delegate }