diff --git a/Cargo.lock b/Cargo.lock index 17ee175d2..ff03d07f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -524,6 +524,7 @@ dependencies = [ "parity-updater 1.5.0", "rlp 0.1.0", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/js/src/api/rpc/parity/parity.js b/js/src/api/rpc/parity/parity.js index 2c1d04d93..36de46df0 100644 --- a/js/src/api/rpc/parity/parity.js +++ b/js/src/api/rpc/parity/parity.js @@ -315,4 +315,29 @@ export default class Parity { .execute('parity_unsignedTransactionsCount') .then(outNumber); } + + consensusCapability () { + return this._transport + .execute('parity_consensusCapability') + } + + versionInfo () { + return this._transport + .execute('parity_versionInfo') + } + + releasesInfo () { + return this._transport + .execute('parity_releasesInfo') + } + + upgradeReady () { + return this._transport + .execute('parity_upgradeReady') + } + + executeUpgrade () { + return this._transport + .execute('parity_executeUpgrade') + } } diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index b52e5affc..30a8c596c 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -242,7 +242,7 @@ pub fn setup_rpc(server: T, deps: Arc, apis: ApiSet server.add_delegate(ParityAccountsClient::new(&deps.secret_store, &deps.client).to_delegate()); }, Api::ParitySet => { - server.add_delegate(ParitySetClient::new(&deps.client, &deps.miner, &deps.net_service).to_delegate()) + server.add_delegate(ParitySetClient::new(&deps.client, &deps.miner, &deps.updater, &deps.net_service).to_delegate()) }, Api::Traces => { server.add_delegate(TracesClient::new(&deps.client, &deps.miner).to_delegate()) diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 81da64f4d..56230db16 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -34,6 +34,7 @@ serde_macros = { version = "0.8.0", optional = true } clippy = { version = "0.0.103", optional = true} ethcore-ipc = { path = "../ipc/rpc" } time = "0.1" +semver = "0.5" [build-dependencies] serde_codegen = { version = "0.8.0", optional = true } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 18a0a535d..22a2164ff 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -19,6 +19,7 @@ #![cfg_attr(feature="nightly", feature(custom_derive, custom_attribute, plugin))] #![cfg_attr(feature="nightly", plugin(serde_macros, clippy))] +extern crate semver; extern crate rustc_serialize; extern crate serde; extern crate serde_json; diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index db616da24..dd8c49832 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -38,7 +38,8 @@ use v1::types::{ Bytes, U256, H160, H256, H512, Peers, Transaction, RpcSettings, Histogram, TransactionStats, LocalTransactionStatus, - BlockNumber, ConsensusCapability + BlockNumber, ConsensusCapability, VersionInfo, + OperationsInfo }; use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings}; use v1::helpers::dispatch::DEFAULT_MAC; @@ -366,4 +367,16 @@ impl Parity for ParityClient where let updater = take_weak!(self.updater); Ok(updater.capability().into()) } + + fn version_info(&self) -> Result { + try!(self.active()); + let updater = take_weak!(self.updater); + Ok(updater.version_info().into()) + } + + fn releases_info(&self) -> Result, Error> { + try!(self.active()); + let updater = take_weak!(self.updater); + Ok(updater.info().map(Into::into)) + } } diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index b63adaa67..7aa598d6a 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -24,45 +24,51 @@ use ethcore::mode::Mode; use ethsync::ManageNetwork; use fetch::{Client as FetchClient, Fetch}; use util::{Mutex, sha3}; +use updater::{Service as UpdateService}; use jsonrpc_core::Error; use v1::helpers::auto_args::Ready; use v1::helpers::errors; use v1::traits::ParitySet; -use v1::types::{Bytes, H160, H256, U256}; +use v1::types::{Bytes, H160, H256, U256, ReleaseInfo}; /// Parity-specific rpc interface for operations altering the settings. -pub struct ParitySetClient where +pub struct ParitySetClient where C: MiningBlockChainClient, M: MinerService, + U: UpdateService, F: Fetch, { client: Weak, miner: Weak, + updater: Weak, net: Weak, fetch: Mutex, } -impl ParitySetClient where +impl ParitySetClient where C: MiningBlockChainClient, - M: MinerService + M: MinerService, + U: UpdateService, { /// Creates new `ParitySetClient` with default `FetchClient`. - pub fn new(client: &Arc, miner: &Arc, net: &Arc) -> Self { - Self::with_fetch(client, miner, net) + pub fn new(client: &Arc, miner: &Arc, updater: &Arc, net: &Arc) -> Self { + Self::with_fetch(client, miner, updater, net) } } -impl ParitySetClient where +impl ParitySetClient where C: MiningBlockChainClient, M: MinerService, + U: UpdateService, F: Fetch, { /// Creates new `ParitySetClient` with default `FetchClient`. - pub fn with_fetch(client: &Arc, miner: &Arc, net: &Arc) -> Self { + pub fn with_fetch(client: &Arc, miner: &Arc, updater: &Arc, net: &Arc) -> Self { ParitySetClient { client: Arc::downgrade(client), miner: Arc::downgrade(miner), + updater: Arc::downgrade(updater), net: Arc::downgrade(net), fetch: Mutex::new(F::default()), } @@ -75,9 +81,10 @@ impl ParitySetClient where } } -impl ParitySet for ParitySetClient where +impl ParitySet for ParitySetClient where C: MiningBlockChainClient + 'static, M: MinerService + 'static, + U: UpdateService + 'static, F: Fetch + 'static, { @@ -230,4 +237,16 @@ impl ParitySet for ParitySetClient where } } } + + fn upgrade_ready(&self) -> Result, Error> { + try!(self.active()); + let updater = take_weak!(self.updater); + Ok(updater.upgrade_ready().map(Into::into)) + } + + fn execute_upgrade(&self) -> Result { + try!(self.active()); + let updater = take_weak!(self.updater); + Ok(updater.execute_upgrade()) + } } diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 32d2a041c..f2efac0ec 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -23,7 +23,8 @@ use v1::types::{ H160, H256, H512, U256, Bytes, Peers, Transaction, RpcSettings, Histogram, TransactionStats, LocalTransactionStatus, - BlockNumber, ConsensusCapability + BlockNumber, ConsensusCapability, VersionInfo, + OperationsInfo }; build_rpc_trait! { @@ -159,5 +160,13 @@ build_rpc_trait! { /// Returns information on current consensus capability. #[rpc(name = "parity_consensusCapability")] fn consensus_capability(&self) -> Result; + + /// Get our version information in a nice object. + #[rpc(name = "parity_versionInfo")] + fn version_info(&self) -> Result; + + /// Get information concerning the latest releases if available. + #[rpc(name = "parity_releasesInfo")] + fn releases_info(&self) -> Result, Error>; } } diff --git a/rpc/src/v1/traits/parity_set.rs b/rpc/src/v1/traits/parity_set.rs index 486f7fb42..2f997bb1e 100644 --- a/rpc/src/v1/traits/parity_set.rs +++ b/rpc/src/v1/traits/parity_set.rs @@ -19,7 +19,7 @@ use jsonrpc_core::Error; use v1::helpers::auto_args::{Wrap, WrapAsync, Ready}; -use v1::types::{Bytes, H160, H256, U256}; +use v1::types::{Bytes, H160, H256, U256, ReleaseInfo}; build_rpc_trait! { /// Parity-specific rpc interface for operations altering the settings. @@ -91,5 +91,13 @@ build_rpc_trait! { /// Hash a file content under given URL. #[rpc(async, name = "parity_hashContent")] fn hash_content(&self, Ready, String); + + /// Is there a release ready for install? + #[rpc(name = "parity_upgradeReady")] + fn upgrade_ready(&self) -> Result, Error>; + + /// Execute a release which is ready according to upgrade_ready(). + #[rpc(name = "parity_executeUpgrade")] + fn execute_upgrade(&self) -> Result; } } diff --git a/rpc/src/v1/types/consensus_status.rs b/rpc/src/v1/types/consensus_status.rs index f919fcd58..c9820b138 100644 --- a/rpc/src/v1/types/consensus_status.rs +++ b/rpc/src/v1/types/consensus_status.rs @@ -14,10 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use updater::CapState; +use semver; +use v1::types::{H160, H256}; +use updater::{self, CapState}; /// Capability info -#[derive(Debug, Serialize, PartialEq)] +#[derive(Debug, PartialEq, Serialize)] pub enum ConsensusCapability { /// Unknown. #[serde(rename="unknown")] @@ -44,3 +46,116 @@ impl Into for CapState { } } +/// A release's track. +#[derive(Debug, PartialEq, Serialize)] +pub enum ReleaseTrack { + /// Stable track. + Stable, + /// Beta track. + Beta, + /// Nightly track. + Nightly, + /// No known track. + Unknown, +} + +impl Into for updater::ReleaseTrack { + fn into(self) -> ReleaseTrack { + match self { + updater::ReleaseTrack::Stable => ReleaseTrack::Stable, + updater::ReleaseTrack::Beta => ReleaseTrack::Beta, + updater::ReleaseTrack::Nightly => ReleaseTrack::Nightly, + updater::ReleaseTrack::Unknown => ReleaseTrack::Unknown, + } + } +} + +/// Semantic version. +#[derive(Debug, PartialEq, Serialize)] +pub struct Version { + /// Major part. + major: u64, + /// Minor part. + minor: u64, + /// Patch part. + patch: u64, +} + +impl Into for semver::Version { + fn into(self) -> Version { + Version { + major: self.major, + minor: self.minor, + patch: self.patch, + } + } +} + +/// Version information of a particular release. +#[derive(Debug, PartialEq, Serialize)] +pub struct VersionInfo { + /// The track on which it was released. + pub track: ReleaseTrack, + /// The version. + pub version: Version, + /// The (SHA1?) 160-bit hash of this build's code base. + pub hash: H160, +} + +impl Into for updater::VersionInfo { + fn into(self) -> VersionInfo { + VersionInfo { + track: self.track.into(), + version: self.version.into(), + hash: self.hash.into(), + } + } +} + +/// Information regarding a particular release of Parity +#[derive(Debug, PartialEq, Serialize)] +pub struct ReleaseInfo { + /// Information on the version. + pub version: VersionInfo, + /// Does this release contain critical security updates? + pub is_critical: bool, + /// The latest fork that this release can handle. + pub fork: u64, + /// Our platform's binary, if known. + pub binary: Option, +} + +impl Into for updater::ReleaseInfo { + fn into(self) -> ReleaseInfo { + ReleaseInfo { + version: self.version.into(), + is_critical: self.is_critical, + fork: self.fork, + binary: self.binary.map(Into::into), + } + } +} + +/// Information on our operations environment. +#[derive(Debug, PartialEq, Serialize)] +pub struct OperationsInfo { + /// Our blockchain's latest fork. + pub fork: u64, + /// Last fork our client supports, if known. + pub this_fork: Option, + /// Information on our track's latest release. + pub track: ReleaseInfo, + /// Information on our minor version's latest release. + pub minor: Option, +} + +impl Into for updater::OperationsInfo { + fn into(self) -> OperationsInfo { + OperationsInfo { + fork: self.fork, + this_fork: self.this_fork, + track: self.track.into(), + minor: self.minor.map(Into::into), + } + } +} diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index a7acfe5c6..b5d467886 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -56,4 +56,4 @@ pub use self::trace_filter::TraceFilter; pub use self::uint::{U128, U256}; pub use self::work::Work; pub use self::histogram::Histogram; -pub use self::consensus_status::ConsensusCapability; \ No newline at end of file +pub use self::consensus_status::*; \ No newline at end of file diff --git a/updater/src/updater.rs b/updater/src/updater.rs index 3b793623e..f10e15c28 100644 --- a/updater/src/updater.rs +++ b/updater/src/updater.rs @@ -137,8 +137,13 @@ impl Updater { fn collect_latest(&self) -> Result { if let Some(ref operations) = *self.operations.lock() { + let hh: H256 = self.this.hash.into(); + info!("Looking up this_fork for our release: {}/{:?}", CLIENT_ID, hh); let this_fork = operations.release(CLIENT_ID, &self.this.hash.into()).ok() - .and_then(|(fork, track, _, _)| if track > 0 {Some(fork as u64)} else {None}); + .and_then(|(fork, track, _, _)| { + info!("Operations returned fork={}, track={}", fork as u64, track); + if track > 0 {Some(fork as u64)} else {None} + }); if self.this.track == ReleaseTrack::Unknown { return Err(format!("Current executable ({}) is unreleased.", H160::from(self.this.hash))); @@ -207,7 +212,7 @@ impl Updater { } fn poll(&self) { - info!(target: "updater", "Current release is {}", self.this); + info!(target: "updater", "Current release is {} ({:?})", self.this, self.this.hash); if self.operations.lock().is_none() { if let Some(ops_addr) = self.client.upgrade().and_then(|c| c.registry_address("operations".into())) {