mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-22 21:55:45 +00:00
Allow to expose a subset of unsafe RPCs (#5233)
* sc-cli: Use type-safe constructors for RPC/Prometheus interfaces * service: Simplify rpc handler creation Could probably be further simplifies once [this][commit] lands. [commit]: https://github.com/paritytech/jsonrpc/commit/20485387ed06a48f1a70bf4d609a7cde6cf0accf * service: Streamline some HTTP & WS server start logic * client: Introduce a simple RPC policy mechanism * rpc/system: Check unsafe RPCs * rpc/offchain: Check unsafe RPCs * rpc/author: Check unsafe RPCs
This commit is contained in:
@@ -279,6 +279,12 @@ macro_rules! substrate_cli_subcommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn unsafe_rpc_expose(&self) -> $crate::Result<bool> {
|
||||||
|
match self {
|
||||||
|
$($enum::$variant(cmd) => cmd.unsafe_rpc_expose()),*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn rpc_ws_max_connections(&self) -> $crate::Result<::std::option::Option<usize>> {
|
fn rpc_ws_max_connections(&self) -> $crate::Result<::std::option::Option<usize>> {
|
||||||
match self {
|
match self {
|
||||||
$($enum::$variant(cmd) => cmd.rpc_ws_max_connections()),*
|
$($enum::$variant(cmd) => cmd.rpc_ws_max_connections()),*
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ use sc_service::{
|
|||||||
ChainSpec, Role,
|
ChainSpec, Role,
|
||||||
};
|
};
|
||||||
use sc_telemetry::TelemetryEndpoints;
|
use sc_telemetry::TelemetryEndpoints;
|
||||||
use std::net::SocketAddr;
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use structopt::{clap::arg_enum, StructOpt};
|
use structopt::{clap::arg_enum, StructOpt};
|
||||||
|
|
||||||
arg_enum! {
|
arg_enum! {
|
||||||
@@ -93,6 +93,14 @@ pub struct RunCmd {
|
|||||||
#[structopt(long = "unsafe-rpc-external")]
|
#[structopt(long = "unsafe-rpc-external")]
|
||||||
pub unsafe_rpc_external: bool,
|
pub unsafe_rpc_external: bool,
|
||||||
|
|
||||||
|
/// Don't deny potentially unsafe RPCs when listening on external interfaces.
|
||||||
|
///
|
||||||
|
/// Default is false. This allows exposing RPC methods publicly (same as `--unsafe-{rpc,ws}-external` )
|
||||||
|
/// but will allow doing so even on validator nodes, which is prohibited by default.
|
||||||
|
/// Please do this if you know what you're doing.
|
||||||
|
#[structopt(long = "unsafe-rpc-expose")]
|
||||||
|
pub unsafe_rpc_expose: bool,
|
||||||
|
|
||||||
/// Listen to all Websocket interfaces.
|
/// Listen to all Websocket interfaces.
|
||||||
///
|
///
|
||||||
/// Default is local. Note: not all RPC methods are safe to be exposed publicly. Use an RPC proxy
|
/// Default is local. Note: not all RPC methods are safe to be exposed publicly. Use an RPC proxy
|
||||||
@@ -361,22 +369,19 @@ impl CliConfiguration for RunCmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn prometheus_config(&self) -> Result<Option<PrometheusConfig>> {
|
fn prometheus_config(&self) -> Result<Option<PrometheusConfig>> {
|
||||||
if self.no_prometheus {
|
Ok(if self.no_prometheus {
|
||||||
Ok(None)
|
None
|
||||||
} else {
|
} else {
|
||||||
let prometheus_interface: &str = if self.prometheus_external {
|
let interface = if self.prometheus_external {
|
||||||
"0.0.0.0"
|
Ipv4Addr::UNSPECIFIED
|
||||||
} else {
|
} else {
|
||||||
"127.0.0.1"
|
Ipv4Addr::LOCALHOST
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Some(PrometheusConfig::new_with_default_registry(
|
Some(PrometheusConfig::new_with_default_registry(
|
||||||
parse_address(
|
SocketAddr::new(interface.into(), self.prometheus_port.unwrap_or(9615))
|
||||||
&format!("{}:{}", prometheus_interface, 9615),
|
))
|
||||||
self.prometheus_port,
|
})
|
||||||
)?,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disable_grandpa(&self) -> Result<bool> {
|
fn disable_grandpa(&self) -> Result<bool> {
|
||||||
@@ -409,23 +414,29 @@ impl CliConfiguration for RunCmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rpc_http(&self) -> Result<Option<SocketAddr>> {
|
fn rpc_http(&self) -> Result<Option<SocketAddr>> {
|
||||||
let rpc_interface: &str =
|
let interface = rpc_interface(
|
||||||
interface_str(self.rpc_external, self.unsafe_rpc_external, self.validator)?;
|
self.rpc_external,
|
||||||
|
self.unsafe_rpc_external,
|
||||||
|
self.unsafe_rpc_expose,
|
||||||
|
self.validator
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(Some(parse_address(
|
Ok(Some(SocketAddr::new(interface, self.rpc_port.unwrap_or(9933))))
|
||||||
&format!("{}:{}", rpc_interface, 9933),
|
|
||||||
self.rpc_port,
|
|
||||||
)?))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rpc_ws(&self) -> Result<Option<SocketAddr>> {
|
fn rpc_ws(&self) -> Result<Option<SocketAddr>> {
|
||||||
let ws_interface: &str =
|
let interface = rpc_interface(
|
||||||
interface_str(self.ws_external, self.unsafe_ws_external, self.validator)?;
|
self.ws_external,
|
||||||
|
self.unsafe_ws_external,
|
||||||
|
self.unsafe_rpc_expose,
|
||||||
|
self.validator
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(Some(parse_address(
|
Ok(Some(SocketAddr::new(interface, self.ws_port.unwrap_or(9944))))
|
||||||
&format!("{}:{}", ws_interface, 9944),
|
}
|
||||||
self.ws_port,
|
|
||||||
)?))
|
fn unsafe_rpc_expose(&self) -> Result<bool> {
|
||||||
|
Ok(self.unsafe_rpc_expose)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn offchain_worker(&self, role: &Role) -> Result<bool> {
|
fn offchain_worker(&self, role: &Role) -> Result<bool> {
|
||||||
@@ -468,23 +479,13 @@ pub fn is_node_name_valid(_name: &str) -> std::result::Result<(), &str> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_address(address: &str, port: Option<u16>) -> std::result::Result<SocketAddr, String> {
|
fn rpc_interface(
|
||||||
let mut address: SocketAddr = address
|
|
||||||
.parse()
|
|
||||||
.map_err(|_| format!("Invalid address: {}", address))?;
|
|
||||||
if let Some(port) = port {
|
|
||||||
address.set_port(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(address)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn interface_str(
|
|
||||||
is_external: bool,
|
is_external: bool,
|
||||||
is_unsafe_external: bool,
|
is_unsafe_external: bool,
|
||||||
|
is_unsafe_rpc_expose: bool,
|
||||||
is_validator: bool,
|
is_validator: bool,
|
||||||
) -> Result<&'static str> {
|
) -> Result<IpAddr> {
|
||||||
if is_external && is_validator {
|
if is_external && is_validator && !is_unsafe_rpc_expose {
|
||||||
return Err(Error::Input(
|
return Err(Error::Input(
|
||||||
"--rpc-external and --ws-external options shouldn't be \
|
"--rpc-external and --ws-external options shouldn't be \
|
||||||
used if the node is running as a validator. Use `--unsafe-rpc-external` if you understand \
|
used if the node is running as a validator. Use `--unsafe-rpc-external` if you understand \
|
||||||
@@ -499,9 +500,9 @@ fn interface_str(
|
|||||||
available set of RPC methods."
|
available set of RPC methods."
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok("0.0.0.0")
|
Ok(Ipv4Addr::UNSPECIFIED.into())
|
||||||
} else {
|
} else {
|
||||||
Ok("127.0.0.1")
|
Ok(Ipv4Addr::LOCALHOST.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -249,6 +249,13 @@ pub trait CliConfiguration: Sized {
|
|||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `Ok(true) if potentially unsafe RPC is to be exposed.
|
||||||
|
///
|
||||||
|
/// By default this is `false`.
|
||||||
|
fn unsafe_rpc_expose(&self) -> Result<bool> {
|
||||||
|
Ok(Default::default())
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the RPC websockets maximum connections (`None` if unlimited).
|
/// Get the RPC websockets maximum connections (`None` if unlimited).
|
||||||
///
|
///
|
||||||
/// By default this is `None`.
|
/// By default this is `None`.
|
||||||
@@ -419,6 +426,7 @@ pub trait CliConfiguration: Sized {
|
|||||||
execution_strategies: self.execution_strategies(is_dev)?,
|
execution_strategies: self.execution_strategies(is_dev)?,
|
||||||
rpc_http: self.rpc_http()?,
|
rpc_http: self.rpc_http()?,
|
||||||
rpc_ws: self.rpc_ws()?,
|
rpc_ws: self.rpc_ws()?,
|
||||||
|
unsafe_rpc_expose: self.unsafe_rpc_expose()?,
|
||||||
rpc_ws_max_connections: self.rpc_ws_max_connections()?,
|
rpc_ws_max_connections: self.rpc_ws_max_connections()?,
|
||||||
rpc_cors: self.rpc_cors(is_dev)?,
|
rpc_cors: self.rpc_cors(is_dev)?,
|
||||||
prometheus_config: self.prometheus_config()?,
|
prometheus_config: self.prometheus_config()?,
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ pub enum Error {
|
|||||||
/// Invalid session keys encoding.
|
/// Invalid session keys encoding.
|
||||||
#[display(fmt="Session keys are not encoded correctly")]
|
#[display(fmt="Session keys are not encoded correctly")]
|
||||||
InvalidSessionKeys,
|
InvalidSessionKeys,
|
||||||
|
/// Call to an unsafe RPC was denied.
|
||||||
|
UnsafeRpcCalled(crate::policy::UnsafeRpcError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Error {
|
impl std::error::Error for Error {
|
||||||
@@ -65,6 +67,7 @@ impl std::error::Error for Error {
|
|||||||
Error::Client(ref err) => Some(&**err),
|
Error::Client(ref err) => Some(&**err),
|
||||||
Error::Pool(ref err) => Some(err),
|
Error::Pool(ref err) => Some(err),
|
||||||
Error::Verification(ref err) => Some(&**err),
|
Error::Verification(ref err) => Some(&**err),
|
||||||
|
Error::UnsafeRpcCalled(ref err) => Some(err),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,6 +155,7 @@ impl From<Error> for rpc::Error {
|
|||||||
request to insert the key successfully.".into()
|
request to insert the key successfully.".into()
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
Error::UnsafeRpcCalled(e) => e.into(),
|
||||||
e => errors::internal(e),
|
e => errors::internal(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,13 @@
|
|||||||
|
|
||||||
mod errors;
|
mod errors;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
|
mod policy;
|
||||||
mod subscriptions;
|
mod subscriptions;
|
||||||
|
|
||||||
pub use jsonrpc_core::IoHandlerExtension as RpcExtension;
|
pub use jsonrpc_core::IoHandlerExtension as RpcExtension;
|
||||||
pub use subscriptions::{Subscriptions, TaskExecutor};
|
pub use subscriptions::{Subscriptions, TaskExecutor};
|
||||||
pub use helpers::Receiver;
|
pub use helpers::Receiver;
|
||||||
|
pub use policy::DenyUnsafe;
|
||||||
|
|
||||||
pub mod author;
|
pub mod author;
|
||||||
pub mod chain;
|
pub mod chain;
|
||||||
|
|||||||
@@ -27,11 +27,16 @@ pub enum Error {
|
|||||||
/// Unavailable storage kind error.
|
/// Unavailable storage kind error.
|
||||||
#[display(fmt="This storage kind is not available yet.")]
|
#[display(fmt="This storage kind is not available yet.")]
|
||||||
UnavailableStorageKind,
|
UnavailableStorageKind,
|
||||||
|
/// Call to an unsafe RPC was denied.
|
||||||
|
UnsafeRpcCalled(crate::policy::UnsafeRpcError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::error::Error for Error {
|
impl std::error::Error for Error {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
None
|
match self {
|
||||||
|
Self::UnsafeRpcCalled(err) => Some(err),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +51,7 @@ impl From<Error> for rpc::Error {
|
|||||||
message: "This storage kind is not available yet" .into(),
|
message: "This storage kind is not available yet" .into(),
|
||||||
data: None,
|
data: None,
|
||||||
},
|
},
|
||||||
|
Error::UnsafeRpcCalled(e) => e.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
// Copyright 2020 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Substrate.
|
||||||
|
|
||||||
|
// Substrate 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.
|
||||||
|
|
||||||
|
// Substrate 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 Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Policy-related types.
|
||||||
|
//!
|
||||||
|
//! Contains a `DenyUnsafe` type that can be used to deny potentially unsafe
|
||||||
|
//! RPC when accessed externally.
|
||||||
|
|
||||||
|
use jsonrpc_core as rpc;
|
||||||
|
|
||||||
|
/// Signifies whether a potentially unsafe RPC should be denied.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum DenyUnsafe {
|
||||||
|
/// Denies only potentially unsafe RPCs.
|
||||||
|
Yes,
|
||||||
|
/// Allows calling every RPCs.
|
||||||
|
No
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DenyUnsafe {
|
||||||
|
/// Returns `Ok(())` if the RPCs considered unsafe are safe to call,
|
||||||
|
/// otherwise returns `Err(UnsafeRpcError)`.
|
||||||
|
pub fn check_if_safe(self) -> Result<(), UnsafeRpcError> {
|
||||||
|
match self {
|
||||||
|
DenyUnsafe::Yes => Err(UnsafeRpcError),
|
||||||
|
DenyUnsafe::No => Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Signifies whether an RPC considered unsafe is denied to be called externally.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UnsafeRpcError;
|
||||||
|
|
||||||
|
impl std::fmt::Display for UnsafeRpcError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "RPC call is unsafe to be called externally")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for UnsafeRpcError {}
|
||||||
|
|
||||||
|
impl From<UnsafeRpcError> for rpc::Error {
|
||||||
|
fn from(_: UnsafeRpcError) -> rpc::Error {
|
||||||
|
rpc::Error::method_not_found()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,14 +72,16 @@ pub trait SystemApi<Hash, Number> {
|
|||||||
|
|
||||||
/// Returns currently connected peers
|
/// Returns currently connected peers
|
||||||
#[rpc(name = "system_peers", returns = "Vec<PeerInfo<Hash, Number>>")]
|
#[rpc(name = "system_peers", returns = "Vec<PeerInfo<Hash, Number>>")]
|
||||||
fn system_peers(&self) -> Receiver<Vec<PeerInfo<Hash, Number>>>;
|
fn system_peers(&self)
|
||||||
|
-> Compat<BoxFuture<'static, jsonrpc_core::Result<Vec<PeerInfo<Hash, Number>>>>>;
|
||||||
|
|
||||||
/// Returns current state of the network.
|
/// Returns current state of the network.
|
||||||
///
|
///
|
||||||
/// **Warning**: This API is not stable.
|
/// **Warning**: This API is not stable.
|
||||||
// TODO: make this stable and move structs https://github.com/paritytech/substrate/issues/1890
|
// TODO: make this stable and move structs https://github.com/paritytech/substrate/issues/1890
|
||||||
#[rpc(name = "system_networkState", returns = "jsonrpc_core::Value")]
|
#[rpc(name = "system_networkState", returns = "jsonrpc_core::Value")]
|
||||||
fn system_network_state(&self) -> Receiver<jsonrpc_core::Value>;
|
fn system_network_state(&self)
|
||||||
|
-> Compat<BoxFuture<'static, jsonrpc_core::Result<jsonrpc_core::Value>>>;
|
||||||
|
|
||||||
/// Adds a reserved peer. Returns the empty string or an error. The string
|
/// Adds a reserved peer. Returns the empty string or an error. The string
|
||||||
/// parameter should encode a `p2p` multiaddr.
|
/// parameter should encode a `p2p` multiaddr.
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use rpc::futures::{
|
|||||||
};
|
};
|
||||||
use futures::{StreamExt as _, compat::Compat};
|
use futures::{StreamExt as _, compat::Compat};
|
||||||
use futures::future::{ready, FutureExt, TryFutureExt};
|
use futures::future::{ready, FutureExt, TryFutureExt};
|
||||||
use sc_rpc_api::Subscriptions;
|
use sc_rpc_api::{DenyUnsafe, Subscriptions};
|
||||||
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
|
use jsonrpc_pubsub::{typed::Subscriber, SubscriptionId};
|
||||||
use codec::{Encode, Decode};
|
use codec::{Encode, Decode};
|
||||||
use sp_core::{Bytes, traits::BareCryptoStorePtr};
|
use sp_core::{Bytes, traits::BareCryptoStorePtr};
|
||||||
@@ -56,6 +56,8 @@ pub struct Author<P, Client> {
|
|||||||
subscriptions: Subscriptions,
|
subscriptions: Subscriptions,
|
||||||
/// The key store.
|
/// The key store.
|
||||||
keystore: BareCryptoStorePtr,
|
keystore: BareCryptoStorePtr,
|
||||||
|
/// Whether to deny unsafe calls
|
||||||
|
deny_unsafe: DenyUnsafe,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, Client> Author<P, Client> {
|
impl<P, Client> Author<P, Client> {
|
||||||
@@ -65,12 +67,14 @@ impl<P, Client> Author<P, Client> {
|
|||||||
pool: Arc<P>,
|
pool: Arc<P>,
|
||||||
subscriptions: Subscriptions,
|
subscriptions: Subscriptions,
|
||||||
keystore: BareCryptoStorePtr,
|
keystore: BareCryptoStorePtr,
|
||||||
|
deny_unsafe: DenyUnsafe,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Author {
|
Author {
|
||||||
client,
|
client,
|
||||||
pool,
|
pool,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
keystore,
|
keystore,
|
||||||
|
deny_unsafe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,6 +101,8 @@ impl<P, Client> AuthorApi<TxHash<P>, BlockHash<P>> for Author<P, Client>
|
|||||||
suri: String,
|
suri: String,
|
||||||
public: Bytes,
|
public: Bytes,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
self.deny_unsafe.check_if_safe()?;
|
||||||
|
|
||||||
let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?;
|
let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?;
|
||||||
let mut keystore = self.keystore.write();
|
let mut keystore = self.keystore.write();
|
||||||
keystore.insert_unknown(key_type, &suri, &public[..])
|
keystore.insert_unknown(key_type, &suri, &public[..])
|
||||||
@@ -105,6 +111,8 @@ impl<P, Client> AuthorApi<TxHash<P>, BlockHash<P>> for Author<P, Client>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn rotate_keys(&self) -> Result<Bytes> {
|
fn rotate_keys(&self) -> Result<Bytes> {
|
||||||
|
self.deny_unsafe.check_if_safe()?;
|
||||||
|
|
||||||
let best_block_hash = self.client.info().best_hash;
|
let best_block_hash = self.client.info().best_hash;
|
||||||
self.client.runtime_api().generate_session_keys(
|
self.client.runtime_api().generate_session_keys(
|
||||||
&generic::BlockId::Hash(best_block_hash),
|
&generic::BlockId::Hash(best_block_hash),
|
||||||
@@ -113,6 +121,8 @@ impl<P, Client> AuthorApi<TxHash<P>, BlockHash<P>> for Author<P, Client>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn has_session_keys(&self, session_keys: Bytes) -> Result<bool> {
|
fn has_session_keys(&self, session_keys: Bytes) -> Result<bool> {
|
||||||
|
self.deny_unsafe.check_if_safe()?;
|
||||||
|
|
||||||
let best_block_hash = self.client.info().best_hash;
|
let best_block_hash = self.client.info().best_hash;
|
||||||
let keys = self.client.runtime_api().decode_session_keys(
|
let keys = self.client.runtime_api().decode_session_keys(
|
||||||
&generic::BlockId::Hash(best_block_hash),
|
&generic::BlockId::Hash(best_block_hash),
|
||||||
@@ -124,6 +134,8 @@ impl<P, Client> AuthorApi<TxHash<P>, BlockHash<P>> for Author<P, Client>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn has_key(&self, public_key: Bytes, key_type: String) -> Result<bool> {
|
fn has_key(&self, public_key: Bytes, key_type: String) -> Result<bool> {
|
||||||
|
self.deny_unsafe.check_if_safe()?;
|
||||||
|
|
||||||
let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?;
|
let key_type = key_type.as_str().try_into().map_err(|_| Error::BadKeyType)?;
|
||||||
Ok(self.keystore.read().has_keys(&[(public_key.to_vec(), key_type)]))
|
Ok(self.keystore.read().has_keys(&[(public_key.to_vec(), key_type)]))
|
||||||
}
|
}
|
||||||
@@ -151,6 +163,8 @@ impl<P, Client> AuthorApi<TxHash<P>, BlockHash<P>> for Author<P, Client>
|
|||||||
&self,
|
&self,
|
||||||
bytes_or_hash: Vec<hash::ExtrinsicOrHash<TxHash<P>>>,
|
bytes_or_hash: Vec<hash::ExtrinsicOrHash<TxHash<P>>>,
|
||||||
) -> Result<Vec<TxHash<P>>> {
|
) -> Result<Vec<TxHash<P>>> {
|
||||||
|
self.deny_unsafe.check_if_safe()?;
|
||||||
|
|
||||||
let hashes = bytes_or_hash.into_iter()
|
let hashes = bytes_or_hash.into_iter()
|
||||||
.map(|x| match x {
|
.map(|x| match x {
|
||||||
hash::ExtrinsicOrHash::Hash(h) => Ok(h),
|
hash::ExtrinsicOrHash::Hash(h) => Ok(h),
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ impl TestSetup {
|
|||||||
pool: self.pool.clone(),
|
pool: self.pool.clone(),
|
||||||
subscriptions: Subscriptions::new(Arc::new(self.runtime.executor())),
|
subscriptions: Subscriptions::new(Arc::new(self.runtime.executor())),
|
||||||
keystore: self.keystore.clone(),
|
keystore: self.keystore.clone(),
|
||||||
|
deny_unsafe: DenyUnsafe::No,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
mod metadata;
|
mod metadata;
|
||||||
|
|
||||||
pub use sc_rpc_api::Subscriptions;
|
pub use sc_rpc_api::{DenyUnsafe, Subscriptions};
|
||||||
pub use self::metadata::Metadata;
|
pub use self::metadata::Metadata;
|
||||||
pub use rpc::IoHandlerExtension as RpcExtension;
|
pub use rpc::IoHandlerExtension as RpcExtension;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ mod tests;
|
|||||||
|
|
||||||
/// Re-export the API for backward compatibility.
|
/// Re-export the API for backward compatibility.
|
||||||
pub use sc_rpc_api::offchain::*;
|
pub use sc_rpc_api::offchain::*;
|
||||||
|
use sc_rpc_api::DenyUnsafe;
|
||||||
use self::error::{Error, Result};
|
use self::error::{Error, Result};
|
||||||
use sp_core::{
|
use sp_core::{
|
||||||
Bytes,
|
Bytes,
|
||||||
@@ -34,13 +35,15 @@ use std::sync::Arc;
|
|||||||
pub struct Offchain<T: OffchainStorage> {
|
pub struct Offchain<T: OffchainStorage> {
|
||||||
/// Offchain storage
|
/// Offchain storage
|
||||||
storage: Arc<RwLock<T>>,
|
storage: Arc<RwLock<T>>,
|
||||||
|
deny_unsafe: DenyUnsafe,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: OffchainStorage> Offchain<T> {
|
impl<T: OffchainStorage> Offchain<T> {
|
||||||
/// Create new instance of Offchain API.
|
/// Create new instance of Offchain API.
|
||||||
pub fn new(storage: T) -> Self {
|
pub fn new(storage: T, deny_unsafe: DenyUnsafe) -> Self {
|
||||||
Offchain {
|
Offchain {
|
||||||
storage: Arc::new(RwLock::new(storage)),
|
storage: Arc::new(RwLock::new(storage)),
|
||||||
|
deny_unsafe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,6 +51,8 @@ impl<T: OffchainStorage> Offchain<T> {
|
|||||||
impl<T: OffchainStorage + 'static> OffchainApi for Offchain<T> {
|
impl<T: OffchainStorage + 'static> OffchainApi for Offchain<T> {
|
||||||
/// Set offchain local storage under given key and prefix.
|
/// Set offchain local storage under given key and prefix.
|
||||||
fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> Result<()> {
|
fn set_local_storage(&self, kind: StorageKind, key: Bytes, value: Bytes) -> Result<()> {
|
||||||
|
self.deny_unsafe.check_if_safe()?;
|
||||||
|
|
||||||
let prefix = match kind {
|
let prefix = match kind {
|
||||||
StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX,
|
StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX,
|
||||||
StorageKind::LOCAL => return Err(Error::UnavailableStorageKind),
|
StorageKind::LOCAL => return Err(Error::UnavailableStorageKind),
|
||||||
@@ -58,6 +63,8 @@ impl<T: OffchainStorage + 'static> OffchainApi for Offchain<T> {
|
|||||||
|
|
||||||
/// Get offchain local storage under given key and prefix.
|
/// Get offchain local storage under given key and prefix.
|
||||||
fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> Result<Option<Bytes>> {
|
fn get_local_storage(&self, kind: StorageKind, key: Bytes) -> Result<Option<Bytes>> {
|
||||||
|
self.deny_unsafe.check_if_safe()?;
|
||||||
|
|
||||||
let prefix = match kind {
|
let prefix = match kind {
|
||||||
StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX,
|
StorageKind::PERSISTENT => sp_offchain::STORAGE_PREFIX,
|
||||||
StorageKind::LOCAL => return Err(Error::UnavailableStorageKind),
|
StorageKind::LOCAL => return Err(Error::UnavailableStorageKind),
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use sp_core::{Bytes, offchain::storage::InMemOffchainStorage};
|
|||||||
#[test]
|
#[test]
|
||||||
fn local_storage_should_work() {
|
fn local_storage_should_work() {
|
||||||
let storage = InMemOffchainStorage::default();
|
let storage = InMemOffchainStorage::default();
|
||||||
let offchain = Offchain::new(storage);
|
let offchain = Offchain::new(storage, DenyUnsafe::No);
|
||||||
let key = Bytes(b"offchain_storage".to_vec());
|
let key = Bytes(b"offchain_storage".to_vec());
|
||||||
let value = Bytes(b"offchain_value".to_vec());
|
let value = Bytes(b"offchain_value".to_vec());
|
||||||
|
|
||||||
@@ -34,3 +34,20 @@ fn local_storage_should_work() {
|
|||||||
Ok(Some(ref v)) if *v == value
|
Ok(Some(ref v)) if *v == value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn offchain_calls_considered_unsafe() {
|
||||||
|
let storage = InMemOffchainStorage::default();
|
||||||
|
let offchain = Offchain::new(storage, DenyUnsafe::Yes);
|
||||||
|
let key = Bytes(b"offchain_storage".to_vec());
|
||||||
|
let value = Bytes(b"offchain_value".to_vec());
|
||||||
|
|
||||||
|
assert_matches!(
|
||||||
|
offchain.set_local_storage(StorageKind::PERSISTENT, key.clone(), value.clone()),
|
||||||
|
Err(Error::UnsafeRpcCalled(_))
|
||||||
|
);
|
||||||
|
assert_matches!(
|
||||||
|
offchain.get_local_storage(StorageKind::PERSISTENT, key),
|
||||||
|
Err(Error::UnsafeRpcCalled(_))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ mod tests;
|
|||||||
|
|
||||||
use futures::{future::BoxFuture, FutureExt, TryFutureExt};
|
use futures::{future::BoxFuture, FutureExt, TryFutureExt};
|
||||||
use futures::{channel::oneshot, compat::Compat};
|
use futures::{channel::oneshot, compat::Compat};
|
||||||
use sc_rpc_api::Receiver;
|
use sc_rpc_api::{DenyUnsafe, Receiver};
|
||||||
use sp_utils::mpsc::TracingUnboundedSender;
|
use sp_utils::mpsc::TracingUnboundedSender;
|
||||||
use sp_runtime::traits::{self, Header as HeaderT};
|
use sp_runtime::traits::{self, Header as HeaderT};
|
||||||
|
|
||||||
@@ -31,10 +31,19 @@ pub use sc_rpc_api::system::*;
|
|||||||
pub use self::helpers::{SystemInfo, Health, PeerInfo, NodeRole};
|
pub use self::helpers::{SystemInfo, Health, PeerInfo, NodeRole};
|
||||||
pub use self::gen_client::Client as SystemClient;
|
pub use self::gen_client::Client as SystemClient;
|
||||||
|
|
||||||
|
macro_rules! bail_if_unsafe {
|
||||||
|
($value: expr) => {
|
||||||
|
if let Err(err) = $value.check_if_safe() {
|
||||||
|
return async move { Err(err.into()) }.boxed().compat();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// System API implementation
|
/// System API implementation
|
||||||
pub struct System<B: traits::Block> {
|
pub struct System<B: traits::Block> {
|
||||||
info: SystemInfo,
|
info: SystemInfo,
|
||||||
send_back: TracingUnboundedSender<Request<B>>,
|
send_back: TracingUnboundedSender<Request<B>>,
|
||||||
|
deny_unsafe: DenyUnsafe,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request to be processed.
|
/// Request to be processed.
|
||||||
@@ -66,10 +75,12 @@ impl<B: traits::Block> System<B> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
info: SystemInfo,
|
info: SystemInfo,
|
||||||
send_back: TracingUnboundedSender<Request<B>>,
|
send_back: TracingUnboundedSender<Request<B>>,
|
||||||
|
deny_unsafe: DenyUnsafe,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
System {
|
System {
|
||||||
info,
|
info,
|
||||||
send_back,
|
send_back,
|
||||||
|
deny_unsafe,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,21 +124,37 @@ impl<B: traits::Block> SystemApi<B::Hash, <B::Header as HeaderT>::Number> for Sy
|
|||||||
Receiver(Compat::new(rx))
|
Receiver(Compat::new(rx))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn system_peers(&self) -> Receiver<Vec<PeerInfo<B::Hash, <B::Header as HeaderT>::Number>>> {
|
fn system_peers(&self)
|
||||||
|
-> Compat<BoxFuture<'static, rpc::Result<Vec<PeerInfo<B::Hash, <B::Header as HeaderT>::Number>>>>>
|
||||||
|
{
|
||||||
|
bail_if_unsafe!(self.deny_unsafe);
|
||||||
|
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let _ = self.send_back.unbounded_send(Request::Peers(tx));
|
let _ = self.send_back.unbounded_send(Request::Peers(tx));
|
||||||
Receiver(Compat::new(rx))
|
|
||||||
|
async move {
|
||||||
|
rx.await.map_err(|_| rpc::Error::internal_error())
|
||||||
|
}.boxed().compat()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn system_network_state(&self) -> Receiver<rpc::Value> {
|
fn system_network_state(&self)
|
||||||
|
-> Compat<BoxFuture<'static, rpc::Result<rpc::Value>>>
|
||||||
|
{
|
||||||
|
bail_if_unsafe!(self.deny_unsafe);
|
||||||
|
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let _ = self.send_back.unbounded_send(Request::NetworkState(tx));
|
let _ = self.send_back.unbounded_send(Request::NetworkState(tx));
|
||||||
Receiver(Compat::new(rx))
|
|
||||||
|
async move {
|
||||||
|
rx.await.map_err(|_| rpc::Error::internal_error())
|
||||||
|
}.boxed().compat()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn system_add_reserved_peer(&self, peer: String)
|
fn system_add_reserved_peer(&self, peer: String)
|
||||||
-> Compat<BoxFuture<'static, std::result::Result<(), rpc::Error>>>
|
-> Compat<BoxFuture<'static, std::result::Result<(), rpc::Error>>>
|
||||||
{
|
{
|
||||||
|
bail_if_unsafe!(self.deny_unsafe);
|
||||||
|
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let _ = self.send_back.unbounded_send(Request::NetworkAddReservedPeer(peer, tx));
|
let _ = self.send_back.unbounded_send(Request::NetworkAddReservedPeer(peer, tx));
|
||||||
async move {
|
async move {
|
||||||
@@ -142,6 +169,8 @@ impl<B: traits::Block> SystemApi<B::Hash, <B::Header as HeaderT>::Number> for Sy
|
|||||||
fn system_remove_reserved_peer(&self, peer: String)
|
fn system_remove_reserved_peer(&self, peer: String)
|
||||||
-> Compat<BoxFuture<'static, std::result::Result<(), rpc::Error>>>
|
-> Compat<BoxFuture<'static, std::result::Result<(), rpc::Error>>>
|
||||||
{
|
{
|
||||||
|
bail_if_unsafe!(self.deny_unsafe);
|
||||||
|
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
let _ = self.send_back.unbounded_send(Request::NetworkRemoveReservedPeer(peer, tx));
|
let _ = self.send_back.unbounded_send(Request::NetworkRemoveReservedPeer(peer, tx));
|
||||||
async move {
|
async move {
|
||||||
|
|||||||
@@ -109,13 +109,17 @@ fn api<T: Into<Option<Status>>>(sync: T) -> System<Block> {
|
|||||||
future::ready(())
|
future::ready(())
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
System::new(SystemInfo {
|
System::new(
|
||||||
impl_name: "testclient".into(),
|
SystemInfo {
|
||||||
impl_version: "0.2.0".into(),
|
impl_name: "testclient".into(),
|
||||||
chain_name: "testchain".into(),
|
impl_version: "0.2.0".into(),
|
||||||
properties: Default::default(),
|
chain_name: "testchain".into(),
|
||||||
chain_type: Default::default(),
|
properties: Default::default(),
|
||||||
}, tx)
|
chain_type: Default::default(),
|
||||||
|
},
|
||||||
|
tx,
|
||||||
|
sc_rpc_api::DenyUnsafe::No
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_receiver<T>(rx: Receiver<T>) -> T {
|
fn wait_receiver<T>(rx: Receiver<T>) -> T {
|
||||||
@@ -238,14 +242,19 @@ fn system_local_listen_addresses_works() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn system_peers() {
|
fn system_peers() {
|
||||||
|
let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();
|
||||||
|
|
||||||
let peer_id = PeerId::random();
|
let peer_id = PeerId::random();
|
||||||
|
let req = api(Status {
|
||||||
|
peer_id: peer_id.clone(),
|
||||||
|
peers: 1,
|
||||||
|
is_syncing: false,
|
||||||
|
is_dev: true,
|
||||||
|
}).system_peers();
|
||||||
|
let res = runtime.block_on(req).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
wait_receiver(api(Status {
|
res,
|
||||||
peer_id: peer_id.clone(),
|
|
||||||
peers: 1,
|
|
||||||
is_syncing: false,
|
|
||||||
is_dev: true,
|
|
||||||
}).system_peers()),
|
|
||||||
vec![PeerInfo {
|
vec![PeerInfo {
|
||||||
peer_id: peer_id.to_base58(),
|
peer_id: peer_id.to_base58(),
|
||||||
roles: "FULL".into(),
|
roles: "FULL".into(),
|
||||||
@@ -258,7 +267,10 @@ fn system_peers() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn system_network_state() {
|
fn system_network_state() {
|
||||||
let res = wait_receiver(api(None).system_network_state());
|
let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap();
|
||||||
|
let req = api(None).system_network_state();
|
||||||
|
let res = runtime.block_on(req).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
serde_json::from_value::<sc_network::network_state::NetworkState>(res).unwrap(),
|
serde_json::from_value::<sc_network::network_state::NetworkState>(res).unwrap(),
|
||||||
sc_network::network_state::NetworkState {
|
sc_network::network_state::NetworkState {
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ use sp_runtime::traits::{
|
|||||||
use sp_api::ProvideRuntimeApi;
|
use sp_api::ProvideRuntimeApi;
|
||||||
use sc_executor::{NativeExecutor, NativeExecutionDispatch};
|
use sc_executor::{NativeExecutor, NativeExecutionDispatch};
|
||||||
use std::{
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
io::{Read, Write, Seek},
|
io::{Read, Write, Seek},
|
||||||
marker::PhantomData, sync::Arc, pin::Pin
|
marker::PhantomData, sync::Arc, pin::Pin
|
||||||
};
|
};
|
||||||
@@ -1001,7 +1002,7 @@ ServiceBuilder<
|
|||||||
|
|
||||||
// RPC
|
// RPC
|
||||||
let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc");
|
let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc");
|
||||||
let gen_handler = || {
|
let gen_handler = |deny_unsafe: sc_rpc::DenyUnsafe| {
|
||||||
use sc_rpc::{chain, state, author, system, offchain};
|
use sc_rpc::{chain, state, author, system, offchain};
|
||||||
|
|
||||||
let system_info = sc_rpc::system::SystemInfo {
|
let system_info = sc_rpc::system::SystemInfo {
|
||||||
@@ -1043,32 +1044,31 @@ ServiceBuilder<
|
|||||||
transaction_pool.clone(),
|
transaction_pool.clone(),
|
||||||
subscriptions,
|
subscriptions,
|
||||||
keystore.clone(),
|
keystore.clone(),
|
||||||
|
deny_unsafe,
|
||||||
);
|
);
|
||||||
let system = system::System::new(system_info, system_rpc_tx.clone());
|
let system = system::System::new(system_info, system_rpc_tx.clone(), deny_unsafe);
|
||||||
|
|
||||||
match offchain_storage.clone() {
|
let maybe_offchain_rpc = offchain_storage.clone()
|
||||||
Some(storage) => {
|
.map(|storage| {
|
||||||
let offchain = sc_rpc::offchain::Offchain::new(storage);
|
let offchain = sc_rpc::offchain::Offchain::new(storage, deny_unsafe);
|
||||||
sc_rpc_server::rpc_handler((
|
// FIXME: Use plain Option (don't collect into HashMap) when we upgrade to jsonrpc 14.1
|
||||||
state::StateApi::to_delegate(state),
|
// https://github.com/paritytech/jsonrpc/commit/20485387ed06a48f1a70bf4d609a7cde6cf0accf
|
||||||
chain::ChainApi::to_delegate(chain),
|
let delegate = offchain::OffchainApi::to_delegate(offchain);
|
||||||
offchain::OffchainApi::to_delegate(offchain),
|
delegate.into_iter().collect::<HashMap<_, _>>()
|
||||||
author::AuthorApi::to_delegate(author),
|
}).unwrap_or_default();
|
||||||
system::SystemApi::to_delegate(system),
|
|
||||||
rpc_extensions.clone(),
|
sc_rpc_server::rpc_handler((
|
||||||
))
|
state::StateApi::to_delegate(state),
|
||||||
},
|
chain::ChainApi::to_delegate(chain),
|
||||||
None => sc_rpc_server::rpc_handler((
|
maybe_offchain_rpc,
|
||||||
state::StateApi::to_delegate(state),
|
author::AuthorApi::to_delegate(author),
|
||||||
chain::ChainApi::to_delegate(chain),
|
system::SystemApi::to_delegate(system),
|
||||||
author::AuthorApi::to_delegate(author),
|
rpc_extensions.clone(),
|
||||||
system::SystemApi::to_delegate(system),
|
))
|
||||||
rpc_extensions.clone(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let rpc_handlers = gen_handler();
|
|
||||||
let rpc = start_rpc_servers(&config, gen_handler)?;
|
let rpc = start_rpc_servers(&config, gen_handler)?;
|
||||||
|
// This is used internally, so don't restrict access to unsafe RPC
|
||||||
|
let rpc_handlers = gen_handler(sc_rpc::DenyUnsafe::No);
|
||||||
|
|
||||||
spawn_handle.spawn(
|
spawn_handle.spawn(
|
||||||
"network-worker",
|
"network-worker",
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ pub struct Configuration {
|
|||||||
pub wasm_method: WasmExecutionMethod,
|
pub wasm_method: WasmExecutionMethod,
|
||||||
/// Execution strategies.
|
/// Execution strategies.
|
||||||
pub execution_strategies: ExecutionStrategies,
|
pub execution_strategies: ExecutionStrategies,
|
||||||
|
/// Whether potentially unsafe RPC is considered safe to be exposed.
|
||||||
|
pub unsafe_rpc_expose: bool,
|
||||||
/// RPC over HTTP binding address. `None` if disabled.
|
/// RPC over HTTP binding address. `None` if disabled.
|
||||||
pub rpc_http: Option<SocketAddr>,
|
pub rpc_http: Option<SocketAddr>,
|
||||||
/// RPC over Websockets binding address. `None` if disabled.
|
/// RPC over Websockets binding address. `None` if disabled.
|
||||||
|
|||||||
@@ -511,7 +511,7 @@ mod waiting {
|
|||||||
|
|
||||||
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
|
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
|
||||||
#[cfg(not(target_os = "unknown"))]
|
#[cfg(not(target_os = "unknown"))]
|
||||||
fn start_rpc_servers<H: FnMut() -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
|
fn start_rpc_servers<H: FnMut(sc_rpc::DenyUnsafe) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
|
||||||
config: &Configuration,
|
config: &Configuration,
|
||||||
mut gen_handler: H
|
mut gen_handler: H
|
||||||
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {
|
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {
|
||||||
@@ -533,10 +533,23 @@ fn start_rpc_servers<H: FnMut() -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deny_unsafe(addr: &Option<SocketAddr>, unsafe_rpc_expose: bool) -> sc_rpc::DenyUnsafe {
|
||||||
|
let is_exposed_addr = addr.map(|x| x.ip().is_loopback()).unwrap_or(false);
|
||||||
|
if is_exposed_addr && !unsafe_rpc_expose {
|
||||||
|
sc_rpc::DenyUnsafe::Yes
|
||||||
|
} else {
|
||||||
|
sc_rpc::DenyUnsafe::No
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Box::new((
|
Ok(Box::new((
|
||||||
maybe_start_server(
|
maybe_start_server(
|
||||||
config.rpc_http,
|
config.rpc_http,
|
||||||
|address| sc_rpc_server::start_http(address, config.rpc_cors.as_ref(), gen_handler()),
|
|address| sc_rpc_server::start_http(
|
||||||
|
address,
|
||||||
|
config.rpc_cors.as_ref(),
|
||||||
|
gen_handler(deny_unsafe(&config.rpc_http, config.unsafe_rpc_expose)),
|
||||||
|
),
|
||||||
)?.map(|s| waiting::HttpServer(Some(s))),
|
)?.map(|s| waiting::HttpServer(Some(s))),
|
||||||
maybe_start_server(
|
maybe_start_server(
|
||||||
config.rpc_ws,
|
config.rpc_ws,
|
||||||
@@ -544,15 +557,15 @@ fn start_rpc_servers<H: FnMut() -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
|
|||||||
address,
|
address,
|
||||||
config.rpc_ws_max_connections,
|
config.rpc_ws_max_connections,
|
||||||
config.rpc_cors.as_ref(),
|
config.rpc_cors.as_ref(),
|
||||||
gen_handler(),
|
gen_handler(deny_unsafe(&config.rpc_ws, config.unsafe_rpc_expose)),
|
||||||
),
|
),
|
||||||
)?.map(|s| waiting::WsServer(Some(s))).map(Mutex::new),
|
)?.map(|s| waiting::WsServer(Some(s))),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
|
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
|
||||||
#[cfg(target_os = "unknown")]
|
#[cfg(target_os = "unknown")]
|
||||||
fn start_rpc_servers<H: FnMut() -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
|
fn start_rpc_servers<H: FnMut(sc_rpc::DenyUnsafe) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
|
||||||
_: &Configuration,
|
_: &Configuration,
|
||||||
_: H
|
_: H
|
||||||
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {
|
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
|
|||||||
chain_spec: Box::new((*spec).clone()),
|
chain_spec: Box::new((*spec).clone()),
|
||||||
wasm_method: sc_service::config::WasmExecutionMethod::Interpreted,
|
wasm_method: sc_service::config::WasmExecutionMethod::Interpreted,
|
||||||
execution_strategies: Default::default(),
|
execution_strategies: Default::default(),
|
||||||
|
unsafe_rpc_expose: false,
|
||||||
rpc_http: None,
|
rpc_http: None,
|
||||||
rpc_ws: None,
|
rpc_ws: None,
|
||||||
rpc_ws_max_connections: None,
|
rpc_ws_max_connections: None,
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ where
|
|||||||
rpc_cors: Default::default(),
|
rpc_cors: Default::default(),
|
||||||
rpc_http: Default::default(),
|
rpc_http: Default::default(),
|
||||||
rpc_ws: Default::default(),
|
rpc_ws: Default::default(),
|
||||||
|
unsafe_rpc_expose: false,
|
||||||
rpc_ws_max_connections: Default::default(),
|
rpc_ws_max_connections: Default::default(),
|
||||||
state_cache_child_ratio: Default::default(),
|
state_cache_child_ratio: Default::default(),
|
||||||
state_cache_size: Default::default(),
|
state_cache_size: Default::default(),
|
||||||
|
|||||||
Reference in New Issue
Block a user