diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index 90ebba39a..8205ae2ab 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -116,6 +116,9 @@ pub trait LightChainClient: Send + Sync { /// Query whether a block is known. fn is_known(&self, hash: &H256) -> bool; + /// Set the chain via a spec name. + fn set_spec_name(&self, new_spec_name: String) -> Result<(), ()>; + /// Clear the queue. fn clear_queue(&self); @@ -164,6 +167,8 @@ pub struct Client { listeners: RwLock>>, fetcher: T, verify_full: bool, + /// A closure to call when we want to restart the client + exit_handler: Mutex>>, } impl Client { @@ -190,6 +195,7 @@ impl Client { listeners: RwLock::new(vec![]), fetcher, verify_full: config.verify_full, + exit_handler: Mutex::new(None), }) } @@ -360,6 +366,14 @@ impl Client { self.chain.heap_size_of_children() } + /// Set a closure to call when the client wants to be restarted. + /// + /// The parameter passed to the callback is the name of the new chain spec to use after + /// the restart. + pub fn set_exit_handler(&self, f: F) where F: Fn(String) + 'static + Send { + *self.exit_handler.lock() = Some(Box::new(f)); + } + /// Get a handle to the verification engine. pub fn engine(&self) -> &Arc { &self.engine @@ -563,6 +577,17 @@ impl LightChainClient for Client { Client::engine(self) } + fn set_spec_name(&self, new_spec_name: String) -> Result<(), ()> { + trace!(target: "mode", "Client::set_spec_name({:?})", new_spec_name); + if let Some(ref h) = *self.exit_handler.lock() { + (*h)(new_spec_name); + Ok(()) + } else { + warn!("Not hypervised; cannot change chain."); + Err(()) + } + } + fn is_known(&self, hash: &H256) -> bool { self.status(hash) == BlockStatus::InChain } diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index d40fc3033..0be48a636 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1706,15 +1706,17 @@ impl BlockChainClient for Client { self.config.spec_name.clone() } - fn set_spec_name(&self, new_spec_name: String) { + fn set_spec_name(&self, new_spec_name: String) -> Result<(), ()> { trace!(target: "mode", "Client::set_spec_name({:?})", new_spec_name); if !self.enabled.load(AtomicOrdering::Relaxed) { - return; + return Err(()); } if let Some(ref h) = *self.exit_handler.lock() { (*h)(new_spec_name); + Ok(()) } else { warn!("Not hypervised; cannot change chain."); + Err(()) } } diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 5236f7cd4..fbad806fd 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -863,7 +863,7 @@ impl BlockChainClient for TestBlockChainClient { fn spec_name(&self) -> String { "foundation".into() } - fn set_spec_name(&self, _: String) { unimplemented!(); } + fn set_spec_name(&self, _: String) -> Result<(), ()> { unimplemented!(); } fn disable(&self) { self.disabled.store(true, AtomicOrder::Relaxed); } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 2bc702622..8e4abc01c 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -360,7 +360,7 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra fn spec_name(&self) -> String; /// Set the chain via a spec name. - fn set_spec_name(&self, spec_name: String); + fn set_spec_name(&self, spec_name: String) -> Result<(), ()>; /// Disable the client from importing blocks. This cannot be undone in this session and indicates /// that a subsystem has reason to believe this executable incapable of syncing the chain. diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index 4413e6a77..9287f6272 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -634,7 +634,7 @@ impl LightDependencies { handler.extend_with(ParityAccounts::to_delegate(ParityAccountsClient::new(&self.accounts))); } Api::ParitySet => handler.extend_with( - light::ParitySetClient::new(self.sync.clone(), self.fetch.clone()) + light::ParitySetClient::new(self.client.clone(), self.sync.clone(), self.fetch.clone()) .to_delegate(), ), Api::Traces => handler.extend_with(light::TracesClient.to_delegate()), diff --git a/parity/run.rs b/parity/run.rs index 13e93c1e2..c4a3c7512 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -165,7 +165,9 @@ impl ::local_store::NodeInfo for FullNodeInfo { type LightClient = ::light::client::Client<::light_helpers::EpochFetch>; // helper for light execution. -fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result { +fn execute_light_impl(cmd: RunCmd, logger: Arc, on_client_rq: Cr) -> Result + where Cr: Fn(String) + 'static + Send +{ use light::client as light_client; use sync::{LightSyncParams, LightSync, ManageNetwork}; use parking_lot::{Mutex, RwLock}; @@ -367,6 +369,8 @@ fn execute_light_impl(cmd: RunCmd, logger: Arc) -> Result(cmd: RunCmd, logger: Arc, Rr: Fn() + 'static + Send { if cmd.light { - execute_light_impl(cmd, logger) + execute_light_impl(cmd, logger, on_client_rq) } else { execute_impl(cmd, logger, on_client_rq, on_updater_rq) } diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index eebd76dbe..1ff40f979 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -59,6 +59,7 @@ mod codes { pub const NO_PEERS: i64 = -32066; pub const DEPRECATED: i64 = -32070; pub const EXPERIMENTAL_RPC: i64 = -32071; + pub const CANNOT_RESTART: i64 = -32080; } pub fn unimplemented(details: Option) -> Error { @@ -125,6 +126,14 @@ pub fn account(error: &str, details: T) -> Error { } } +pub fn cannot_restart() -> Error { + Error { + code: ErrorCode::ServerError(codes::CANNOT_RESTART), + message: "Parity could not be restarted. This feature is disabled in development mode and if the binary name isn't parity.".into(), + data: None, + } +} + /// Internal error signifying a logic error in code. /// Should not be used when function can just fail /// because of invalid parameters or incomplete node state. diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index da7425e1f..24dba420e 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -24,6 +24,7 @@ use crypto::DEFAULT_MAC; use ethkey::{crypto::ecies, Brain, Generator}; use ethstore::random_phrase; use sync::{LightSyncInfo, LightSyncProvider, LightNetworkDispatcher, ManageNetwork}; +use updater::VersionInfo as UpdaterVersionInfo; use ethereum_types::{H64, H160, H256, H512, U64, U256}; use ethcore_logger::RotatingLogger; @@ -299,7 +300,7 @@ where } fn version_info(&self) -> Result { - Err(errors::light_unimplemented(None)) + Ok(UpdaterVersionInfo::this().into()) } fn releases_info(&self) -> Result> { @@ -389,7 +390,7 @@ where } fn logs_no_tx_hash(&self, filter: Filter) -> BoxFuture> { - let filter = match filter.try_into() { + let filter = match filter.try_into() { Ok(value) => value, Err(err) => return Box::new(future::err(err)), }; diff --git a/rpc/src/v1/impls/light/parity_set.rs b/rpc/src/v1/impls/light/parity_set.rs index 080e9402a..f129f86b3 100644 --- a/rpc/src/v1/impls/light/parity_set.rs +++ b/rpc/src/v1/impls/light/parity_set.rs @@ -23,6 +23,7 @@ use std::sync::Arc; use ethereum_types::{H160, H256, U256}; use fetch::{self, Fetch}; use hash::keccak_buffer; +use light::client::LightChainClient; use sync::ManageNetwork; use jsonrpc_core::{Result, BoxFuture}; @@ -33,14 +34,16 @@ use v1::types::{Bytes, ReleaseInfo, Transaction}; /// Parity-specific rpc interface for operations altering the settings. pub struct ParitySetClient { + client: Arc, net: Arc, fetch: F, } impl ParitySetClient { /// Creates new `ParitySetClient` with given `Fetch`. - pub fn new(net: Arc, fetch: F) -> Self { + pub fn new(client: Arc, net: Arc, fetch: F) -> Self { ParitySetClient { + client: client, net: net, fetch: fetch, } @@ -118,8 +121,8 @@ impl ParitySet for ParitySetClient { Err(errors::light_unimplemented(None)) } - fn set_spec_name(&self, _spec_name: String) -> Result { - Err(errors::light_unimplemented(None)) + fn set_spec_name(&self, spec_name: String) -> Result { + self.client.set_spec_name(spec_name).map(|_| true).map_err(|()| errors::cannot_restart()) } fn hash_content(&self, url: String) -> BoxFuture { diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index a50138eb1..16ef8d543 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -211,8 +211,7 @@ impl ParitySet for ParitySetClient where } fn set_spec_name(&self, spec_name: String) -> Result { - self.client.set_spec_name(spec_name); - Ok(true) + self.client.set_spec_name(spec_name).map(|_| true).map_err(|()| errors::cannot_restart()) } fn hash_content(&self, url: String) -> BoxFuture { @@ -240,7 +239,7 @@ impl ParitySet for ParitySetClient where let hash = hash.into(); Ok(self.miner.remove_transaction(&hash) - .map(|t| Transaction::from_pending(t.pending().clone())) + .map(|t| Transaction::from_pending(t.pending().clone())) ) } }