Expose health status over RPC (#6274)

* Node-health to a separate crate.

* Initialize node_health outside of dapps.

* Expose health over RPC.

* Bring back 412 and fix JS.

* Add health to workspace and tests.

* Fix compilation without default features.

* Fix borked merge.

* Revert to generics to avoid virtual calls.

* Fix node-health tests.

* Add missing trailing comma.
This commit is contained in:
Tomasz Drwięga 2017-08-28 14:11:55 +02:00 committed by Gav Wood
parent 622632616c
commit 3226e1ca33
31 changed files with 513 additions and 300 deletions

20
Cargo.lock generated
View File

@ -1613,6 +1613,21 @@ dependencies = [
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "node-health"
version = "0.1.0"
dependencies = [
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"ntp 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-reactor 0.1.0",
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "nodrop" name = "nodrop"
version = "0.1.9" version = "0.1.9"
@ -1821,6 +1836,7 @@ dependencies = [
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"node-health 0.1.0",
"num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"panic_hook 0.1.0", "panic_hook 0.1.0",
@ -1862,7 +1878,6 @@ dependencies = [
"ethcore-util 1.8.0", "ethcore-util 1.8.0",
"fetch 0.1.0", "fetch 0.1.0",
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
@ -1870,7 +1885,7 @@ dependencies = [
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ntp 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "node-health 0.1.0",
"parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-hash-fetch 1.8.0", "parity-hash-fetch 1.8.0",
"parity-reactor 0.1.0", "parity-reactor 0.1.0",
@ -1985,6 +2000,7 @@ dependencies = [
"jsonrpc-ws-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-ws-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
"log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"multihash 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "multihash 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"node-health 0.1.0",
"order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-reactor 0.1.0", "parity-reactor 0.1.0",
"parity-updater 1.8.0", "parity-updater 1.8.0",

View File

@ -43,6 +43,7 @@ ethcore-logger = { path = "logger" }
ethcore-stratum = { path = "stratum" } ethcore-stratum = { path = "stratum" }
ethcore-network = { path = "util/network" } ethcore-network = { path = "util/network" }
ethkey = { path = "ethkey" } ethkey = { path = "ethkey" }
node-health = { path = "dapps/node-health" }
rlp = { path = "util/rlp" } rlp = { path = "util/rlp" }
rpc-cli = { path = "rpc_cli" } rpc-cli = { path = "rpc_cli" }
parity-hash-fetch = { path = "hash-fetch" } parity-hash-fetch = { path = "hash-fetch" }
@ -110,4 +111,4 @@ lto = false
panic = "abort" panic = "abort"
[workspace] [workspace]
members = ["ethstore/cli", "ethkey/cli", "evmbin", "whisper", "chainspec"] members = ["ethstore/cli", "ethkey/cli", "evmbin", "whisper", "chainspec", "dapps/node-health"]

View File

@ -9,15 +9,12 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
base32 = "0.3" base32 = "0.3"
env_logger = "0.4"
futures = "0.1" futures = "0.1"
futures-cpupool = "0.1"
linked-hash-map = "0.3" linked-hash-map = "0.3"
log = "0.3" log = "0.3"
parity-dapps-glue = "1.7" parity-dapps-glue = "1.7"
mime = "0.2" mime = "0.2"
mime_guess = "1.6.1" mime_guess = "1.6.1"
ntp = "0.2.0"
rand = "0.3" rand = "0.3"
rustc-hex = "1.0" rustc-hex = "1.0"
serde = "1.0" serde = "1.0"
@ -32,15 +29,19 @@ itertools = "0.5"
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" } jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
ethcore-devtools = { path = "../devtools" }
ethcore-util = { path = "../util" } ethcore-util = { path = "../util" }
fetch = { path = "../util/fetch" } fetch = { path = "../util/fetch" }
node-health = { path = "./node-health" }
parity-hash-fetch = { path = "../hash-fetch" } parity-hash-fetch = { path = "../hash-fetch" }
parity-reactor = { path = "../util/reactor" } parity-reactor = { path = "../util/reactor" }
parity-ui = { path = "./ui" } parity-ui = { path = "./ui" }
clippy = { version = "0.0.103", optional = true} clippy = { version = "0.0.103", optional = true}
[dev-dependencies]
env_logger = "0.4"
ethcore-devtools = { path = "../devtools" }
[features] [features]
dev = ["clippy", "ethcore-util/dev"] dev = ["clippy", "ethcore-util/dev"]

View File

@ -0,0 +1,18 @@
[package]
name = "node-health"
description = "Node's health status"
version = "0.1.0"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
futures = "0.1"
futures-cpupool = "0.1"
log = "0.3"
ntp = "0.2.0"
parking_lot = "0.4"
serde = "1.0"
serde_derive = "1.0"
time = "0.1.35"
parity-reactor = { path = "../../util/reactor" }

View File

@ -0,0 +1,122 @@
// Copyright 2015-2017 Parity Technologies (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/>.
//! Reporting node's health.
use std::sync::Arc;
use std::time;
use futures::{Future, BoxFuture};
use futures::sync::oneshot;
use types::{HealthInfo, HealthStatus, Health};
use time::{TimeChecker, MAX_DRIFT};
use parity_reactor::Remote;
use parking_lot::Mutex;
use {SyncStatus};
const TIMEOUT_SECS: u64 = 5;
const PROOF: &str = "Only one closure is invoked.";
/// A struct enabling you to query for node's health.
#[derive(Debug, Clone)]
pub struct NodeHealth {
sync_status: Arc<SyncStatus>,
time: TimeChecker,
remote: Remote,
}
impl NodeHealth {
/// Creates new `NodeHealth`.
pub fn new(sync_status: Arc<SyncStatus>, time: TimeChecker, remote: Remote) -> Self {
NodeHealth { sync_status, time, remote, }
}
/// Query latest health report.
pub fn health(&self) -> BoxFuture<Health, ()> {
trace!(target: "dapps", "Checking node health.");
// Check timediff
let sync_status = self.sync_status.clone();
let time = self.time.time_drift();
let (tx, rx) = oneshot::channel();
let tx = Arc::new(Mutex::new(Some(tx)));
let tx2 = tx.clone();
self.remote.spawn_with_timeout(
move || time.then(move |result| {
let _ = tx.lock().take().expect(PROOF).send(Ok(result));
Ok(())
}),
time::Duration::from_secs(TIMEOUT_SECS),
move || {
let _ = tx2.lock().take().expect(PROOF).send(Err(()));
},
);
rx.map_err(|err| {
warn!(target: "dapps", "Health request cancelled: {:?}", err);
}).and_then(move |time| {
// Check peers
let peers = {
let (connected, max) = sync_status.peers();
let (status, message) = match connected {
0 => {
(HealthStatus::Bad, "You are not connected to any peers. There is most likely some network issue. Fix connectivity.".into())
},
1 => (HealthStatus::NeedsAttention, "You are connected to only one peer. Your node might not be reliable. Check your network connection.".into()),
_ => (HealthStatus::Ok, "".into()),
};
HealthInfo { status, message, details: (connected, max) }
};
// Check sync
let sync = {
let is_syncing = sync_status.is_major_importing();
let (status, message) = if is_syncing {
(HealthStatus::NeedsAttention, "Your node is still syncing, the values you see might be outdated. Wait until it's fully synced.".into())
} else {
(HealthStatus::Ok, "".into())
};
HealthInfo { status, message, details: is_syncing }
};
// Check time
let time = {
let (status, message, details) = match time {
Ok(Ok(diff)) if diff < MAX_DRIFT && diff > -MAX_DRIFT => {
(HealthStatus::Ok, "".into(), diff)
},
Ok(Ok(diff)) => {
(HealthStatus::Bad, format!(
"Your clock is not in sync. Detected difference is too big for the protocol to work: {}ms. Synchronize your clock.",
diff,
), diff)
},
Ok(Err(err)) => {
(HealthStatus::NeedsAttention, format!(
"Unable to reach time API: {}. Make sure that your clock is synchronized.",
err,
), 0)
},
Err(_) => {
(HealthStatus::NeedsAttention, "Time API request timed out. Make sure that the clock is synchronized.".into(), 0)
},
};
HealthInfo { status, message, details, }
};
Ok(Health { peers, sync, time})
}).boxed()
}
}

View File

@ -0,0 +1,49 @@
// Copyright 2015-2017 Parity Technologies (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/>.
//! Node Health status reporting.
#![warn(missing_docs)]
extern crate futures;
extern crate futures_cpupool;
extern crate ntp;
extern crate time as time_crate;
extern crate parity_reactor;
extern crate parking_lot;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
mod health;
mod time;
mod types;
pub use futures_cpupool::CpuPool;
pub use health::NodeHealth;
pub use types::{Health, HealthInfo, HealthStatus};
pub use time::{TimeChecker, Error};
/// Indicates sync status
pub trait SyncStatus: ::std::fmt::Debug + Send + Sync {
/// Returns true if there is a major sync happening.
fn is_major_importing(&self) -> bool;
/// Returns number of connected and ideal peers.
fn peers(&self) -> (usize, usize);
}

View File

@ -41,8 +41,8 @@ use futures::{self, Future, BoxFuture};
use futures::future::{self, IntoFuture}; use futures::future::{self, IntoFuture};
use futures_cpupool::{CpuPool, CpuFuture}; use futures_cpupool::{CpuPool, CpuFuture};
use ntp; use ntp;
use time::{Duration, Timespec}; use parking_lot::RwLock;
use util::RwLock; use time_crate::{Duration, Timespec};
/// Time checker error. /// Time checker error.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -164,7 +164,7 @@ impl Ntp for SimpleNtp {
match ntp::request(&server.address) { match ntp::request(&server.address) {
Ok(packet) => { Ok(packet) => {
let dest_time = ::time::now_utc().to_timespec(); let dest_time = ::time_crate::now_utc().to_timespec();
let orig_time = Timespec::from(packet.orig_time); let orig_time = Timespec::from(packet.orig_time);
let recv_time = Timespec::from(packet.recv_time); let recv_time = Timespec::from(packet.recv_time);
let transmit_time = Timespec::from(packet.transmit_time); let transmit_time = Timespec::from(packet.transmit_time);
@ -293,7 +293,7 @@ mod tests {
use time::Duration; use time::Duration;
use futures::{future, Future}; use futures::{future, Future};
use super::{Ntp, TimeChecker, Error}; use super::{Ntp, TimeChecker, Error};
use util::RwLock; use parking_lot::RwLock;
#[derive(Clone)] #[derive(Clone)]
struct FakeNtp(RefCell<Vec<Duration>>, Cell<u64>); struct FakeNtp(RefCell<Vec<Duration>>, Cell<u64>);

View File

@ -0,0 +1,57 @@
// Copyright 2015-2017 Parity Technologies (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/>.
//! Base health types.
/// Health API endpoint status.
#[derive(Debug, PartialEq, Serialize)]
pub enum HealthStatus {
/// Everything's OK.
#[serde(rename = "ok")]
Ok,
/// Node health need attention
/// (the issue is not critical, but may need investigation)
#[serde(rename = "needsAttention")]
NeedsAttention,
/// There is something bad detected with the node.
#[serde(rename = "bad")]
Bad,
}
/// Represents a single check in node health.
/// Cointains the status of that check and apropriate message and details.
#[derive(Debug, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct HealthInfo<T> {
/// Check status.
pub status: HealthStatus,
/// Human-readable message.
pub message: String,
/// Technical details of the check.
pub details: T,
}
/// Node Health status.
#[derive(Debug, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Health {
/// Status of peers.
pub peers: HealthInfo<(usize, usize)>,
/// Sync status.
pub sync: HealthInfo<bool>,
/// Time diff info.
pub time: HealthInfo<i64>,
}

View File

@ -21,32 +21,28 @@ use hyper::method::Method;
use hyper::status::StatusCode; use hyper::status::StatusCode;
use api::{response, types}; use api::{response, types};
use api::time::{TimeChecker, MAX_DRIFT};
use apps::fetcher::Fetcher; use apps::fetcher::Fetcher;
use handlers::{self, extract_url}; use handlers::{self, extract_url};
use endpoint::{Endpoint, Handler, EndpointPath}; use endpoint::{Endpoint, Handler, EndpointPath};
use node_health::{NodeHealth, HealthStatus, Health};
use parity_reactor::Remote; use parity_reactor::Remote;
use {SyncStatus};
#[derive(Clone)] #[derive(Clone)]
pub struct RestApi { pub struct RestApi {
fetcher: Arc<Fetcher>, fetcher: Arc<Fetcher>,
sync_status: Arc<SyncStatus>, health: NodeHealth,
time: TimeChecker,
remote: Remote, remote: Remote,
} }
impl RestApi { impl RestApi {
pub fn new( pub fn new(
fetcher: Arc<Fetcher>, fetcher: Arc<Fetcher>,
sync_status: Arc<SyncStatus>, health: NodeHealth,
time: TimeChecker,
remote: Remote, remote: Remote,
) -> Box<Endpoint> { ) -> Box<Endpoint> {
Box::new(RestApi { Box::new(RestApi {
fetcher, fetcher,
sync_status, health,
time,
remote, remote,
}) })
} }
@ -90,68 +86,23 @@ impl RestApiRouter {
} }
fn health(&self, control: Control) -> Box<Handler> { fn health(&self, control: Control) -> Box<Handler> {
use self::types::{HealthInfo, HealthStatus, Health}; let map = move |health: Result<Result<Health, ()>, ()>| {
let status = match health {
trace!(target: "dapps", "Checking node health."); Ok(Ok(ref health)) => {
// Check timediff if [&health.peers.status, &health.sync.status].iter().any(|x| *x != &HealthStatus::Ok) {
let sync_status = self.api.sync_status.clone(); StatusCode::PreconditionFailed // HTTP 412
let map = move |time| {
// Check peers
let peers = {
let (connected, max) = sync_status.peers();
let (status, message) = match connected {
0 => {
(HealthStatus::Bad, "You are not connected to any peers. There is most likely some network issue. Fix connectivity.".into())
},
1 => (HealthStatus::NeedsAttention, "You are connected to only one peer. Your node might not be reliable. Check your network connection.".into()),
_ => (HealthStatus::Ok, "".into()),
};
HealthInfo { status, message, details: (connected, max) }
};
// Check sync
let sync = {
let is_syncing = sync_status.is_major_importing();
let (status, message) = if is_syncing {
(HealthStatus::NeedsAttention, "Your node is still syncing, the values you see might be outdated. Wait until it's fully synced.".into())
} else { } else {
(HealthStatus::Ok, "".into()) StatusCode::Ok // HTTP 200
}; }
HealthInfo { status, message, details: is_syncing } },
_ => StatusCode::ServiceUnavailable, // HTTP 503
}; };
// Check time response::as_json(status, &health)
let time = {
let (status, message, details) = match time {
Ok(Ok(diff)) if diff < MAX_DRIFT && diff > -MAX_DRIFT => {
(HealthStatus::Ok, "".into(), diff)
},
Ok(Ok(diff)) => {
(HealthStatus::Bad, format!(
"Your clock is not in sync. Detected difference is too big for the protocol to work: {}ms. Synchronize your clock.",
diff,
), diff)
},
Ok(Err(err)) => {
(HealthStatus::NeedsAttention, format!(
"Unable to reach time API: {}. Make sure that your clock is synchronized.",
err,
), 0)
},
Err(_) => {
(HealthStatus::NeedsAttention, "Time API request timed out. Make sure that the clock is synchronized.".into(), 0)
},
}; };
let health = self.api.health.health();
HealthInfo { status, message, details, }
};
response::as_json(StatusCode::Ok, &Health { peers, sync, time })
};
let time = self.api.time.time_drift();
let remote = self.api.remote.clone(); let remote = self.api.remote.clone();
Box::new(handlers::AsyncHandler::new(time, map, remote, control)) Box::new(handlers::AsyncHandler::new(health, map, remote, control))
} }
} }

View File

@ -18,8 +18,6 @@
mod api; mod api;
mod response; mod response;
mod time;
mod types; mod types;
pub use self::api::RestApi; pub use self::api::RestApi;
pub use self::time::TimeChecker;

View File

@ -25,43 +25,3 @@ pub struct ApiError {
/// More technical error details. /// More technical error details.
pub detail: String, pub detail: String,
} }
/// Health API endpoint status.
#[derive(Debug, PartialEq, Serialize)]
pub enum HealthStatus {
/// Everything's OK.
#[serde(rename = "ok")]
Ok,
/// Node health need attention
/// (the issue is not critical, but may need investigation)
#[serde(rename = "needsAttention")]
NeedsAttention,
/// There is something bad detected with the node.
#[serde(rename = "bad")]
Bad
}
/// Represents a single check in node health.
/// Cointains the status of that check and apropriate message and details.
#[derive(Debug, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct HealthInfo<T> {
/// Check status.
pub status: HealthStatus,
/// Human-readable message.
pub message: String,
/// Technical details of the check.
pub details: T,
}
/// Node Health status.
#[derive(Debug, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Health {
/// Status of peers.
pub peers: HealthInfo<(usize, usize)>,
/// Sync status.
pub sync: HealthInfo<bool>,
/// Time diff info.
pub time: HealthInfo<i64>,
}

View File

@ -281,6 +281,7 @@ mod tests {
} }
} }
#[derive(Debug)]
struct FakeSync(bool); struct FakeSync(bool);
impl SyncStatus for FakeSync { impl SyncStatus for FakeSync {
fn is_major_importing(&self) -> bool { self.0 } fn is_major_importing(&self) -> bool { self.0 }

View File

@ -21,11 +21,9 @@
extern crate base32; extern crate base32;
extern crate futures; extern crate futures;
extern crate futures_cpupool;
extern crate itertools; extern crate itertools;
extern crate linked_hash_map; extern crate linked_hash_map;
extern crate mime_guess; extern crate mime_guess;
extern crate ntp;
extern crate rand; extern crate rand;
extern crate rustc_hex; extern crate rustc_hex;
extern crate serde; extern crate serde;
@ -40,6 +38,7 @@ extern crate jsonrpc_http_server;
extern crate ethcore_util as util; extern crate ethcore_util as util;
extern crate fetch; extern crate fetch;
extern crate node_health;
extern crate parity_dapps_glue as parity_dapps; extern crate parity_dapps_glue as parity_dapps;
extern crate parity_hash_fetch as hash_fetch; extern crate parity_hash_fetch as hash_fetch;
extern crate parity_reactor; extern crate parity_reactor;
@ -57,7 +56,6 @@ extern crate ethcore_devtools as devtools;
#[cfg(test)] #[cfg(test)]
extern crate env_logger; extern crate env_logger;
mod endpoint; mod endpoint;
mod apps; mod apps;
mod page; mod page;
@ -79,19 +77,12 @@ use util::RwLock;
use jsonrpc_http_server::{self as http, hyper, Origin}; use jsonrpc_http_server::{self as http, hyper, Origin};
use fetch::Fetch; use fetch::Fetch;
use futures_cpupool::CpuPool; use node_health::NodeHealth;
use parity_reactor::Remote; use parity_reactor::Remote;
pub use hash_fetch::urlhint::ContractClient; pub use hash_fetch::urlhint::ContractClient;
pub use node_health::SyncStatus;
/// Indicates sync status
pub trait SyncStatus: Send + Sync {
/// Returns true if there is a major sync happening.
fn is_major_importing(&self) -> bool;
/// Returns number of connected and ideal peers.
fn peers(&self) -> (usize, usize);
}
/// Validates Web Proxy tokens /// Validates Web Proxy tokens
pub trait WebProxyTokens: Send + Sync { pub trait WebProxyTokens: Send + Sync {
@ -156,8 +147,7 @@ impl Middleware {
/// Creates new middleware for UI server. /// Creates new middleware for UI server.
pub fn ui<F: Fetch>( pub fn ui<F: Fetch>(
ntp_servers: &[String], health: NodeHealth,
pool: CpuPool,
remote: Remote, remote: Remote,
dapps_domain: &str, dapps_domain: &str,
registrar: Arc<ContractClient>, registrar: Arc<ContractClient>,
@ -172,11 +162,9 @@ impl Middleware {
).embeddable_on(None).allow_dapps(false)); ).embeddable_on(None).allow_dapps(false));
let special = { let special = {
let mut special = special_endpoints( let mut special = special_endpoints(
ntp_servers, health,
pool,
content_fetcher.clone(), content_fetcher.clone(),
remote.clone(), remote.clone(),
sync_status.clone(),
); );
special.insert(router::SpecialEndpoint::Home, Some(apps::ui())); special.insert(router::SpecialEndpoint::Home, Some(apps::ui()));
special special
@ -197,8 +185,7 @@ impl Middleware {
/// Creates new Dapps server middleware. /// Creates new Dapps server middleware.
pub fn dapps<F: Fetch>( pub fn dapps<F: Fetch>(
ntp_servers: &[String], health: NodeHealth,
pool: CpuPool,
remote: Remote, remote: Remote,
ui_address: Option<(String, u16)>, ui_address: Option<(String, u16)>,
extra_embed_on: Vec<(String, u16)>, extra_embed_on: Vec<(String, u16)>,
@ -236,11 +223,9 @@ impl Middleware {
let special = { let special = {
let mut special = special_endpoints( let mut special = special_endpoints(
ntp_servers, health,
pool,
content_fetcher.clone(), content_fetcher.clone(),
remote.clone(), remote.clone(),
sync_status,
); );
special.insert( special.insert(
router::SpecialEndpoint::Home, router::SpecialEndpoint::Home,
@ -270,20 +255,17 @@ impl http::RequestMiddleware for Middleware {
} }
} }
fn special_endpoints<T: AsRef<str>>( fn special_endpoints(
ntp_servers: &[T], health: NodeHealth,
pool: CpuPool,
content_fetcher: Arc<apps::fetcher::Fetcher>, content_fetcher: Arc<apps::fetcher::Fetcher>,
remote: Remote, remote: Remote,
sync_status: Arc<SyncStatus>,
) -> HashMap<router::SpecialEndpoint, Option<Box<endpoint::Endpoint>>> { ) -> HashMap<router::SpecialEndpoint, Option<Box<endpoint::Endpoint>>> {
let mut special = HashMap::new(); let mut special = HashMap::new();
special.insert(router::SpecialEndpoint::Rpc, None); special.insert(router::SpecialEndpoint::Rpc, None);
special.insert(router::SpecialEndpoint::Utils, Some(apps::utils())); special.insert(router::SpecialEndpoint::Utils, Some(apps::utils()));
special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new( special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new(
content_fetcher, content_fetcher,
sync_status, health,
api::TimeChecker::new(ntp_servers, pool),
remote, remote,
))); )));
special special

View File

@ -26,7 +26,7 @@ use jsonrpc_http_server::{self as http, Host, DomainsValidation};
use devtools::http_client; use devtools::http_client;
use hash_fetch::urlhint::ContractClient; use hash_fetch::urlhint::ContractClient;
use fetch::{Fetch, Client as FetchClient}; use fetch::{Fetch, Client as FetchClient};
use futures_cpupool::CpuPool; use node_health::{NodeHealth, TimeChecker, CpuPool};
use parity_reactor::Remote; use parity_reactor::Remote;
use {Middleware, SyncStatus, WebProxyTokens}; use {Middleware, SyncStatus, WebProxyTokens};
@ -39,6 +39,7 @@ use self::fetch::FakeFetch;
const SIGNER_PORT: u16 = 18180; const SIGNER_PORT: u16 = 18180;
#[derive(Debug)]
struct FakeSync(bool); struct FakeSync(bool);
impl SyncStatus for FakeSync { impl SyncStatus for FakeSync {
fn is_major_importing(&self) -> bool { self.0 } fn is_major_importing(&self) -> bool { self.0 }
@ -254,9 +255,13 @@ impl Server {
remote: Remote, remote: Remote,
fetch: F, fetch: F,
) -> Result<Server, http::Error> { ) -> Result<Server, http::Error> {
let health = NodeHealth::new(
sync_status.clone(),
TimeChecker::new::<String>(&[], CpuPool::new(1)),
remote.clone(),
);
let middleware = Middleware::dapps( let middleware = Middleware::dapps(
&["0.pool.ntp.org:123".into(), "1.pool.ntp.org:123".into()], health,
CpuPool::new(4),
remote, remote,
signer_address, signer_address,
vec![], vec![],

View File

@ -385,6 +385,11 @@ export default class Parity {
.then(outNumber); .then(outNumber);
} }
nodeHealth () {
return this._transport
.execute('parity_nodeHealth');
}
nodeName () { nodeName () {
return this._transport return this._transport
.execute('parity_nodeName'); .execute('parity_nodeName');

View File

@ -200,7 +200,7 @@ export default class Status {
const statusPromises = [ const statusPromises = [
this._api.eth.syncing(), this._api.eth.syncing(),
this._api.parity.netPeers(), this._api.parity.netPeers(),
this._fetchHealth() this._api.parity.nodeHealth()
]; ];
return Promise return Promise
@ -247,13 +247,6 @@ export default class Status {
}; };
} }
_fetchHealth = () => {
// Support Parity-Extension.
const uiUrl = this._api.transport.uiUrlWithProtocol || '';
return fetch(`${uiUrl}/api/health`).then(res => res.json());
}
/** /**
* The data fetched here should not change * The data fetched here should not change
* unless Parity is restarted. They are thus * unless Parity is restarted. They are thus

View File

@ -346,6 +346,7 @@ impl Configuration {
daemon: daemon, daemon: daemon,
logger_config: logger_config.clone(), logger_config: logger_config.clone(),
miner_options: self.miner_options(self.args.flag_reseal_min_period)?, miner_options: self.miner_options(self.args.flag_reseal_min_period)?,
ntp_servers: self.ntp_servers(),
ws_conf: ws_conf, ws_conf: ws_conf,
http_conf: http_conf, http_conf: http_conf,
ipc_conf: ipc_conf, ipc_conf: ipc_conf,
@ -563,7 +564,6 @@ impl Configuration {
fn ui_config(&self) -> UiConfiguration { fn ui_config(&self) -> UiConfiguration {
UiConfiguration { UiConfiguration {
enabled: self.ui_enabled(), enabled: self.ui_enabled(),
ntp_servers: self.ntp_servers(),
interface: self.ui_interface(), interface: self.ui_interface(),
port: self.ui_port(), port: self.ui_port(),
hosts: self.ui_hosts(), hosts: self.ui_hosts(),
@ -576,7 +576,6 @@ impl Configuration {
DappsConfiguration { DappsConfiguration {
enabled: self.dapps_enabled(), enabled: self.dapps_enabled(),
ntp_servers: self.ntp_servers(),
dapps_path: PathBuf::from(self.directories().dapps), dapps_path: PathBuf::from(self.directories().dapps),
extra_dapps: if self.args.cmd_dapp { extra_dapps: if self.args.cmd_dapp {
self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect() self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect()
@ -1318,12 +1317,6 @@ mod tests {
support_token_api: true support_token_api: true
}, UiConfiguration { }, UiConfiguration {
enabled: true, enabled: true,
ntp_servers: vec![
"0.parity.pool.ntp.org:123".into(),
"1.parity.pool.ntp.org:123".into(),
"2.parity.pool.ntp.org:123".into(),
"3.parity.pool.ntp.org:123".into(),
],
interface: "127.0.0.1".into(), interface: "127.0.0.1".into(),
port: 8180, port: 8180,
hosts: Some(vec![]), hosts: Some(vec![]),
@ -1348,6 +1341,12 @@ mod tests {
daemon: None, daemon: None,
logger_config: Default::default(), logger_config: Default::default(),
miner_options: Default::default(), miner_options: Default::default(),
ntp_servers: vec![
"0.parity.pool.ntp.org:123".into(),
"1.parity.pool.ntp.org:123".into(),
"2.parity.pool.ntp.org:123".into(),
"3.parity.pool.ntp.org:123".into(),
],
ws_conf: Default::default(), ws_conf: Default::default(),
http_conf: Default::default(), http_conf: Default::default(),
ipc_conf: Default::default(), ipc_conf: Default::default(),
@ -1567,16 +1566,9 @@ mod tests {
let conf3 = parse(&["parity", "--ui-path", "signer", "--ui-interface", "test"]); let conf3 = parse(&["parity", "--ui-path", "signer", "--ui-interface", "test"]);
// then // then
let ntp_servers = vec![
"0.parity.pool.ntp.org:123".into(),
"1.parity.pool.ntp.org:123".into(),
"2.parity.pool.ntp.org:123".into(),
"3.parity.pool.ntp.org:123".into(),
];
assert_eq!(conf0.directories().signer, "signer".to_owned()); assert_eq!(conf0.directories().signer, "signer".to_owned());
assert_eq!(conf0.ui_config(), UiConfiguration { assert_eq!(conf0.ui_config(), UiConfiguration {
enabled: true, enabled: true,
ntp_servers: ntp_servers.clone(),
interface: "127.0.0.1".into(), interface: "127.0.0.1".into(),
port: 8180, port: 8180,
hosts: Some(vec![]), hosts: Some(vec![]),
@ -1585,7 +1577,6 @@ mod tests {
assert_eq!(conf1.directories().signer, "signer".to_owned()); assert_eq!(conf1.directories().signer, "signer".to_owned());
assert_eq!(conf1.ui_config(), UiConfiguration { assert_eq!(conf1.ui_config(), UiConfiguration {
enabled: true, enabled: true,
ntp_servers: ntp_servers.clone(),
interface: "127.0.0.1".into(), interface: "127.0.0.1".into(),
port: 8180, port: 8180,
hosts: Some(vec![]), hosts: Some(vec![]),
@ -1595,7 +1586,6 @@ mod tests {
assert_eq!(conf2.directories().signer, "signer".to_owned()); assert_eq!(conf2.directories().signer, "signer".to_owned());
assert_eq!(conf2.ui_config(), UiConfiguration { assert_eq!(conf2.ui_config(), UiConfiguration {
enabled: true, enabled: true,
ntp_servers: ntp_servers.clone(),
interface: "127.0.0.1".into(), interface: "127.0.0.1".into(),
port: 3123, port: 3123,
hosts: Some(vec![]), hosts: Some(vec![]),
@ -1604,7 +1594,6 @@ mod tests {
assert_eq!(conf3.directories().signer, "signer".to_owned()); assert_eq!(conf3.directories().signer, "signer".to_owned());
assert_eq!(conf3.ui_config(), UiConfiguration { assert_eq!(conf3.ui_config(), UiConfiguration {
enabled: true, enabled: true,
ntp_servers: ntp_servers.clone(),
interface: "test".into(), interface: "test".into(),
port: 8180, port: 8180,
hosts: Some(vec![]), hosts: Some(vec![]),

View File

@ -22,12 +22,12 @@ use ethcore::client::{Client, BlockChainClient, BlockId};
use ethcore::transaction::{Transaction, Action}; use ethcore::transaction::{Transaction, Action};
use ethsync::LightSync; use ethsync::LightSync;
use futures::{future, IntoFuture, Future, BoxFuture}; use futures::{future, IntoFuture, Future, BoxFuture};
use futures_cpupool::CpuPool;
use hash_fetch::fetch::Client as FetchClient; use hash_fetch::fetch::Client as FetchClient;
use hash_fetch::urlhint::ContractClient; use hash_fetch::urlhint::ContractClient;
use helpers::replace_home; use helpers::replace_home;
use light::client::Client as LightClient; use light::client::Client as LightClient;
use light::on_demand::{self, OnDemand}; use light::on_demand::{self, OnDemand};
use node_health::{SyncStatus, NodeHealth};
use rpc; use rpc;
use rpc_apis::SignerService; use rpc_apis::SignerService;
use parity_reactor; use parity_reactor;
@ -36,7 +36,6 @@ use util::{Bytes, Address};
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Configuration { pub struct Configuration {
pub enabled: bool, pub enabled: bool,
pub ntp_servers: Vec<String>,
pub dapps_path: PathBuf, pub dapps_path: PathBuf,
pub extra_dapps: Vec<PathBuf>, pub extra_dapps: Vec<PathBuf>,
pub extra_embed_on: Vec<(String, u16)>, pub extra_embed_on: Vec<(String, u16)>,
@ -48,12 +47,6 @@ impl Default for Configuration {
let data_dir = default_data_path(); let data_dir = default_data_path();
Configuration { Configuration {
enabled: true, enabled: true,
ntp_servers: vec![
"0.parity.pool.ntp.org:123".into(),
"1.parity.pool.ntp.org:123".into(),
"2.parity.pool.ntp.org:123".into(),
"3.parity.pool.ntp.org:123".into(),
],
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(), dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
extra_dapps: vec![], extra_dapps: vec![],
extra_embed_on: vec![], extra_embed_on: vec![],
@ -149,10 +142,10 @@ impl ContractClient for LightRegistrar {
// to resolve. // to resolve.
#[derive(Clone)] #[derive(Clone)]
pub struct Dependencies { pub struct Dependencies {
pub node_health: NodeHealth,
pub sync_status: Arc<SyncStatus>, pub sync_status: Arc<SyncStatus>,
pub contract_client: Arc<ContractClient>, pub contract_client: Arc<ContractClient>,
pub remote: parity_reactor::TokioRemote, pub remote: parity_reactor::TokioRemote,
pub pool: CpuPool,
pub fetch: FetchClient, pub fetch: FetchClient,
pub signer: Arc<SignerService>, pub signer: Arc<SignerService>,
pub ui_address: Option<(String, u16)>, pub ui_address: Option<(String, u16)>,
@ -165,7 +158,6 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<Mi
server::dapps_middleware( server::dapps_middleware(
deps, deps,
&configuration.ntp_servers,
configuration.dapps_path, configuration.dapps_path,
configuration.extra_dapps, configuration.extra_dapps,
rpc::DAPPS_DOMAIN, rpc::DAPPS_DOMAIN,
@ -174,19 +166,18 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<Mi
).map(Some) ).map(Some)
} }
pub fn new_ui(enabled: bool, ntp_servers: &[String], deps: Dependencies) -> Result<Option<Middleware>, String> { pub fn new_ui(enabled: bool, deps: Dependencies) -> Result<Option<Middleware>, String> {
if !enabled { if !enabled {
return Ok(None); return Ok(None);
} }
server::ui_middleware( server::ui_middleware(
deps, deps,
ntp_servers,
rpc::DAPPS_DOMAIN, rpc::DAPPS_DOMAIN,
).map(Some) ).map(Some)
} }
pub use self::server::{SyncStatus, Middleware, service}; pub use self::server::{Middleware, service};
#[cfg(not(feature = "dapps"))] #[cfg(not(feature = "dapps"))]
mod server { mod server {
@ -196,11 +187,6 @@ mod server {
use parity_rpc::{hyper, RequestMiddleware, RequestMiddlewareAction}; use parity_rpc::{hyper, RequestMiddleware, RequestMiddlewareAction};
use rpc_apis; use rpc_apis;
pub trait SyncStatus {
fn is_major_importing(&self) -> bool;
fn peers(&self) -> (usize, usize);
}
pub struct Middleware; pub struct Middleware;
impl RequestMiddleware for Middleware { impl RequestMiddleware for Middleware {
fn on_request( fn on_request(
@ -212,7 +198,6 @@ mod server {
pub fn dapps_middleware( pub fn dapps_middleware(
_deps: Dependencies, _deps: Dependencies,
_ntp_servers: &[String],
_dapps_path: PathBuf, _dapps_path: PathBuf,
_extra_dapps: Vec<PathBuf>, _extra_dapps: Vec<PathBuf>,
_dapps_domain: &str, _dapps_domain: &str,
@ -224,7 +209,6 @@ mod server {
pub fn ui_middleware( pub fn ui_middleware(
_deps: Dependencies, _deps: Dependencies,
_ntp_servers: &[String],
_dapps_domain: &str, _dapps_domain: &str,
) -> Result<Middleware, String> { ) -> Result<Middleware, String> {
Err("Your Parity version has been compiled without UI support.".into()) Err("Your Parity version has been compiled without UI support.".into())
@ -246,11 +230,9 @@ mod server {
use parity_reactor; use parity_reactor;
pub use parity_dapps::Middleware; pub use parity_dapps::Middleware;
pub use parity_dapps::SyncStatus;
pub fn dapps_middleware( pub fn dapps_middleware(
deps: Dependencies, deps: Dependencies,
ntp_servers: &[String],
dapps_path: PathBuf, dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>, extra_dapps: Vec<PathBuf>,
dapps_domain: &str, dapps_domain: &str,
@ -262,8 +244,7 @@ mod server {
let web_proxy_tokens = Arc::new(move |token| signer.web_proxy_access_token_domain(&token)); let web_proxy_tokens = Arc::new(move |token| signer.web_proxy_access_token_domain(&token));
Ok(parity_dapps::Middleware::dapps( Ok(parity_dapps::Middleware::dapps(
ntp_servers, deps.node_health,
deps.pool,
parity_remote, parity_remote,
deps.ui_address, deps.ui_address,
extra_embed_on, extra_embed_on,
@ -280,13 +261,11 @@ mod server {
pub fn ui_middleware( pub fn ui_middleware(
deps: Dependencies, deps: Dependencies,
ntp_servers: &[String],
dapps_domain: &str, dapps_domain: &str,
) -> Result<Middleware, String> { ) -> Result<Middleware, String> {
let parity_remote = parity_reactor::Remote::new(deps.remote.clone()); let parity_remote = parity_reactor::Remote::new(deps.remote.clone());
Ok(parity_dapps::Middleware::ui( Ok(parity_dapps::Middleware::ui(
ntp_servers, deps.node_health,
deps.pool,
parity_remote, parity_remote,
dapps_domain, dapps_domain,
deps.contract_client, deps.contract_client,

View File

@ -58,6 +58,7 @@ extern crate ethcore_util as util;
extern crate ethcore_network as network; extern crate ethcore_network as network;
extern crate ethkey; extern crate ethkey;
extern crate ethsync; extern crate ethsync;
extern crate node_health;
extern crate panic_hook; extern crate panic_hook;
extern crate parity_hash_fetch as hash_fetch; extern crate parity_hash_fetch as hash_fetch;
extern crate parity_ipfs_api; extern crate parity_ipfs_api;

View File

@ -73,7 +73,6 @@ impl Default for HttpConfiguration {
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct UiConfiguration { pub struct UiConfiguration {
pub enabled: bool, pub enabled: bool,
pub ntp_servers: Vec<String>,
pub interface: String, pub interface: String,
pub port: u16, pub port: u16,
pub hosts: Option<Vec<String>>, pub hosts: Option<Vec<String>>,
@ -107,12 +106,6 @@ impl Default for UiConfiguration {
fn default() -> Self { fn default() -> Self {
UiConfiguration { UiConfiguration {
enabled: true && cfg!(feature = "ui-enabled"), enabled: true && cfg!(feature = "ui-enabled"),
ntp_servers: vec![
"0.parity.pool.ntp.org:123".into(),
"1.parity.pool.ntp.org:123".into(),
"2.parity.pool.ntp.org:123".into(),
"3.parity.pool.ntp.org:123".into(),
],
port: 8180, port: 8180,
interface: "127.0.0.1".into(), interface: "127.0.0.1".into(),
hosts: Some(vec![]), hosts: Some(vec![]),

View File

@ -27,17 +27,18 @@ use ethcore::account_provider::AccountProvider;
use ethcore::client::Client; use ethcore::client::Client;
use ethcore::miner::{Miner, ExternalMiner}; use ethcore::miner::{Miner, ExternalMiner};
use ethcore::snapshot::SnapshotService; use ethcore::snapshot::SnapshotService;
use parity_rpc::{Metadata, NetworkSettings}; use ethcore_logger::RotatingLogger;
use parity_rpc::informant::{ActivityNotifier, ClientNotifier};
use parity_rpc::dispatch::{FullDispatcher, LightDispatcher};
use ethsync::{ManageNetwork, SyncProvider, LightSync}; use ethsync::{ManageNetwork, SyncProvider, LightSync};
use hash_fetch::fetch::Client as FetchClient; use hash_fetch::fetch::Client as FetchClient;
use jsonrpc_core::{self as core, MetaIoHandler}; use jsonrpc_core::{self as core, MetaIoHandler};
use light::{TransactionQueue as LightTransactionQueue, Cache as LightDataCache}; use light::{TransactionQueue as LightTransactionQueue, Cache as LightDataCache};
use node_health::NodeHealth;
use parity_reactor;
use parity_rpc::dispatch::{FullDispatcher, LightDispatcher};
use parity_rpc::informant::{ActivityNotifier, ClientNotifier};
use parity_rpc::{Metadata, NetworkSettings};
use updater::Updater; use updater::Updater;
use util::{Mutex, RwLock}; use util::{Mutex, RwLock};
use ethcore_logger::RotatingLogger;
use parity_reactor;
#[derive(Debug, PartialEq, Clone, Eq, Hash)] #[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub enum Api { pub enum Api {
@ -217,6 +218,7 @@ pub struct FullDependencies {
pub settings: Arc<NetworkSettings>, pub settings: Arc<NetworkSettings>,
pub net_service: Arc<ManageNetwork>, pub net_service: Arc<ManageNetwork>,
pub updater: Arc<Updater>, pub updater: Arc<Updater>,
pub health: NodeHealth,
pub geth_compatibility: bool, pub geth_compatibility: bool,
pub dapps_service: Option<Arc<DappsService>>, pub dapps_service: Option<Arc<DappsService>>,
pub dapps_address: Option<(String, u16)>, pub dapps_address: Option<(String, u16)>,
@ -300,12 +302,13 @@ impl FullDependencies {
false => None, false => None,
}; };
handler.extend_with(ParityClient::new( handler.extend_with(ParityClient::new(
&self.client, self.client.clone(),
&self.miner, self.miner.clone(),
&self.sync, self.sync.clone(),
&self.updater, self.updater.clone(),
&self.net_service, self.net_service.clone(),
&self.secret_store, self.health.clone(),
self.secret_store.clone(),
self.logger.clone(), self.logger.clone(),
self.settings.clone(), self.settings.clone(),
signer, signer,
@ -403,6 +406,7 @@ pub struct LightDependencies {
pub secret_store: Arc<AccountProvider>, pub secret_store: Arc<AccountProvider>,
pub logger: Arc<RotatingLogger>, pub logger: Arc<RotatingLogger>,
pub settings: Arc<NetworkSettings>, pub settings: Arc<NetworkSettings>,
pub health: NodeHealth,
pub on_demand: Arc<::light::on_demand::OnDemand>, pub on_demand: Arc<::light::on_demand::OnDemand>,
pub cache: Arc<Mutex<LightDataCache>>, pub cache: Arc<Mutex<LightDataCache>>,
pub transaction_queue: Arc<RwLock<LightTransactionQueue>>, pub transaction_queue: Arc<RwLock<LightTransactionQueue>>,
@ -507,6 +511,7 @@ impl LightDependencies {
self.secret_store.clone(), self.secret_store.clone(),
self.logger.clone(), self.logger.clone(),
self.settings.clone(), self.settings.clone(),
self.health.clone(),
signer, signer,
self.dapps_address.clone(), self.dapps_address.clone(),
self.ws_address.clone(), self.ws_address.clone(),

View File

@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::fmt;
use std::sync::Arc; use std::sync::Arc;
use std::net::{TcpListener}; use std::net::{TcpListener};
@ -32,6 +33,7 @@ use fdlimit::raise_fd_limit;
use hash_fetch::fetch::{Fetch, Client as FetchClient}; use hash_fetch::fetch::{Fetch, Client as FetchClient};
use informant::{Informant, LightNodeInformantData, FullNodeInformantData}; use informant::{Informant, LightNodeInformantData, FullNodeInformantData};
use light::Cache as LightDataCache; use light::Cache as LightDataCache;
use node_health;
use parity_reactor::EventLoop; use parity_reactor::EventLoop;
use parity_rpc::{NetworkSettings, informant, is_major_importing}; use parity_rpc::{NetworkSettings, informant, is_major_importing};
use updater::{UpdatePolicy, Updater}; use updater::{UpdatePolicy, Updater};
@ -80,6 +82,7 @@ pub struct RunCmd {
pub daemon: Option<String>, pub daemon: Option<String>,
pub logger_config: LogConfig, pub logger_config: LogConfig,
pub miner_options: MinerOptions, pub miner_options: MinerOptions,
pub ntp_servers: Vec<String>,
pub ws_conf: rpc::WsConfiguration, pub ws_conf: rpc::WsConfiguration,
pub http_conf: rpc::HttpConfiguration, pub http_conf: rpc::HttpConfiguration,
pub ipc_conf: rpc::IpcConfiguration, pub ipc_conf: rpc::IpcConfiguration,
@ -283,7 +286,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
// the dapps server // the dapps server
let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config)); let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config));
let dapps_deps = { let (node_health, dapps_deps) = {
let contract_client = Arc::new(::dapps::LightRegistrar { let contract_client = Arc::new(::dapps::LightRegistrar {
client: service.client().clone(), client: service.client().clone(),
sync: light_sync.clone(), sync: light_sync.clone(),
@ -291,7 +294,12 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
}); });
struct LightSyncStatus(Arc<LightSync>); struct LightSyncStatus(Arc<LightSync>);
impl dapps::SyncStatus for LightSyncStatus { impl fmt::Debug for LightSyncStatus {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Light Sync Status")
}
}
impl node_health::SyncStatus for LightSyncStatus {
fn is_major_importing(&self) -> bool { self.0.is_major_importing() } fn is_major_importing(&self) -> bool { self.0.is_major_importing() }
fn peers(&self) -> (usize, usize) { fn peers(&self) -> (usize, usize) {
let peers = ethsync::LightSyncProvider::peer_numbers(&*self.0); let peers = ethsync::LightSyncProvider::peer_numbers(&*self.0);
@ -299,19 +307,26 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
} }
} }
dapps::Dependencies { let sync_status = Arc::new(LightSyncStatus(light_sync.clone()));
sync_status: Arc::new(LightSyncStatus(light_sync.clone())), let node_health = node_health::NodeHealth::new(
pool: fetch.pool(), sync_status.clone(),
node_health::TimeChecker::new(&cmd.ntp_servers, fetch.pool()),
event_loop.remote(),
);
(node_health.clone(), dapps::Dependencies {
sync_status,
node_health,
contract_client: contract_client, contract_client: contract_client,
remote: event_loop.raw_remote(), remote: event_loop.raw_remote(),
fetch: fetch.clone(), fetch: fetch.clone(),
signer: signer_service.clone(), signer: signer_service.clone(),
ui_address: cmd.ui_conf.address(), ui_address: cmd.ui_conf.address(),
} })
}; };
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?;
let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, &cmd.ui_conf.ntp_servers, dapps_deps)?; let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?;
// start RPCs // start RPCs
let dapps_service = dapps::service(&dapps_middleware); let dapps_service = dapps::service(&dapps_middleware);
@ -320,6 +335,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
client: service.client().clone(), client: service.client().clone(),
sync: light_sync.clone(), sync: light_sync.clone(),
net: light_sync.clone(), net: light_sync.clone(),
health: node_health,
secret_store: account_provider, secret_store: account_provider,
logger: logger, logger: logger,
settings: Arc::new(cmd.net_settings), settings: Arc::new(cmd.net_settings),
@ -661,12 +677,17 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config)); let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.ui_conf, &cmd.logger_config));
// the dapps server // the dapps server
let dapps_deps = { let (node_health, dapps_deps) = {
let (sync, client) = (sync_provider.clone(), client.clone()); let (sync, client) = (sync_provider.clone(), client.clone());
let contract_client = Arc::new(::dapps::FullRegistrar { client: client.clone() }); let contract_client = Arc::new(::dapps::FullRegistrar { client: client.clone() });
struct SyncStatus(Arc<ethsync::SyncProvider>, Arc<Client>, ethsync::NetworkConfiguration); struct SyncStatus(Arc<ethsync::SyncProvider>, Arc<Client>, ethsync::NetworkConfiguration);
impl dapps::SyncStatus for SyncStatus { impl fmt::Debug for SyncStatus {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Dapps Sync Status")
}
}
impl node_health::SyncStatus for SyncStatus {
fn is_major_importing(&self) -> bool { fn is_major_importing(&self) -> bool {
is_major_importing(Some(self.0.status().state), self.1.queue_info()) is_major_importing(Some(self.0.status().state), self.1.queue_info())
} }
@ -676,18 +697,24 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
} }
} }
dapps::Dependencies { let sync_status = Arc::new(SyncStatus(sync, client, net_conf));
sync_status: Arc::new(SyncStatus(sync, client, net_conf)), let node_health = node_health::NodeHealth::new(
pool: fetch.pool(), sync_status.clone(),
node_health::TimeChecker::new(&cmd.ntp_servers, fetch.pool()),
event_loop.remote(),
);
(node_health.clone(), dapps::Dependencies {
sync_status,
node_health,
contract_client: contract_client, contract_client: contract_client,
remote: event_loop.raw_remote(), remote: event_loop.raw_remote(),
fetch: fetch.clone(), fetch: fetch.clone(),
signer: signer_service.clone(), signer: signer_service.clone(),
ui_address: cmd.ui_conf.address(), ui_address: cmd.ui_conf.address(),
} })
}; };
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?;
let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, &cmd.ui_conf.ntp_servers, dapps_deps)?; let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?;
let dapps_service = dapps::service(&dapps_middleware); let dapps_service = dapps::service(&dapps_middleware);
let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies { let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies {
@ -695,6 +722,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
snapshot: snapshot_service.clone(), snapshot: snapshot_service.clone(),
client: client.clone(), client: client.clone(),
sync: sync_provider.clone(), sync: sync_provider.clone(),
health: node_health,
net: manage_network.clone(), net: manage_network.clone(),
secret_store: secret_store, secret_store: secret_store,
miner: miner.clone(), miner: miner.clone(),

View File

@ -47,12 +47,13 @@ ethjson = { path = "../json" }
ethcore-devtools = { path = "../devtools" } ethcore-devtools = { path = "../devtools" }
ethcore-light = { path = "../ethcore/light" } ethcore-light = { path = "../ethcore/light" }
ethcore-logger = { path = "../logger" } ethcore-logger = { path = "../logger" }
vm = { path = "../ethcore/vm" }
parity-updater = { path = "../updater" }
parity-reactor = { path = "../util/reactor" }
rlp = { path = "../util/rlp" }
fetch = { path = "../util/fetch" } fetch = { path = "../util/fetch" }
node-health = { path = "../dapps/node-health" }
parity-reactor = { path = "../util/reactor" }
parity-updater = { path = "../updater" }
rlp = { path = "../util/rlp" }
stats = { path = "../util/stats" } stats = { path = "../util/stats" }
vm = { path = "../ethcore/vm" }
clippy = { version = "0.0.103", optional = true} clippy = { version = "0.0.103", optional = true}
pretty_assertions = "0.1" pretty_assertions = "0.1"

View File

@ -55,6 +55,7 @@ extern crate ethsync;
extern crate ethcore_logger; extern crate ethcore_logger;
extern crate vm; extern crate vm;
extern crate fetch; extern crate fetch;
extern crate node_health;
extern crate parity_reactor; extern crate parity_reactor;
extern crate parity_updater as updater; extern crate parity_updater as updater;
extern crate rlp; extern crate rlp;

View File

@ -584,8 +584,9 @@ fn decrypt(accounts: &AccountProvider, address: Address, msg: Bytes, password: S
} }
/// Extract the default gas price from a client and miner. /// Extract the default gas price from a client and miner.
pub fn default_gas_price<C, M>(client: &C, miner: &M) -> U256 pub fn default_gas_price<C, M>(client: &C, miner: &M) -> U256 where
where C: MiningBlockChainClient, M: MinerService C: MiningBlockChainClient,
M: MinerService,
{ {
client.gas_price_corpus(100).median().cloned().unwrap_or_else(|| miner.sensible_gas_price()) client.gas_price_corpus(100).median().cloned().unwrap_or_else(|| miner.sensible_gas_price())
} }

View File

@ -24,8 +24,8 @@ use jsonrpc_core::Error;
use v1::helpers::CallRequest; use v1::helpers::CallRequest;
use v1::helpers::dispatch::default_gas_price; use v1::helpers::dispatch::default_gas_price;
pub fn sign_call<B: MiningBlockChainClient, M: MinerService>( pub fn sign_call<C: MiningBlockChainClient, M: MinerService> (
client: &Arc<B>, client: &Arc<C>,
miner: &Arc<M>, miner: &Arc<M>,
request: CallRequest, request: CallRequest,
gas_cap: bool, gas_cap: bool,

View File

@ -19,15 +19,15 @@ use std::sync::Arc;
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use futures::{future, Future, BoxFuture}; use futures::{future, Future, BoxFuture};
use ethcore_logger::RotatingLogger;
use util::misc::version_data; use util::misc::version_data;
use crypto::ecies; use crypto::{ecies, DEFAULT_MAC};
use ethkey::{Brain, Generator}; use ethkey::{Brain, Generator};
use ethstore::random_phrase; use ethstore::random_phrase;
use ethsync::LightSyncProvider; use ethsync::LightSyncProvider;
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use crypto::DEFAULT_MAC; use ethcore_logger::RotatingLogger;
use node_health::{NodeHealth, Health};
use light::client::LightChainClient; use light::client::LightChainClient;
@ -53,6 +53,7 @@ pub struct ParityClient {
accounts: Arc<AccountProvider>, accounts: Arc<AccountProvider>,
logger: Arc<RotatingLogger>, logger: Arc<RotatingLogger>,
settings: Arc<NetworkSettings>, settings: Arc<NetworkSettings>,
health: NodeHealth,
signer: Option<Arc<SignerService>>, signer: Option<Arc<SignerService>>,
dapps_address: Option<(String, u16)>, dapps_address: Option<(String, u16)>,
ws_address: Option<(String, u16)>, ws_address: Option<(String, u16)>,
@ -67,18 +68,20 @@ impl ParityClient {
accounts: Arc<AccountProvider>, accounts: Arc<AccountProvider>,
logger: Arc<RotatingLogger>, logger: Arc<RotatingLogger>,
settings: Arc<NetworkSettings>, settings: Arc<NetworkSettings>,
health: NodeHealth,
signer: Option<Arc<SignerService>>, signer: Option<Arc<SignerService>>,
dapps_address: Option<(String, u16)>, dapps_address: Option<(String, u16)>,
ws_address: Option<(String, u16)>, ws_address: Option<(String, u16)>,
) -> Self { ) -> Self {
ParityClient { ParityClient {
light_dispatch: light_dispatch, light_dispatch,
accounts: accounts, accounts,
logger: logger, logger,
settings: settings, settings,
signer: signer, health,
dapps_address: dapps_address, signer,
ws_address: ws_address, dapps_address,
ws_address,
eip86_transition: client.eip86_transition(), eip86_transition: client.eip86_transition(),
} }
} }
@ -393,4 +396,10 @@ impl Parity for ParityClient {
fn call(&self, _meta: Self::Metadata, _requests: Vec<CallRequest>, _block: Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error> { fn call(&self, _meta: Self::Metadata, _requests: Vec<CallRequest>, _block: Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error> {
future::err(errors::light_unimplemented(None)).boxed() future::err(errors::light_unimplemented(None)).boxed()
} }
fn node_health(&self) -> BoxFuture<Health, Error> {
self.health.health()
.map_err(|err| errors::internal("Health API failure.", err))
.boxed()
}
} }

View File

@ -20,11 +20,10 @@ use std::str::FromStr;
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use futures::{future, Future, BoxFuture}; use futures::{future, Future, BoxFuture};
use ethcore_logger::RotatingLogger;
use util::Address; use util::Address;
use util::misc::version_data; use util::misc::version_data;
use crypto::ecies; use crypto::{DEFAULT_MAC, ecies};
use ethkey::{Brain, Generator}; use ethkey::{Brain, Generator};
use ethstore::random_phrase; use ethstore::random_phrase;
use ethsync::{SyncProvider, ManageNetwork}; use ethsync::{SyncProvider, ManageNetwork};
@ -34,8 +33,9 @@ use ethcore::ids::BlockId;
use ethcore::miner::MinerService; use ethcore::miner::MinerService;
use ethcore::mode::Mode; use ethcore::mode::Mode;
use ethcore::transaction::SignedTransaction; use ethcore::transaction::SignedTransaction;
use ethcore_logger::RotatingLogger;
use node_health::{NodeHealth, Health};
use updater::{Service as UpdateService}; use updater::{Service as UpdateService};
use crypto::DEFAULT_MAC;
use jsonrpc_core::Error; use jsonrpc_core::Error;
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
@ -53,17 +53,13 @@ use v1::types::{
}; };
/// Parity implementation. /// Parity implementation.
pub struct ParityClient<C, M, S: ?Sized, U> where pub struct ParityClient<C, M, U> {
C: MiningBlockChainClient,
M: MinerService,
S: SyncProvider,
U: UpdateService,
{
client: Arc<C>, client: Arc<C>,
miner: Arc<M>, miner: Arc<M>,
sync: Arc<S>,
updater: Arc<U>, updater: Arc<U>,
sync: Arc<SyncProvider>,
net: Arc<ManageNetwork>, net: Arc<ManageNetwork>,
health: NodeHealth,
accounts: Option<Arc<AccountProvider>>, accounts: Option<Arc<AccountProvider>>,
logger: Arc<RotatingLogger>, logger: Arc<RotatingLogger>,
settings: Arc<NetworkSettings>, settings: Arc<NetworkSettings>,
@ -73,39 +69,39 @@ pub struct ParityClient<C, M, S: ?Sized, U> where
eip86_transition: u64, eip86_transition: u64,
} }
impl<C, M, S: ?Sized, U> ParityClient<C, M, S, U> where impl<C, M, U> ParityClient<C, M, U> where
C: MiningBlockChainClient, C: MiningBlockChainClient,
M: MinerService,
S: SyncProvider,
U: UpdateService,
{ {
/// Creates new `ParityClient`. /// Creates new `ParityClient`.
pub fn new( pub fn new(
client: &Arc<C>, client: Arc<C>,
miner: &Arc<M>, miner: Arc<M>,
sync: &Arc<S>, sync: Arc<SyncProvider>,
updater: &Arc<U>, updater: Arc<U>,
net: &Arc<ManageNetwork>, net: Arc<ManageNetwork>,
store: &Option<Arc<AccountProvider>>, health: NodeHealth,
accounts: Option<Arc<AccountProvider>>,
logger: Arc<RotatingLogger>, logger: Arc<RotatingLogger>,
settings: Arc<NetworkSettings>, settings: Arc<NetworkSettings>,
signer: Option<Arc<SignerService>>, signer: Option<Arc<SignerService>>,
dapps_address: Option<(String, u16)>, dapps_address: Option<(String, u16)>,
ws_address: Option<(String, u16)>, ws_address: Option<(String, u16)>,
) -> Self { ) -> Self {
let eip86_transition = client.eip86_transition();
ParityClient { ParityClient {
client: client.clone(), client,
miner: miner.clone(), miner,
sync: sync.clone(), sync,
updater: updater.clone(), updater,
net: net.clone(), net,
accounts: store.clone(), health,
logger: logger, accounts,
settings: settings, logger,
signer: signer, settings,
dapps_address: dapps_address, signer,
ws_address: ws_address, dapps_address,
eip86_transition: client.eip86_transition(), ws_address,
eip86_transition,
} }
} }
@ -116,10 +112,9 @@ impl<C, M, S: ?Sized, U> ParityClient<C, M, S, U> where
} }
} }
impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where impl<C, M, U> Parity for ParityClient<C, M, U> where
M: MinerService + 'static,
C: MiningBlockChainClient + 'static, C: MiningBlockChainClient + 'static,
S: SyncProvider + 'static, M: MinerService + 'static,
U: UpdateService + 'static, U: UpdateService + 'static,
{ {
type Metadata = Metadata; type Metadata = Metadata;
@ -429,4 +424,10 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
future::done(result).boxed() future::done(result).boxed()
} }
fn node_health(&self) -> BoxFuture<Health, Error> {
self.health.health()
.map_err(|err| errors::internal("Health API failure.", err))
.boxed()
}
} }

View File

@ -15,13 +15,15 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc; use std::sync::Arc;
use ethcore_logger::RotatingLogger;
use util::{Address, U256};
use ethsync::ManageNetwork;
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use ethcore::client::{TestBlockChainClient, Executed}; use ethcore::client::{TestBlockChainClient, Executed};
use ethcore::miner::LocalTransactionStatus; use ethcore::miner::LocalTransactionStatus;
use ethcore_logger::RotatingLogger;
use ethstore::ethkey::{Generator, Random}; use ethstore::ethkey::{Generator, Random};
use ethsync::ManageNetwork;
use node_health::{self, NodeHealth};
use parity_reactor;
use util::Address;
use jsonrpc_core::IoHandler; use jsonrpc_core::IoHandler;
use v1::{Parity, ParityClient}; use v1::{Parity, ParityClient};
@ -30,13 +32,14 @@ use v1::helpers::{SignerService, NetworkSettings};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService, TestUpdater}; use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService, TestUpdater};
use super::manage_network::TestManageNetwork; use super::manage_network::TestManageNetwork;
pub type TestParityClient = ParityClient<TestBlockChainClient, TestMinerService, TestSyncProvider, TestUpdater>; pub type TestParityClient = ParityClient<TestBlockChainClient, TestMinerService, TestUpdater>;
pub struct Dependencies { pub struct Dependencies {
pub miner: Arc<TestMinerService>, pub miner: Arc<TestMinerService>,
pub client: Arc<TestBlockChainClient>, pub client: Arc<TestBlockChainClient>,
pub sync: Arc<TestSyncProvider>, pub sync: Arc<TestSyncProvider>,
pub updater: Arc<TestUpdater>, pub updater: Arc<TestUpdater>,
pub health: NodeHealth,
pub logger: Arc<RotatingLogger>, pub logger: Arc<RotatingLogger>,
pub settings: Arc<NetworkSettings>, pub settings: Arc<NetworkSettings>,
pub network: Arc<ManageNetwork>, pub network: Arc<ManageNetwork>,
@ -54,6 +57,11 @@ impl Dependencies {
network_id: 3, network_id: 3,
num_peers: 120, num_peers: 120,
})), })),
health: NodeHealth::new(
Arc::new(FakeSync),
node_health::TimeChecker::new::<String>(&[], node_health::CpuPool::new(1)),
parity_reactor::Remote::new_sync(),
),
updater: Arc::new(TestUpdater::default()), updater: Arc::new(TestUpdater::default()),
logger: Arc::new(RotatingLogger::new("rpc=trace".to_owned())), logger: Arc::new(RotatingLogger::new("rpc=trace".to_owned())),
settings: Arc::new(NetworkSettings { settings: Arc::new(NetworkSettings {
@ -75,12 +83,13 @@ impl Dependencies {
let opt_accounts = Some(self.accounts.clone()); let opt_accounts = Some(self.accounts.clone());
ParityClient::new( ParityClient::new(
&self.client, self.client.clone(),
&self.miner, self.miner.clone(),
&self.sync, self.sync.clone(),
&self.updater, self.updater.clone(),
&self.network, self.network.clone(),
&opt_accounts, self.health.clone(),
opt_accounts.clone(),
self.logger.clone(), self.logger.clone(),
self.settings.clone(), self.settings.clone(),
signer, signer,
@ -102,6 +111,13 @@ impl Dependencies {
} }
} }
#[derive(Debug)]
struct FakeSync;
impl node_health::SyncStatus for FakeSync {
fn is_major_importing(&self) -> bool { false }
fn peers(&self) -> (usize, usize) { (4, 25) }
}
#[test] #[test]
fn rpc_parity_accounts_info() { fn rpc_parity_accounts_info() {
let deps = Dependencies::new(); let deps = Dependencies::new();
@ -507,6 +523,8 @@ fn rpc_parity_cid() {
#[test] #[test]
fn rpc_parity_call() { fn rpc_parity_call() {
use util::U256;
let deps = Dependencies::new(); let deps = Dependencies::new();
deps.client.set_execution_result(Ok(Executed { deps.client.set_execution_result(Ok(Executed {
exception: None, exception: None,
@ -541,3 +559,14 @@ fn rpc_parity_call() {
assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
} }
#[test]
fn rpc_parity_node_health() {
let deps = Dependencies::new();
let io = deps.default_client();
let request = r#"{"jsonrpc": "2.0", "method": "parity_nodeHealth", "params":[], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":{"peers":{"details":[4,25],"message":"","status":"ok"},"sync":{"details":false,"message":"","status":"ok"},"time":{"details":0,"message":"","status":"ok"}},"id":1}"#;
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}

View File

@ -22,6 +22,7 @@ use jsonrpc_core::Error;
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
use futures::BoxFuture; use futures::BoxFuture;
use node_health::Health;
use v1::types::{ use v1::types::{
H160, H256, H512, U256, Bytes, CallRequest, H160, H256, H512, U256, Bytes, CallRequest,
Peers, Transaction, RpcSettings, Histogram, Peers, Transaction, RpcSettings, Histogram,
@ -207,5 +208,9 @@ build_rpc_trait! {
/// Call contract, returning the output data. /// Call contract, returning the output data.
#[rpc(meta, name = "parity_call")] #[rpc(meta, name = "parity_call")]
fn call(&self, Self::Metadata, Vec<CallRequest>, Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error>; fn call(&self, Self::Metadata, Vec<CallRequest>, Trailing<BlockNumber>) -> BoxFuture<Vec<Bytes>, Error>;
/// Returns node's health report.
#[rpc(async, name = "parity_nodeHealth")]
fn node_health(&self) -> BoxFuture<Health, Error>;
} }
} }

View File

@ -20,7 +20,7 @@
extern crate futures; extern crate futures;
extern crate tokio_core; extern crate tokio_core;
use std::thread; use std::{fmt, thread};
use std::sync::mpsc; use std::sync::mpsc;
use std::time::Duration; use std::time::Duration;
use futures::{Future, IntoFuture}; use futures::{Future, IntoFuture};
@ -81,7 +81,19 @@ enum Mode {
ThreadPerFuture, ThreadPerFuture,
} }
#[derive(Clone)] impl fmt::Debug for Mode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
use self::Mode::*;
match *self {
Tokio(_) => write!(fmt, "tokio"),
Sync => write!(fmt, "synchronous"),
ThreadPerFuture => write!(fmt, "thread per future"),
}
}
}
#[derive(Debug, Clone)]
pub struct Remote { pub struct Remote {
inner: Mode, inner: Mode,
} }