// Copyright 2022 Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Cumulus 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.
// Cumulus 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 Cumulus. If not, see .
use futures::channel::mpsc::Receiver;
use jsonrpsee::{core::params::ArrayParams, rpc_params};
use parity_scale_codec::{Decode, Encode};
use serde::de::DeserializeOwned;
pub use url::Url;
use sc_client_api::StorageData;
use sc_rpc_api::{state::ReadProof, system::Health};
use sc_service::TaskManager;
use sp_api::RuntimeVersion;
use sp_consensus_babe::Epoch;
use sp_core::sp_std::collections::btree_map::BTreeMap;
use sp_storage::StorageKey;
use cumulus_primitives_core::{
relay_chain::{
slashing, BlockNumber, CandidateCommitments, CandidateEvent, CandidateHash,
CommittedCandidateReceipt, CoreState, DisputeState, ExecutorParams, GroupRotationInfo,
Hash as RelayHash, Header as RelayHeader, InboundHrmpMessage, OccupiedCoreAssumption,
PvfCheckStatement, ScrapedOnChainVotes, SessionIndex, SessionInfo, ValidationCode,
ValidationCodeHash, ValidatorId, ValidatorIndex, ValidatorSignature,
},
InboundDownwardMessage, ParaId, PersistedValidationData,
};
use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult};
use crate::reconnecting_ws_client::ReconnectingWsClient;
const LOG_TARGET: &str = "relay-chain-rpc-client";
/// Client that maps RPC methods and deserializes results
#[derive(Clone)]
pub struct RelayChainRpcClient {
/// Websocket client to make calls
ws_client: ReconnectingWsClient,
}
/// Entry point to create [`RelayChainRpcClient`] and start a worker that distributes notifications.
pub async fn create_client_and_start_worker(
urls: Vec,
task_manager: &mut TaskManager,
) -> RelayChainResult {
let ws_client = ReconnectingWsClient::new(urls, task_manager).await?;
let client = RelayChainRpcClient::new(ws_client).await?;
Ok(client)
}
impl RelayChainRpcClient {
/// Initialize new RPC Client.
async fn new(ws_client: ReconnectingWsClient) -> RelayChainResult {
let client = RelayChainRpcClient { ws_client };
Ok(client)
}
/// Call a call to `state_call` rpc method.
pub async fn call_remote_runtime_function(
&self,
method_name: &str,
hash: RelayHash,
payload: Option,
) -> RelayChainResult {
let payload_bytes =
payload.map_or(sp_core::Bytes(Vec::new()), |v| sp_core::Bytes(v.encode()));
let params = rpc_params! {
method_name,
payload_bytes,
hash
};
let res = self
.request_tracing::("state_call", params, |err| {
tracing::trace!(
target: LOG_TARGET,
%method_name,
%hash,
error = %err,
"Error during call to 'state_call'.",
);
})
.await?;
Decode::decode(&mut &*res.0).map_err(Into::into)
}
/// Perform RPC request
async fn request<'a, R>(
&self,
method: &'a str,
params: ArrayParams,
) -> Result
where
R: DeserializeOwned + std::fmt::Debug,
{
self.request_tracing(
method,
params,
|e| tracing::trace!(target:LOG_TARGET, error = %e, %method, "Unable to complete RPC request"),
)
.await
}
/// Perform RPC request
async fn request_tracing<'a, R, OR>(
&self,
method: &'a str,
params: ArrayParams,
trace_error: OR,
) -> Result
where
R: DeserializeOwned + std::fmt::Debug,
OR: Fn(&RelayChainError),
{
self.ws_client.request(method, params).await.map_err(|err| {
trace_error(&err);
RelayChainError::RpcCallError(method.to_string())
})
}
/// Returns information regarding the current epoch.
pub async fn babe_api_current_epoch(&self, at: RelayHash) -> Result {
self.call_remote_runtime_function("BabeApi_current_epoch", at, None::<()>).await
}
/// Scrape dispute relevant from on-chain, backing votes and resolved disputes.
pub async fn parachain_host_on_chain_votes(
&self,
at: RelayHash,
) -> Result