diff --git a/bin/oe/cli/mod.rs b/bin/oe/cli/mod.rs index 54e229957..f07422940 100644 --- a/bin/oe/cli/mod.rs +++ b/bin/oe/cli/mod.rs @@ -409,9 +409,9 @@ usage! { "--jsonrpc-interface=[IP]", "Specify the hostname portion of the HTTP JSON-RPC API server, IP should be an interface's IP address, or all (all interfaces) or local.", - ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces", or |c: &Config| c.rpc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), + ARG arg_jsonrpc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc", or |c: &Config| c.rpc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--jsonrpc-apis=[APIS]", - "Specify the APIs available through the HTTP JSON-RPC interface using a comma-delimited list of API names. Possible names are: all, safe, debug, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces", + "Specify the APIs available through the HTTP JSON-RPC interface using a comma-delimited list of API names. Possible names are: all, safe, debug, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc", ARG arg_jsonrpc_hosts: (String) = "none", or |c: &Config| c.rpc.as_ref()?.hosts.as_ref().map(|vec| vec.join(",")), "--jsonrpc-hosts=[HOSTS]", @@ -450,9 +450,9 @@ usage! { "--ws-interface=[IP]", "Specify the hostname portion of the WebSockets JSON-RPC server, IP should be an interface's IP address, or all (all interfaces) or local.", - ARG arg_ws_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces", or |c: &Config| c.websockets.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), + ARG arg_ws_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc", or |c: &Config| c.websockets.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--ws-apis=[APIS]", - "Specify the JSON-RPC APIs available through the WebSockets interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces", + "Specify the JSON-RPC APIs available through the WebSockets interface using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc", ARG arg_ws_origins: (String) = "parity://*,chrome-extension://*,moz-extension://*", or |c: &Config| c.websockets.as_ref()?.origins.as_ref().map(|vec| vec.join(",")), "--ws-origins=[URL]", @@ -492,9 +492,9 @@ usage! { "--ipc-path=[PATH]", "Specify custom path for JSON-RPC over IPC service.", - ARG arg_ipc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,parity_accounts,traces", or |c: &Config| c.ipc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), + ARG arg_ipc_apis: (String) = "web3,eth,pubsub,net,parity,parity_pubsub,parity_accounts,traces,rpc", or |c: &Config| c.ipc.as_ref()?.apis.as_ref().map(|vec| vec.join(",")), "--ipc-apis=[APIS]", - "Specify custom API set available via JSON-RPC over IPC using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces", + "Specify custom API set available via JSON-RPC over IPC using a comma-delimited list of API names. Possible names are: all, safe, web3, net, eth, pubsub, personal, signer, parity, parity_pubsub, parity_accounts, parity_set, traces, rpc, secretstore. You can also disable a specific API by putting '-' in the front, example: all,-personal. 'safe' enables the following APIs: web3, net, eth, pubsub, parity, parity_pubsub, traces, rpc", ["Secret Store Options"] FLAG flag_no_secretstore: (bool) = false, or |c: &Config| c.secretstore.as_ref()?.disable.clone(), @@ -1312,7 +1312,7 @@ mod tests { arg_jsonrpc_port: 8545u16, arg_jsonrpc_interface: "local".into(), arg_jsonrpc_cors: "null".into(), - arg_jsonrpc_apis: "web3,eth,net,parity,traces,secretstore".into(), + arg_jsonrpc_apis: "web3,eth,net,parity,traces,rpc,secretstore".into(), arg_jsonrpc_hosts: "none".into(), arg_jsonrpc_server_threads: None, arg_jsonrpc_threads: 4, @@ -1324,7 +1324,7 @@ mod tests { flag_no_ws: false, arg_ws_port: 8546u16, arg_ws_interface: "local".into(), - arg_ws_apis: "web3,eth,net,parity,traces,secretstore".into(), + arg_ws_apis: "web3,eth,net,parity,traces,rpc,secretstore".into(), arg_ws_origins: "none".into(), arg_ws_hosts: "none".into(), arg_ws_max_connections: 100, @@ -1333,7 +1333,7 @@ mod tests { // IPC flag_no_ipc: false, arg_ipc_path: "$HOME/.parity/jsonrpc.ipc".into(), - arg_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,secretstore" + arg_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,rpc,secretstore" .into(), // METRICS diff --git a/bin/oe/cli/tests/config.full.toml b/bin/oe/cli/tests/config.full.toml index 37b01cafc..0d0f7aec1 100644 --- a/bin/oe/cli/tests/config.full.toml +++ b/bin/oe/cli/tests/config.full.toml @@ -39,7 +39,7 @@ disable = false port = 8545 interface = "local" cors = ["null"] -apis = ["web3", "eth", "net", "parity", "traces", "secretstore"] +apis = ["web3", "eth", "net", "parity", "traces", "rpc", "secretstore"] hosts = ["none"] allow_missing_blocks = false @@ -48,13 +48,13 @@ disable = false port = 8546 interface = "local" origins = ["none"] -apis = ["web3", "eth", "net", "parity", "traces", "secretstore"] +apis = ["web3", "eth", "net", "parity", "traces", "rpc", "secretstore"] hosts = ["none"] [ipc] disable = false path = "$HOME/.parity/jsonrpc.ipc" -apis = ["web3", "eth", "net", "parity", "parity_accounts", "personal", "traces", "secretstore"] +apis = ["web3", "eth", "net", "parity", "parity_accounts", "personal", "traces", "rpc", "secretstore"] [secretstore] disable = false diff --git a/bin/oe/configuration.rs b/bin/oe/configuration.rs index fe7a71917..b0b1b9215 100644 --- a/bin/oe/configuration.rs +++ b/bin/oe/configuration.rs @@ -1741,7 +1741,7 @@ mod tests { ApiSet::List(set) => assert_eq!(set, ApiSet::All.list_apis()), _ => panic!("Incorrect rpc apis"), } - // "web3,eth,net,personal,parity,parity_set,traces,parity_accounts"); + // "web3,eth,net,personal,parity,parity_set,traces,rpc,parity_accounts"); assert_eq!(c.http_conf.hosts, None); } _ => panic!("Should be Cmd::Run"), @@ -1762,7 +1762,7 @@ mod tests { ApiSet::List(set) => assert_eq!(set, ApiSet::All.list_apis()), _ => panic!("Incorrect rpc apis"), } - // "web3,eth,net,personal,parity,parity_set,traces,parity_accounts"); + // "web3,eth,net,personal,parity,parity_set,traces,rpc,parity_accounts"); assert_eq!(c.http_conf.hosts, None); } _ => panic!("Should be Cmd::Run"), diff --git a/bin/oe/rpc_apis.rs b/bin/oe/rpc_apis.rs index 0de19f768..0acb88646 100644 --- a/bin/oe/rpc_apis.rs +++ b/bin/oe/rpc_apis.rs @@ -14,7 +14,12 @@ // You should have received a copy of the GNU General Public License // along with OpenEthereum. If not, see . -use std::{cmp::PartialEq, collections::HashSet, str::FromStr, sync::Arc}; +use std::{ + cmp::PartialEq, + collections::{BTreeMap, HashSet}, + str::FromStr, + sync::Arc, +}; pub use parity_rpc::signer::SignerService; @@ -51,6 +56,8 @@ pub enum Api { Parity, /// Traces (Safe) Traces, + /// Rpc (Safe) + Rpc, /// Parity PubSub - Generic Publish-Subscriber (Safety depends on other APIs exposed). ParityPubSub, /// Parity Accounts extensions (UNSAFE: Passwords, Side Effects (new account)) @@ -80,6 +87,7 @@ impl FromStr for Api { "parity_set" => Ok(ParitySet), "personal" => Ok(Personal), "pubsub" => Ok(EthPubSub), + "rpc" => Ok(Rpc), "secretstore" => Ok(SecretStore), "signer" => Ok(Signer), "traces" => Ok(Traces), @@ -146,6 +154,30 @@ impl FromStr for ApiSet { } } +fn to_modules(apis: &HashSet) -> BTreeMap { + let mut modules = BTreeMap::new(); + for api in apis { + let (name, version) = match *api { + Api::Debug => ("debug", "1.0"), + Api::Eth => ("eth", "1.0"), + Api::EthPubSub => ("pubsub", "1.0"), + Api::Net => ("net", "1.0"), + Api::Parity => ("parity", "1.0"), + Api::ParityAccounts => ("parity_accounts", "1.0"), + Api::ParityPubSub => ("parity_pubsub", "1.0"), + Api::ParitySet => ("parity_set", "1.0"), + Api::Personal => ("personal", "1.0"), + Api::Rpc => ("rpc", "1.0"), + Api::SecretStore => ("secretstore", "1.0"), + Api::Signer => ("signer", "1.0"), + Api::Traces => ("traces", "1.0"), + Api::Web3 => ("web3", "1.0"), + }; + modules.insert(name.into(), version.into()); + } + modules +} + macro_rules! add_signing_methods { ($namespace:ident, $handler:expr, $deps:expr, $dispatch:expr) => {{ let deps = &$deps; @@ -376,6 +408,10 @@ impl FullDependencies { ); } Api::Traces => handler.extend_with(TracesClient::new(&self.client).to_delegate()), + Api::Rpc => { + let modules = to_modules(&apis); + handler.extend_with(RpcClient::new(modules).to_delegate()); + } Api::SecretStore => { #[cfg(feature = "accounts")] handler.extend_with(SecretStoreClient::new(&self.accounts).to_delegate()); @@ -409,11 +445,17 @@ impl ApiSet { } pub fn list_apis(&self) -> HashSet { - let mut public_list: HashSet = - [Api::Web3, Api::Net, Api::Eth, Api::EthPubSub, Api::Parity] - .iter() - .cloned() - .collect(); + let mut public_list: HashSet = [ + Api::Web3, + Api::Net, + Api::Eth, + Api::EthPubSub, + Api::Parity, + Api::Rpc, + ] + .iter() + .cloned() + .collect(); match *self { ApiSet::List(ref apis) => apis.clone(), @@ -470,6 +512,7 @@ mod test { assert_eq!(Api::ParityAccounts, "parity_accounts".parse().unwrap()); assert_eq!(Api::ParitySet, "parity_set".parse().unwrap()); assert_eq!(Api::Traces, "traces".parse().unwrap()); + assert_eq!(Api::Rpc, "rpc".parse().unwrap()); assert_eq!(Api::SecretStore, "secretstore".parse().unwrap()); assert!("rp".parse::().is_err()); } @@ -498,6 +541,7 @@ mod test { Api::Parity, Api::ParityPubSub, Api::Traces, + Api::Rpc, ] .into_iter() .collect(); @@ -515,6 +559,7 @@ mod test { Api::Parity, Api::ParityPubSub, Api::Traces, + Api::Rpc, // semi-safe Api::ParityAccounts, ] @@ -536,6 +581,7 @@ mod test { Api::Parity, Api::ParityPubSub, Api::Traces, + Api::Rpc, Api::SecretStore, Api::ParityAccounts, Api::ParitySet, @@ -562,6 +608,7 @@ mod test { Api::Parity, Api::ParityPubSub, Api::Traces, + Api::Rpc, Api::SecretStore, Api::ParityAccounts, Api::ParitySet, @@ -587,6 +634,7 @@ mod test { Api::Parity, Api::ParityPubSub, Api::Traces, + Api::Rpc, ] .into_iter() .collect() diff --git a/crates/rpc/src/v1/impls/mod.rs b/crates/rpc/src/v1/impls/mod.rs index c8a1c64bc..5d7aa04d4 100644 --- a/crates/rpc/src/v1/impls/mod.rs +++ b/crates/rpc/src/v1/impls/mod.rs @@ -28,6 +28,7 @@ mod parity_set; #[cfg(any(test, feature = "accounts"))] mod personal; mod pubsub; +mod rpc; #[cfg(any(test, feature = "accounts"))] mod secretstore; mod signer; @@ -53,6 +54,7 @@ pub use self::{ parity::ParityClient, parity_set::ParitySetClient, pubsub::PubSubClient, + rpc::RpcClient, signer::SignerClient, signing::SigningQueueClient, signing_unsafe::SigningUnsafeClient, diff --git a/crates/rpc/src/v1/impls/rpc.rs b/crates/rpc/src/v1/impls/rpc.rs new file mode 100644 index 000000000..521818620 --- /dev/null +++ b/crates/rpc/src/v1/impls/rpc.rs @@ -0,0 +1,66 @@ +// Copyright 2015-2020 Parity Technologies (UK) Ltd. +// This file is part of OpenEthereum. + +// OpenEthereum 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. + +// OpenEthereum 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 OpenEthereum. If not, see . + +//! RPC generic methods implementation. +use jsonrpc_core::Result; +use std::collections::BTreeMap; +use v1::traits::Rpc; + +/// RPC generic methods implementation. +pub struct RpcClient { + modules: BTreeMap, + valid_apis: Vec, +} + +impl RpcClient { + /// Creates new `RpcClient`. + pub fn new(modules: BTreeMap) -> Self { + // geth 1.3.6 fails upon receiving unknown api + let valid_apis = vec!["web3", "eth", "net", "personal", "rpc"]; + + RpcClient { + modules, + valid_apis: valid_apis.into_iter().map(ToOwned::to_owned).collect(), + } + } +} + +impl Rpc for RpcClient { + fn rpc_modules(&self) -> Result> { + let modules = self + .modules + .iter() + .fold(BTreeMap::new(), |mut map, (k, v)| { + map.insert(k.to_owned(), v.to_owned()); + map + }); + + Ok(modules) + } + + fn modules(&self) -> Result> { + let modules = self + .modules + .iter() + .filter(|&(k, _v)| self.valid_apis.contains(k)) + .fold(BTreeMap::new(), |mut map, (k, v)| { + map.insert(k.to_owned(), v.to_owned()); + map + }); + + Ok(modules) + } +} diff --git a/crates/rpc/src/v1/mod.rs b/crates/rpc/src/v1/mod.rs index 1645cecd8..fe4357c15 100644 --- a/crates/rpc/src/v1/mod.rs +++ b/crates/rpc/src/v1/mod.rs @@ -48,7 +48,7 @@ pub use self::{ metadata::Metadata, traits::{ Debug, Eth, EthFilter, EthPubSub, EthSigning, Net, Parity, ParityAccounts, - ParityAccountsInfo, ParitySet, ParitySetAccounts, ParitySigning, Personal, PubSub, + ParityAccountsInfo, ParitySet, ParitySetAccounts, ParitySigning, Personal, PubSub, Rpc, SecretStore, Signer, Traces, Web3, }, types::Origin, diff --git a/crates/rpc/src/v1/tests/mocked/mod.rs b/crates/rpc/src/v1/tests/mocked/mod.rs index 878e0b050..82d08e2ca 100644 --- a/crates/rpc/src/v1/tests/mocked/mod.rs +++ b/crates/rpc/src/v1/tests/mocked/mod.rs @@ -29,6 +29,7 @@ mod parity_set; #[cfg(any(test, feature = "accounts"))] mod personal; mod pubsub; +mod rpc; #[cfg(any(test, feature = "accounts"))] mod secretstore; mod signer; diff --git a/crates/rpc/src/v1/tests/mocked/rpc.rs b/crates/rpc/src/v1/tests/mocked/rpc.rs new file mode 100644 index 000000000..6dc677c61 --- /dev/null +++ b/crates/rpc/src/v1/tests/mocked/rpc.rs @@ -0,0 +1,52 @@ +// Copyright 2015-2020 Parity Technologies (UK) Ltd. +// This file is part of OpenEthereum. + +// OpenEthereum 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. + +// OpenEthereum 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 OpenEthereum. If not, see . + +use jsonrpc_core::IoHandler; +use std::collections::BTreeMap; +use v1::{Rpc, RpcClient}; + +fn rpc_client() -> RpcClient { + let mut modules = BTreeMap::new(); + modules.insert("rpc".to_owned(), "1.0".to_owned()); + modules.insert("web3".to_owned(), "1.0".to_owned()); + modules.insert("ethcore".to_owned(), "1.0".to_owned()); + RpcClient::new(modules) +} + +#[test] +fn modules() { + let rpc = rpc_client().to_delegate(); + let mut io = IoHandler::new(); + io.extend_with(rpc); + + let request = r#"{"jsonrpc": "2.0", "method": "modules", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":{"rpc":"1.0","web3":"1.0"},"id":1}"#; + + assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); +} + +#[test] +fn rpc_modules() { + let rpc = rpc_client().to_delegate(); + let mut io = IoHandler::new(); + io.extend_with(rpc); + + let request = r#"{"jsonrpc": "2.0", "method": "rpc_modules", "params": [], "id": 1}"#; + let response = + r#"{"jsonrpc":"2.0","result":{"ethcore":"1.0","rpc":"1.0","web3":"1.0"},"id":1}"#; + + assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); +} diff --git a/crates/rpc/src/v1/traits/mod.rs b/crates/rpc/src/v1/traits/mod.rs index 046d54cb1..37c732b37 100644 --- a/crates/rpc/src/v1/traits/mod.rs +++ b/crates/rpc/src/v1/traits/mod.rs @@ -27,6 +27,7 @@ pub mod parity_set; pub mod parity_signing; pub mod personal; pub mod pubsub; +pub mod rpc; pub mod secretstore; pub mod signer; pub mod traces; @@ -44,6 +45,7 @@ pub use self::{ parity_signing::ParitySigning, personal::Personal, pubsub::PubSub, + rpc::Rpc, secretstore::SecretStore, signer::Signer, traces::Traces, diff --git a/crates/rpc/src/v1/traits/rpc.rs b/crates/rpc/src/v1/traits/rpc.rs new file mode 100644 index 000000000..1348279f0 --- /dev/null +++ b/crates/rpc/src/v1/traits/rpc.rs @@ -0,0 +1,36 @@ +// Copyright 2015-2020 Parity Technologies (UK) Ltd. +// This file is part of OpenEthereum. + +// OpenEthereum 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. + +// OpenEthereum 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 OpenEthereum. If not, see . + +//! RPC interface. + +use std::collections::BTreeMap; + +use jsonrpc_core::Result; +use jsonrpc_derive::rpc; + +/// RPC Interface. +#[rpc(server)] +pub trait Rpc { + /// Returns supported modules for Geth 1.3.6 + /// @ignore + #[rpc(name = "modules")] + fn modules(&self) -> Result>; + + /// Returns supported modules for Geth 1.4.0 + /// @ignore + #[rpc(name = "rpc_modules")] + fn rpc_modules(&self) -> Result>; +}