diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 0c50d85aa..ef4415934 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -45,6 +45,7 @@ use block::*; use transaction::{LocalizedTransaction, SignedTransaction, Action}; use blockchain::extras::TransactionAddress; use types::filter::Filter; +use types::mode::Mode as IpcMode; use log_entry::LocalizedLogEntry; use verification::queue::BlockQueue; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; @@ -123,7 +124,7 @@ impl SleepState { /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. /// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue. pub struct Client { - mode: Mode, + mode: Mutex, chain: RwLock>, tracedb: RwLock>, engine: Arc, @@ -221,7 +222,7 @@ impl Client { let client = Client { sleep_state: Mutex::new(SleepState::new(awake)), liveness: AtomicBool::new(awake), - mode: config.mode.clone(), + mode: Mutex::new(config.mode.clone()), chain: RwLock::new(chain), tracedb: tracedb, engine: engine, @@ -614,7 +615,8 @@ impl Client { self.block_queue.collect_garbage(); self.tracedb.read().collect_garbage(); - match self.mode { + let mode = self.mode.lock().clone(); + match mode { Mode::Dark(timeout) => { let mut ss = self.sleep_state.lock(); if let Some(t) = ss.last_activity { @@ -838,12 +840,24 @@ impl BlockChainClient for Client { } fn keep_alive(&self) { - if self.mode != Mode::Active { + let mode = self.mode.lock().clone(); + if mode != Mode::Active { self.wake_up(); (*self.sleep_state.lock()).last_activity = Some(Instant::now()); } } + fn mode(&self) -> IpcMode { self.mode.lock().clone().into() } + + fn set_mode(&self, mode: IpcMode) { + *self.mode.lock() = mode.clone().into(); + match mode { + IpcMode::Active => self.wake_up(), + IpcMode::Off => self.sleep(), + _ => {(*self.sleep_state.lock()).last_activity = Some(Instant::now()); } + } + } + fn best_block_header(&self) -> Bytes { self.chain.read().best_block_header() } diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index 850e5c938..c4aeba8a4 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -76,6 +76,8 @@ pub enum Mode { /// Goes offline after RLP is inactive for some (given) time and /// stays inactive. Dark(Duration), + /// Always off. + Off, } impl Default for Mode { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 11a9286da..29a48f02f 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -37,6 +37,7 @@ use error::{ImportResult}; use evm::{Factory as EvmFactory, VMType, Schedule}; use miner::{Miner, MinerService, TransactionImportResult}; use spec::Spec; +use types::mode::Mode; use verification::queue::QueueInfo; use block::{OpenBlock, SealedBlock}; @@ -625,4 +626,8 @@ impl BlockChainClient for TestBlockChainClient { fn pending_transactions(&self) -> Vec { self.miner.pending_transactions(self.chain_info().best_block_number) } + + fn mode(&self) -> Mode { Mode::Active } + + fn set_mode(&self, _: Mode) { unimplemented!(); } } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 8f6532c1a..d7844ba3d 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -38,6 +38,7 @@ use block_import_error::BlockImportError; use ipc::IpcConfig; use types::blockchain_info::BlockChainInfo; use types::block_status::BlockStatus; +use types::mode::Mode; #[ipc(client_ident="RemoteClient")] /// Blockchain database client. Owns and manages a blockchain and a block queue. @@ -225,6 +226,10 @@ pub trait BlockChainClient : Sync + Send { let (corpus, _) = raw_corpus.split_at(raw_len-raw_len/40); Histogram::new(corpus, bucket_number) } + + fn mode(&self) -> Mode; + + fn set_mode(&self, mode: Mode); } /// Extended client interface used for mining diff --git a/ethcore/src/types/mod.rs.in b/ethcore/src/types/mod.rs.in index 32c7faabe..1d2cdb3c0 100644 --- a/ethcore/src/types/mod.rs.in +++ b/ethcore/src/types/mod.rs.in @@ -33,3 +33,4 @@ pub mod transaction_import; pub mod block_import_error; pub mod restoration_status; pub mod snapshot_manifest; +pub mod mode; \ No newline at end of file diff --git a/ethcore/src/types/mode.rs b/ethcore/src/types/mode.rs new file mode 100644 index 000000000..b48a92a89 --- /dev/null +++ b/ethcore/src/types/mode.rs @@ -0,0 +1,55 @@ +// 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 . + +//! Mode type + +pub use std::time::Duration; +use client::Mode as ClientMode; + +/// IPC-capable shadow-type for client::config::Mode +#[derive(Clone, Binary)] +pub enum Mode { + /// Same as ClientMode::Off. + Off, + /// Same as ClientMode::Dark; values in seconds. + Dark(u64), + /// Same as ClientMode::Passive; values in seconds. + Passive(u64, u64), + /// Same as ClientMode::Active. + Active, +} + +impl From for Mode { + fn from(mode: ClientMode) -> Self { + match mode { + ClientMode::Off => Mode::Off, + ClientMode::Dark(timeout) => Mode::Dark(timeout.as_secs()), + ClientMode::Passive(timeout, alarm) => Mode::Passive(timeout.as_secs(), alarm.as_secs()), + ClientMode::Active => Mode::Active, + } + } +} + +impl From for ClientMode { + fn from(mode: Mode) -> Self { + match mode { + Mode::Off => ClientMode::Off, + Mode::Dark(timeout) => ClientMode::Dark(Duration::from_secs(timeout)), + Mode::Passive(timeout, alarm) => ClientMode::Passive(Duration::from_secs(timeout), Duration::from_secs(alarm)), + Mode::Active => ClientMode::Active, + } + } +} \ No newline at end of file diff --git a/js/src/api/rpc/ethcore/ethcore.js b/js/src/api/rpc/ethcore/ethcore.js index b775208f0..663143f0d 100644 --- a/js/src/api/rpc/ethcore/ethcore.js +++ b/js/src/api/rpc/ethcore/ethcore.js @@ -91,6 +91,11 @@ export default class Ethcore { .then(outNumber); } + mode () { + return this._transport + .execute('ethcore_mode'); + } + netChain () { return this._transport .execute('ethcore_netChain'); @@ -161,6 +166,11 @@ export default class Ethcore { .execute('ethcore_setMinGasPrice', inNumber16(quantity)); } + setMode (mode) { + return this._transport + .execute('ethcore_setMode', mode); + } + setTransactionsLimit (quantity) { return this._transport .execute('ethcore_setTransactionsLimit', inNumber16(quantity)); diff --git a/js/src/jsonrpc/interfaces/ethcore.js b/js/src/jsonrpc/interfaces/ethcore.js index 07c6fed2c..c81a82f76 100644 --- a/js/src/jsonrpc/interfaces/ethcore.js +++ b/js/src/jsonrpc/interfaces/ethcore.js @@ -156,6 +156,15 @@ export default { } }, + mode: { + desc: 'Get the mode. Results one of: "active", "passive", "dark", "off".', + params: [], + returns: { + type: String, + desc: 'The mode' + } + }, + netChain: { desc: 'Returns the name of the connected chain.', params: [], @@ -307,6 +316,20 @@ export default { } }, + setMode: { + desc: 'Changes the mode', + params: [ + { + type: String, + desc: 'The mode to set, one of "active", "passive", "dark", "off"' + } + ], + returns: { + type: Boolean, + desc: 'True if the call succeeded' + } + }, + setTransactionsLimit: { desc: 'Changes limit for transactions in queue.', params: [ diff --git a/rpc/src/v1/impls/ethcore.rs b/rpc/src/v1/impls/ethcore.rs index bcb067d03..dbb27037c 100644 --- a/rpc/src/v1/impls/ethcore.rs +++ b/rpc/src/v1/impls/ethcore.rs @@ -30,6 +30,7 @@ use ethsync::{SyncProvider, ManageNetwork}; use ethcore::miner::MinerService; use ethcore::client::{MiningBlockChainClient}; use ethcore::ids::BlockID; +use ethcore::mode::Mode; use jsonrpc_core::Error; use v1::traits::Ethcore; @@ -343,4 +344,13 @@ impl Ethcore for EthcoreClient where .into() ) } + + fn mode(&self) -> Result { + Ok(match take_weak!(self.client).mode() { + Mode::Off => "off", + Mode::Dark(..) => "dark", + Mode::Passive(..) => "passive", + Mode::Active => "active", + }.into()) + } } diff --git a/rpc/src/v1/impls/ethcore_set.rs b/rpc/src/v1/impls/ethcore_set.rs index 7bebf9bbb..27464cff3 100644 --- a/rpc/src/v1/impls/ethcore_set.rs +++ b/rpc/src/v1/impls/ethcore_set.rs @@ -19,6 +19,7 @@ use std::sync::{Arc, Weak}; use jsonrpc_core::*; use ethcore::miner::MinerService; use ethcore::client::MiningBlockChainClient; +use ethcore::mode::Mode; use ethsync::ManageNetwork; use v1::helpers::errors; use v1::traits::EthcoreSet; @@ -147,4 +148,15 @@ impl EthcoreSet for EthcoreSetClient where take_weak!(self.net).stop_network(); Ok(true) } + + fn set_mode(&self, mode: String) -> Result { + take_weak!(self.client).set_mode(match mode.as_str() { + "off" => Mode::Off, + "dark" => Mode::Dark(300), + "passive" => Mode::Passive(300, 3600), + "active" => Mode::Active, + e => { return Err(errors::invalid_params("mode", e.to_owned())); }, + }); + Ok(true) + } } diff --git a/rpc/src/v1/traits/ethcore.rs b/rpc/src/v1/traits/ethcore.rs index 8ffc4a325..18279d364 100644 --- a/rpc/src/v1/traits/ethcore.rs +++ b/rpc/src/v1/traits/ethcore.rs @@ -129,5 +129,9 @@ build_rpc_trait! { /// Returns next nonce for particular sender. Should include all transactions in the queue. #[rpc(name = "ethcore_nextNonce")] fn next_nonce(&self, H160) -> Result; + + /// Get the mode. Results one of: "active", "passive", "dark", "off". + #[rpc(name = "ethcore_mode")] + fn mode(&self) -> Result; } } diff --git a/rpc/src/v1/traits/ethcore_set.rs b/rpc/src/v1/traits/ethcore_set.rs index 9946314d6..9c0d3d5d4 100644 --- a/rpc/src/v1/traits/ethcore_set.rs +++ b/rpc/src/v1/traits/ethcore_set.rs @@ -69,11 +69,19 @@ build_rpc_trait! { fn accept_non_reserved_peers(&self) -> Result; /// Start the network. + /// + /// Deprecated. Use `set_mode("active")` instead. #[rpc(name = "ethcore_startNetwork")] fn start_network(&self) -> Result; /// Stop the network. + /// + /// Deprecated. Use `set_mode("off")` instead. #[rpc(name = "ethcore_stopNetwork")] fn stop_network(&self) -> Result; + + /// Set the mode. Argument must be one of: "active", "passive", "dark", "off". + #[rpc(name = "ethcore_setMode")] + fn set_mode(&self, String) -> Result; } } \ No newline at end of file