diff --git a/js/src/api/format/output.js b/js/src/api/format/output.js index 952002b60..7348487e7 100644 --- a/js/src/api/format/output.js +++ b/js/src/api/format/output.js @@ -140,6 +140,10 @@ export function outHwAccountInfo (infos) { }, {}); } +export function outNodeKind (info) { + return info; +} + export function outNumber (number) { return new BigNumber(number || 0); } diff --git a/js/src/api/format/output.spec.js b/js/src/api/format/output.spec.js index c23751670..fabe30b32 100644 --- a/js/src/api/format/output.spec.js +++ b/js/src/api/format/output.spec.js @@ -16,7 +16,7 @@ import BigNumber from 'bignumber.js'; -import { outBlock, outAccountInfo, outAddress, outChainStatus, outDate, outHistogram, outHwAccountInfo, outNumber, outPeer, outPeers, outReceipt, outRecentDapps, outSyncing, outTransaction, outTrace, outVaultMeta } from './output'; +import { outBlock, outAccountInfo, outAddress, outChainStatus, outDate, outHistogram, outHwAccountInfo, outNodeKind, outNumber, outPeer, outPeers, outReceipt, outRecentDapps, outSyncing, outTransaction, outTrace, outVaultMeta } from './output'; import { isAddress, isBigNumber, isInstanceOf } from '../../../test/types'; describe('api/format/output', () => { @@ -173,6 +173,14 @@ describe('api/format/output', () => { }); }); + describe('outNodeKind', () => { + it('formats the input as received', () => { + const kind = { availability: 'personal', capability: 'full' }; + + expect(outNodeKind(kind)).to.deep.equal(kind); + }); + }); + describe('outNumber', () => { it('returns a BigNumber equalling the value', () => { const bn = outNumber('0x123456'); diff --git a/js/src/api/rpc/parity/parity.js b/js/src/api/rpc/parity/parity.js index dba6e5d30..26cfac505 100644 --- a/js/src/api/rpc/parity/parity.js +++ b/js/src/api/rpc/parity/parity.js @@ -15,7 +15,7 @@ // along with Parity. If not, see . import { inAddress, inAddresses, inData, inHex, inNumber16, inOptions, inBlockNumber } from '../../format/input'; -import { outAccountInfo, outAddress, outAddresses, outChainStatus, outHistogram, outHwAccountInfo, outNumber, outPeers, outRecentDapps, outTransaction, outVaultMeta } from '../../format/output'; +import { outAccountInfo, outAddress, outAddresses, outChainStatus, outHistogram, outHwAccountInfo, outNodeKind, outNumber, outPeers, outRecentDapps, outTransaction, outVaultMeta } from '../../format/output'; export default class Parity { constructor (transport) { @@ -290,6 +290,12 @@ export default class Parity { .execute('parity_chain'); } + nodeKind () { + return this._transport + .execute('parity_nodeKind') + .then(outNodeKind); + } + chain () { return this._transport .execute('parity_chain'); diff --git a/js/src/jsonrpc/interfaces/parity.js b/js/src/jsonrpc/interfaces/parity.js index 1e6df05de..7a883726a 100644 --- a/js/src/jsonrpc/interfaces/parity.js +++ b/js/src/jsonrpc/interfaces/parity.js @@ -419,6 +419,30 @@ export default { } }, + nodeKind: { + section: SECTION_NODE, + desc: 'Returns the node type availability and capability', + params: [], + returns: { + type: Object, + desc: 'Availability and Capability.', + details: { + availability: { + type: String, + desc: 'Availability, either `personal` or `public`.' + }, + capability: { + type: String, + desc: 'Capability, either `full` or `light`.' + } + } + }, + example: { + availability: 'personal', + capability: 'light' + } + }, + netChain: { section: SECTION_NET, desc: 'Returns the name of the connected chain.', diff --git a/rpc/src/v1/impls/light/parity.rs b/rpc/src/v1/impls/light/parity.rs index 545935417..46062b15a 100644 --- a/rpc/src/v1/impls/light/parity.rs +++ b/rpc/src/v1/impls/light/parity.rs @@ -333,4 +333,13 @@ impl Parity for ParityClient { block_gap: gap.map(|(x, y)| (x.into(), y.into())), }) } + + fn node_kind(&self) -> Result<::v1::types::NodeKind, Error> { + use ::v1::types::{NodeKind, Availability, Capability}; + + Ok(NodeKind { + availability: Availability::Personal, + capability: Capability::Light, + }) + } } diff --git a/rpc/src/v1/impls/parity.rs b/rpc/src/v1/impls/parity.rs index 2a7f85aa3..d6e16f267 100644 --- a/rpc/src/v1/impls/parity.rs +++ b/rpc/src/v1/impls/parity.rs @@ -372,4 +372,14 @@ impl Parity for ParityClient where block_gap: gap.map(|(x, y)| (x.into(), y.into())), }) } + + fn node_kind(&self) -> Result<::v1::types::NodeKind, Error> { + use ::v1::types::{NodeKind, Availability, Capability}; + + // TODO [maciej]: public availability flag. + Ok(NodeKind { + availability: Availability::Personal, + capability: Capability::Full, + }) + } } diff --git a/rpc/src/v1/tests/mocked/parity.rs b/rpc/src/v1/tests/mocked/parity.rs index 3af627037..e9b252af8 100644 --- a/rpc/src/v1/tests/mocked/parity.rs +++ b/rpc/src/v1/tests/mocked/parity.rs @@ -497,3 +497,14 @@ fn rpc_parity_chain_status() { assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); } + +#[test] +fn rpc_parity_node_kind() { + let deps = Dependencies::new(); + let io = deps.default_client(); + + let request = r#"{"jsonrpc": "2.0", "method": "parity_nodeKind", "params":[], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"availability":"personal","capability":"full"},"id":1}"#; + + assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); +} diff --git a/rpc/src/v1/traits/parity.rs b/rpc/src/v1/traits/parity.rs index 263adf6b2..8a15addae 100644 --- a/rpc/src/v1/traits/parity.rs +++ b/rpc/src/v1/traits/parity.rs @@ -194,5 +194,9 @@ build_rpc_trait! { /// Get the current chain status. #[rpc(name = "parity_chainStatus")] fn chain_status(&self) -> Result; + + /// Get node kind info. + #[rpc(name = "parity_nodeKind")] + fn node_kind(&self) -> Result<::v1::types::NodeKind, Error>; } } diff --git a/rpc/src/v1/types/mod.rs b/rpc/src/v1/types/mod.rs index a4bfcb41f..0ec60a74f 100644 --- a/rpc/src/v1/types/mod.rs +++ b/rpc/src/v1/types/mod.rs @@ -30,6 +30,7 @@ mod hash; mod histogram; mod index; mod log; +mod node_kind; mod provenance; mod receipt; mod rpc_settings; @@ -58,6 +59,7 @@ pub use self::hash::{H64, H160, H256, H512, H520, H2048}; pub use self::histogram::Histogram; pub use self::index::Index; pub use self::log::Log; +pub use self::node_kind::{NodeKind, Availability, Capability}; pub use self::provenance::{Origin, DappId}; pub use self::receipt::Receipt; pub use self::rpc_settings::RpcSettings; diff --git a/rpc/src/v1/types/node_kind.rs b/rpc/src/v1/types/node_kind.rs new file mode 100644 index 000000000..5c96fafc6 --- /dev/null +++ b/rpc/src/v1/types/node_kind.rs @@ -0,0 +1,92 @@ +// 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 . + +//! Description of the node. + +/// Describes the kind of node. This information can provide a hint to +/// applications about how to utilize the RPC. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct NodeKind { + /// The capability of the node. + pub capability: Capability, + /// Who the node is available to. + pub availability: Availability, +} + +/// Who the node is available to. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Availability { + /// A personal node, not intended to be available to everyone. + #[serde(rename="personal")] + Personal, + /// A public, open node. + #[serde(rename="public")] + Public, +} + +/// The capability of the node. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum Capability { + /// A full node stores the full state and fully enacts incoming blocks. + #[serde(rename="full")] + Full, + /// A light node does a minimal header sync and fetches data as needed + /// from the network. + #[serde(rename="light")] + Light, +} + +#[cfg(test)] +mod tests { + use super::{NodeKind, Availability, Capability}; + use serde_json; + + #[test] + fn availability() { + let personal = r#""personal""#; + let public = r#""public""#; + + assert_eq!(serde_json::to_string(&Availability::Personal).unwrap(), personal); + assert_eq!(serde_json::to_string(&Availability::Public).unwrap(), public); + + assert_eq!(serde_json::from_str::(personal).unwrap(), Availability::Personal); + assert_eq!(serde_json::from_str::(public).unwrap(), Availability::Public); + } + + #[test] + fn capability() { + let light = r#""light""#; + let full = r#""full""#; + + assert_eq!(serde_json::to_string(&Capability::Light).unwrap(), light); + assert_eq!(serde_json::to_string(&Capability::Full).unwrap(), full); + + assert_eq!(serde_json::from_str::(light).unwrap(), Capability::Light); + assert_eq!(serde_json::from_str::(full).unwrap(), Capability::Full); + } + + #[test] + fn node_kind() { + let kind = NodeKind { + capability: Capability::Full, + availability: Availability::Public, + }; + let s = r#"{"capability":"full","availability":"public"}"#; + + assert_eq!(serde_json::to_string(&kind).unwrap(), s); + assert_eq!(serde_json::from_str::(s).unwrap(), kind); + } +}