From 76f297da1219b58581765e0a4cb17fea39ce16be Mon Sep 17 00:00:00 2001 From: PG Herveou <pgherveou@gmail.com> Date: Tue, 5 Nov 2024 15:41:06 +0100 Subject: [PATCH] [eth-rpc] proxy /health (#6360) make the eth-rpc proxy /health and /health/readiness from the proxied substrate chain see #4802 --------- Co-authored-by: GitHub Action <action@github.com> --- Cargo.lock | 1 + prdoc/pr_6360.prdoc | 9 ++++ substrate/frame/revive/rpc/Cargo.toml | 1 + substrate/frame/revive/rpc/src/cli.rs | 15 ++++-- substrate/frame/revive/rpc/src/client.rs | 9 +++- substrate/frame/revive/rpc/src/lib.rs | 3 ++ substrate/frame/revive/rpc/src/rpc_health.rs | 50 ++++++++++++++++++++ 7 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 prdoc/pr_6360.prdoc create mode 100644 substrate/frame/revive/rpc/src/rpc_health.rs diff --git a/Cargo.lock b/Cargo.lock index 6703a0250de..a8e7d7d4cdd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12562,6 +12562,7 @@ dependencies = [ "rlp 0.6.1", "sc-cli", "sc-rpc", + "sc-rpc-api", "sc-service", "scale-info", "secp256k1", diff --git a/prdoc/pr_6360.prdoc b/prdoc/pr_6360.prdoc new file mode 100644 index 00000000000..270af29e37a --- /dev/null +++ b/prdoc/pr_6360.prdoc @@ -0,0 +1,9 @@ +title: '[eth-rpc] proxy /health' +doc: +- audience: Runtime Dev + description: |- + make the eth-rpc proxy /health and /health/readiness from the proxied substrate chain + see #4802 +crates: +- name: pallet-revive-eth-rpc + bump: minor diff --git a/substrate/frame/revive/rpc/Cargo.toml b/substrate/frame/revive/rpc/Cargo.toml index 56db91f920f..8bf93024024 100644 --- a/substrate/frame/revive/rpc/Cargo.toml +++ b/substrate/frame/revive/rpc/Cargo.toml @@ -56,6 +56,7 @@ sp-core = { workspace = true, default-features = true } sp-weights = { workspace = true, default-features = true } sp-runtime = { workspace = true, default-features = true } sc-rpc = { workspace = true, default-features = true } +sc-rpc-api = { workspace = true, default-features = true } sc-cli = { workspace = true, default-features = true } sc-service = { workspace = true, default-features = true } prometheus-endpoint = { workspace = true, default-features = true } diff --git a/substrate/frame/revive/rpc/src/cli.rs b/substrate/frame/revive/rpc/src/cli.rs index fcb84e6b54b..c0f81fcafd7 100644 --- a/substrate/frame/revive/rpc/src/cli.rs +++ b/substrate/frame/revive/rpc/src/cli.rs @@ -15,7 +15,10 @@ // See the License for the specific language governing permissions and // limitations under the License. //! The Ethereum JSON-RPC server. -use crate::{client::Client, EthRpcServer, EthRpcServerImpl}; +use crate::{ + client::Client, EthRpcServer, EthRpcServerImpl, SystemHealthRpcServer, + SystemHealthRpcServerImpl, +}; use clap::Parser; use futures::{pin_mut, FutureExt}; use jsonrpsee::server::RpcModule; @@ -118,7 +121,10 @@ pub fn run(cmd: CliCommand) -> anyhow::Result<()> { match tokio_handle.block_on(signals.try_until_signal(fut)) { Ok(Ok(client)) => rpc_module(is_dev, client), - Ok(Err(err)) => Err(sc_service::Error::Application(err.into())), + Ok(Err(err)) => { + log::error!("Error connecting to the node at {node_rpc_url}: {err}"); + Err(sc_service::Error::Application(err.into())) + }, Err(_) => Err(sc_service::Error::Application("Client connection interrupted".into())), } }; @@ -142,11 +148,14 @@ pub fn run(cmd: CliCommand) -> anyhow::Result<()> { /// Create the JSON-RPC module. fn rpc_module(is_dev: bool, client: Client) -> Result<RpcModule<()>, sc_service::Error> { - let eth_api = EthRpcServerImpl::new(client) + let eth_api = EthRpcServerImpl::new(client.clone()) .with_accounts(if is_dev { vec![crate::Account::default()] } else { vec![] }) .into_rpc(); + let health_api = SystemHealthRpcServerImpl::new(client).into_rpc(); + let mut module = RpcModule::new(()); module.merge(eth_api).map_err(|e| sc_service::Error::Application(e.into()))?; + module.merge(health_api).map_err(|e| sc_service::Error::Application(e.into()))?; Ok(module) } diff --git a/substrate/frame/revive/rpc/src/client.rs b/substrate/frame/revive/rpc/src/client.rs index ba93d0af62a..a0552189f44 100644 --- a/substrate/frame/revive/rpc/src/client.rs +++ b/substrate/frame/revive/rpc/src/client.rs @@ -44,7 +44,7 @@ use std::{ }; use subxt::{ backend::{ - legacy::LegacyRpcMethods, + legacy::{rpc_methods::SystemHealth, LegacyRpcMethods}, rpc::{ reconnecting_rpc_client::{Client as ReconnectingRpcClient, ExponentialBackoff}, RpcClient, @@ -192,6 +192,7 @@ impl<const N: usize> BlockCache<N> { } /// A client connect to a node and maintains a cache of the last `CACHE_SIZE` blocks. +#[derive(Clone)] pub struct Client { /// The inner state of the client. inner: Arc<ClientInner>, @@ -555,6 +556,12 @@ impl Client { cache.tx_hashes_by_block_and_index.get(block_hash).map(|v| v.len()) } + /// Get the system health. + pub async fn system_health(&self) -> Result<SystemHealth, ClientError> { + let health = self.inner.rpc.system_health().await?; + Ok(health) + } + /// Get the balance of the given address. pub async fn balance( &self, diff --git a/substrate/frame/revive/rpc/src/lib.rs b/substrate/frame/revive/rpc/src/lib.rs index a6d47063ef9..88a3cb64178 100644 --- a/substrate/frame/revive/rpc/src/lib.rs +++ b/substrate/frame/revive/rpc/src/lib.rs @@ -35,6 +35,9 @@ pub mod subxt_client; #[cfg(test)] mod tests; +mod rpc_health; +pub use rpc_health::*; + mod rpc_methods_gen; pub use rpc_methods_gen::*; diff --git a/substrate/frame/revive/rpc/src/rpc_health.rs b/substrate/frame/revive/rpc/src/rpc_health.rs new file mode 100644 index 00000000000..f94d4b82a80 --- /dev/null +++ b/substrate/frame/revive/rpc/src/rpc_health.rs @@ -0,0 +1,50 @@ +// This file is part of Substrate. + +// Copyright (C) Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//! Heatlh JSON-RPC methods. + +use super::*; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use sc_rpc_api::system::helpers::Health; + +#[rpc(server, client)] +pub trait SystemHealthRpc { + /// Proxy the substrate chain system_health RPC call. + #[method(name = "system_health")] + async fn system_health(&self) -> RpcResult<Health>; +} + +pub struct SystemHealthRpcServerImpl { + client: client::Client, +} + +impl SystemHealthRpcServerImpl { + pub fn new(client: client::Client) -> Self { + Self { client } + } +} + +#[async_trait] +impl SystemHealthRpcServer for SystemHealthRpcServerImpl { + async fn system_health(&self) -> RpcResult<Health> { + let health = self.client.system_health().await?; + Ok(Health { + peers: health.peers, + is_syncing: health.is_syncing, + should_have_peers: health.should_have_peers, + }) + } +} -- GitLab