Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Health endpoint #9847

Merged
merged 7 commits into from
Nov 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion parity/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,10 @@ impl Configuration {
Ok(name.parse()?)
}

fn is_dev_chain(&self) -> Result<bool, String> {
Ok(self.chain()? == SpecType::Dev)
}

fn max_peers(&self) -> u32 {
self.args.arg_max_peers
.or(cmp::max(self.args.arg_min_peers, Some(DEFAULT_MAX_PEERS)))
Expand Down Expand Up @@ -528,7 +532,7 @@ impl Configuration {
}

fn miner_options(&self) -> Result<MinerOptions, String> {
let is_dev_chain = self.chain()? == SpecType::Dev;
let is_dev_chain = self.is_dev_chain()?;
if is_dev_chain && self.args.flag_force_sealing && self.args.arg_reseal_min_period == 0 {
return Err("Force sealing can't be used with reseal_min_period = 0".into());
}
Expand Down Expand Up @@ -921,6 +925,7 @@ impl Configuration {
Ok(NetworkSettings {
name: self.args.arg_identity.clone(),
chain: format!("{}", self.chain()?),
is_dev_chain: self.is_dev_chain()?,
network_port: net_addresses.0.port(),
rpc_enabled: http_conf.enabled,
rpc_interface: http_conf.interface,
Expand Down Expand Up @@ -1521,6 +1526,7 @@ mod tests {
assert_eq!(conf.network_settings(), Ok(NetworkSettings {
name: "testname".to_owned(),
chain: "kovan".to_owned(),
is_dev_chain: false,
network_port: 30303,
rpc_enabled: true,
rpc_interface: "127.0.0.1".to_owned(),
Expand Down
1 change: 1 addition & 0 deletions parity/rpc_apis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ impl FullDependencies {
self.settings.clone(),
signer,
self.ws_address.clone(),
self.snapshot.clone().into(),
).to_delegate());

if !for_generic_pubsub {
Expand Down
1 change: 1 addition & 0 deletions rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ pub fn start_http<M, S, H, T>(
.threads(threads)
.cors(cors_domains.into())
.allowed_hosts(allowed_hosts.into())
.health_api(("/api/health", "parity_nodeStatus"))
.max_request_body_size(max_payload * 1024 * 1024)
.start_http(addr)?)
}
Expand Down
3 changes: 2 additions & 1 deletion rpc/src/v1/extractors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,10 @@ impl<M: core::Middleware<Metadata>> WsDispatcher<M> {

impl<M: core::Middleware<Metadata>> core::Middleware<Metadata> for WsDispatcher<M> {
type Future = Either<
core::FutureRpcResult<M::Future>,
core::FutureRpcResult<M::Future, M::CallFuture>,
core::FutureResponse,
>;
type CallFuture = core::middleware::NoopCallFuture;

fn on_request<F, X>(&self, request: core::Request, meta: Metadata, process: F)
-> Either<Self::Future, X>
Expand Down
13 changes: 13 additions & 0 deletions rpc/src/v1/helpers/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ mod codes {
pub const ENCODING_ERROR: i64 = -32058;
pub const FETCH_ERROR: i64 = -32060;
pub const NO_LIGHT_PEERS: i64 = -32065;
pub const NO_PEERS: i64 = -32066;
pub const DEPRECATED: i64 = -32070;
}

Expand Down Expand Up @@ -500,3 +501,15 @@ pub fn on_demand_others(err: &OnDemandError) -> Error {
}
}

pub fn status_error(has_peers: bool) -> Error {
if has_peers {
no_work()
} else {
Error {
code: ErrorCode::ServerError(codes::NO_PEERS),
message: "Node is not connected to any peers.".into(),
data: None,
}
}
}

3 changes: 3 additions & 0 deletions rpc/src/v1/helpers/network_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ pub struct NetworkSettings {
pub name: String,
/// Name of the chain we are connected to
pub chain: String,
/// Is development chain
pub is_dev_chain: bool,
/// Networking port
pub network_port: u16,
/// Is JSON-RPC server enabled?
Expand All @@ -38,6 +40,7 @@ impl Default for NetworkSettings {
NetworkSettings {
name: "".into(),
chain: "foundation".into(),
is_dev_chain: false,
network_port: 30303,
rpc_enabled: true,
rpc_interface: "127.0.0.1".into(),
Expand Down
11 changes: 11 additions & 0 deletions rpc/src/v1/impls/light/parity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,4 +414,15 @@ impl Parity for ParityClient {
fn submit_work_detail(&self, _nonce: H64, _pow_hash: H256, _mix_hash: H256) -> Result<H256> {
Err(errors::light_unimplemented(None))
}

fn status(&self) -> Result<()> {
let has_peers = self.settings.is_dev_chain || self.light_dispatch.sync.peer_numbers().connected > 0;
let is_importing = self.light_dispatch.sync.is_major_importing();

if has_peers && !is_importing {
Ok(())
} else {
Err(errors::status_error(has_peers))
}
}
}
23 changes: 23 additions & 0 deletions rpc/src/v1/impls/parity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,16 @@ use ethcore::account_provider::AccountProvider;
use ethcore::client::{BlockChainClient, StateClient, Call};
use ethcore::ids::BlockId;
use ethcore::miner::{self, MinerService};
use ethcore::snapshot::{SnapshotService, RestorationStatus};
use ethcore::state::StateInfo;
use ethcore_logger::RotatingLogger;
use updater::{Service as UpdateService};
use jsonrpc_core::{BoxFuture, Result};
use jsonrpc_core::futures::future;
use jsonrpc_macros::Trailing;

use v1::helpers::{self, errors, fake_sign, ipfs, SigningQueue, SignerService, NetworkSettings};
use v1::helpers::block_import::is_major_importing;
use v1::metadata::Metadata;
use v1::traits::Parity;
use v1::types::{
Expand All @@ -62,6 +65,7 @@ pub struct ParityClient<C, M, U> {
settings: Arc<NetworkSettings>,
signer: Option<Arc<SignerService>>,
ws_address: Option<Host>,
snapshot: Option<Arc<SnapshotService>>,
}

impl<C, M, U> ParityClient<C, M, U> where
Expand All @@ -79,6 +83,7 @@ impl<C, M, U> ParityClient<C, M, U> where
settings: Arc<NetworkSettings>,
signer: Option<Arc<SignerService>>,
ws_address: Option<Host>,
snapshot: Option<Arc<SnapshotService>>,
) -> Self {
ParityClient {
client,
Expand All @@ -91,6 +96,7 @@ impl<C, M, U> ParityClient<C, M, U> where
settings,
signer,
ws_address,
snapshot,
}
}
}
Expand Down Expand Up @@ -481,4 +487,21 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
fn submit_work_detail(&self, nonce: H64, pow_hash: H256, mix_hash: H256) -> Result<H256> {
helpers::submit_work_detail(&self.client, &self.miner, nonce, pow_hash, mix_hash)
}

fn status(&self) -> Result<()> {
let has_peers = self.settings.is_dev_chain || self.sync.status().num_peers > 0;
let is_warping = match self.snapshot.as_ref().map(|s| s.status()) {
Some(RestorationStatus::Ongoing { .. }) => true,
_ => false,
};
let is_not_syncing =
!is_warping &&
!is_major_importing(Some(self.sync.status().state), self.client.queue_info());

if has_peers && is_not_syncing {
Ok(())
} else {
Err(errors::status_error(has_peers))
}
}
}
1 change: 1 addition & 0 deletions rpc/src/v1/informant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ impl<T: ActivityNotifier> Middleware<T> {

impl<M: core::Metadata, T: ActivityNotifier> core::Middleware<M> for Middleware<T> {
type Future = core::FutureResponse;
type CallFuture = core::middleware::NoopCallFuture;

fn on_request<F, X>(&self, request: core::Request, meta: M, process: F) -> Either<Self::Future, X> where
F: FnOnce(core::Request, M) -> X,
Expand Down
52 changes: 52 additions & 0 deletions rpc/src/v1/tests/mocked/parity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ impl Dependencies {
settings: Arc::new(NetworkSettings {
name: "mynode".to_owned(),
chain: "testchain".to_owned(),
is_dev_chain: false,
network_port: 30303,
rpc_enabled: true,
rpc_interface: "all".to_owned(),
Expand All @@ -83,6 +84,7 @@ impl Dependencies {
self.settings.clone(),
signer,
self.ws_address.clone(),
None,
)
}

Expand Down Expand Up @@ -552,3 +554,53 @@ fn rpc_parity_block_receipts() {

assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}

#[test]
fn rpc_status_ok() {
let deps = Dependencies::new();
let io = deps.default_client();

let request = r#"{
"jsonrpc": "2.0",
"method": "parity_nodeStatus",
"params": [],
"id": 1
}"#;
let response = r#"{"jsonrpc":"2.0","result":null,"id":1}"#;

assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}

#[test]
fn rpc_status_error_peers() {
let deps = Dependencies::new();
deps.sync.status.write().num_peers = 0;
let io = deps.default_client();

let request = r#"{
"jsonrpc": "2.0",
"method": "parity_nodeStatus",
"params": [],
"id": 1
}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32066,"message":"Node is not connected to any peers."},"id":1}"#;

assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}

#[test]
fn rpc_status_error_sync() {
let deps = Dependencies::new();
deps.sync.status.write().state = ::sync::SyncState::Blocks;
let io = deps.default_client();

let request = r#"{
"jsonrpc": "2.0",
"method": "parity_nodeStatus",
"params": [],
"id": 1
}"#;
let response = r#"{"jsonrpc":"2.0","error":{"code":-32001,"message":"Still syncing."},"id":1}"#;

assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
}
10 changes: 10 additions & 0 deletions rpc/src/v1/traits/parity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,5 +227,15 @@ build_rpc_trait! {
/// but returns block hash on success, and returns an explicit error message on failure).
#[rpc(name = "parity_submitWorkDetail")]
fn submit_work_detail(&self, H64, H256, H256) -> Result<H256>;

/// Returns the status of the node. Used as the health endpoint.
///
/// The RPC returns successful response if:
/// - The node have a peer (unless running a dev chain)
/// - The node is not syncing.
///
/// Otherwise the RPC returns error.
#[rpc(name = "parity_nodeStatus")]
fn status(&self) -> Result<()>;
}
}