Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to call arbitrary runtime apis using RelayChainInterface #5521

Merged
9 changes: 9 additions & 0 deletions cumulus/client/consensus/common/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,15 @@ impl RelayChainInterface for Relaychain {
async fn version(&self, _: PHash) -> RelayChainResult<RuntimeVersion> {
unimplemented!("Not needed for test")
}

async fn call_runtime_api(
&self,
_method_name: &'static str,
_hash: PHash,
_payload: &[u8],
) -> RelayChainResult<Vec<u8>> {
unimplemented!("Not needed for test")
}
}

fn sproof_with_best_parent(client: &Client) -> RelayStateSproofBuilder {
Expand Down
9 changes: 9 additions & 0 deletions cumulus/client/network/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,15 @@ impl RelayChainInterface for DummyRelayChainInterface {
system_version: 1,
})
}

async fn call_runtime_api(
&self,
_method_name: &'static str,
_hash: PHash,
_payload: &[u8],
) -> RelayChainResult<Vec<u8>> {
unimplemented!("Not needed for test")
}
}

fn make_validator_and_api() -> (
Expand Down
9 changes: 9 additions & 0 deletions cumulus/client/pov-recovery/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,15 @@ impl RelayChainInterface for Relaychain {
) -> RelayChainResult<Vec<CoreState<PHash, NumberFor<Block>>>> {
unimplemented!("Not needed for test");
}

async fn call_runtime_api(
&self,
_method_name: &'static str,
_hash: PHash,
_payload: &[u8],
) -> RelayChainResult<Vec<u8>> {
unimplemented!("Not needed for test")
}
}

fn make_candidate_chain(candidate_number_range: Range<u32>) -> Vec<CommittedCandidateReceipt> {
Expand Down
19 changes: 18 additions & 1 deletion cumulus/client/relay-chain-inprocess-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use sc_client_api::{
StorageProof,
};
use sc_telemetry::TelemetryWorkerHandle;
use sp_api::ProvideRuntimeApi;
use sp_api::{CallApiAt, CallApiAtParams, CallContext, ProvideRuntimeApi};
use sp_consensus::SyncOracle;
use sp_core::Pair;
use sp_state_machine::{Backend as StateBackend, StorageValue};
Expand Down Expand Up @@ -180,6 +180,23 @@ impl RelayChainInterface for RelayChainInProcessInterface {
Ok(self.backend.blockchain().info().finalized_hash)
}

async fn call_runtime_api(
&self,
method_name: &'static str,
hash: PHash,
payload: &[u8],
) -> RelayChainResult<Vec<u8>> {
Ok(self.full_client.call_api_at(CallApiAtParams {
at: hash,
function: method_name,
arguments: payload.to_vec(),
overlayed_changes: &Default::default(),
call_context: CallContext::Offchain,
recorder: &None,
extensions: &Default::default(),
})?)
}

async fn is_major_syncing(&self) -> RelayChainResult<bool> {
Ok(self.sync_oracle.is_major_syncing())
}
Expand Down
37 changes: 35 additions & 2 deletions cumulus/client/relay-chain-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ use sc_client_api::StorageProof;
use sp_version::RuntimeVersion;

use async_trait::async_trait;
use codec::Error as CodecError;
use codec::{Decode, Encode, Error as CodecError};
use jsonrpsee_core::ClientError as JsonRpcError;
use sp_api::ApiError;

use cumulus_primitives_core::relay_chain::BlockId;
use cumulus_primitives_core::relay_chain::{BlockId, Hash as RelayHash};
pub use cumulus_primitives_core::{
relay_chain::{
BlockNumber, CommittedCandidateReceipt, CoreState, Hash as PHash, Header as PHeader,
Expand Down Expand Up @@ -117,6 +117,14 @@ pub trait RelayChainInterface: Send + Sync {
/// Get the hash of the finalized block.
async fn finalized_block_hash(&self) -> RelayChainResult<PHash>;

/// Call an arbitrary runtime api. The input and output are SCALE-encoded.
async fn call_runtime_api(
&self,
method_name: &'static str,
hash: RelayHash,
payload: &[u8],
) -> RelayChainResult<Vec<u8>>;

/// Returns the whole contents of the downward message queue for the parachain we are collating
/// for.
///
Expand Down Expand Up @@ -296,6 +304,15 @@ where
(**self).finalized_block_hash().await
}

async fn call_runtime_api(
&self,
method_name: &'static str,
hash: RelayHash,
payload: &[u8],
) -> RelayChainResult<Vec<u8>> {
(**self).call_runtime_api(method_name, hash, payload).await
}

async fn is_major_syncing(&self) -> RelayChainResult<bool> {
(**self).is_major_syncing().await
}
Expand Down Expand Up @@ -364,3 +381,19 @@ where
(**self).version(relay_parent).await
}
}

/// Helper function to call an arbitrary runtime API using a `RelayChainInterface` client.
/// Unlike the trait method, this function can be generic, so it handles the encoding of input and
/// output params.
pub async fn call_runtime_api<R>(
tmpolaczyk marked this conversation as resolved.
Show resolved Hide resolved
client: &(impl RelayChainInterface + ?Sized),
method_name: &'static str,
hash: RelayHash,
payload: impl Encode,
) -> RelayChainResult<R>
where
R: Decode,
{
let res = client.call_runtime_api(method_name, hash, &payload.encode()).await?;
Decode::decode(&mut &*res).map_err(Into::into)
}
12 changes: 12 additions & 0 deletions cumulus/client/relay-chain-rpc-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,18 @@ impl RelayChainInterface for RelayChainRpcInterface {
self.rpc_client.chain_get_finalized_head().await
}

async fn call_runtime_api(
&self,
method_name: &'static str,
hash: RelayHash,
payload: &[u8],
) -> RelayChainResult<Vec<u8>> {
self.rpc_client
.call_remote_runtime_function_encoded(method_name, hash, payload)
.await
.map(|bytes| bytes.to_vec())
}

async fn is_major_syncing(&self) -> RelayChainResult<bool> {
self.rpc_client.system_health().await.map(|h| h.is_syncing)
}
Expand Down
26 changes: 20 additions & 6 deletions cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,15 +148,13 @@ impl RelayChainRpcClient {
}
}

/// Call a call to `state_call` rpc method.
pub async fn call_remote_runtime_function<R: Decode>(
/// Same as `call_remote_runtime_function` but work on encoded data
pub async fn call_remote_runtime_function_encoded(
&self,
method_name: &str,
hash: RelayHash,
payload: Option<impl Encode>,
) -> RelayChainResult<R> {
let payload_bytes =
payload.map_or(sp_core::Bytes(Vec::new()), |v| sp_core::Bytes(v.encode()));
payload_bytes: &[u8],
) -> RelayChainResult<sp_core::Bytes> {
let params = rpc_params! {
method_name,
payload_bytes,
Expand All @@ -174,6 +172,22 @@ impl RelayChainRpcClient {
);
})
.await?;

Ok(res)
}

/// Call a call to `state_call` rpc method.
pub async fn call_remote_runtime_function<R: Decode>(
&self,
method_name: &str,
hash: RelayHash,
payload: Option<impl Encode>,
) -> RelayChainResult<R> {
let payload_bytes =
payload.map_or(sp_core::Bytes(Vec::new()), |v| sp_core::Bytes(v.encode()));
let res = self
.call_remote_runtime_function_encoded(method_name, hash, &payload_bytes)
.await?;
Decode::decode(&mut &*res.0).map_err(Into::into)
}

Expand Down
24 changes: 24 additions & 0 deletions prdoc/pr_5521.prdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json

title: Allow to call arbitrary runtime apis using RelayChainInterface

doc:
- audience: Node Dev
description: |
This PR adds a `call_runtime_api` method to RelayChainInterface trait, and a separate function also named `call_runtime_api`
which allows the caller to specify the input and output types, as opposed to having to encode them.

crates:
- name: cumulus-relay-chain-interface
bump: patch
- name: cumulus-client-consensus-common
bump: patch
- name: cumulus-client-pov-recovery
bump: patch
- name: cumulus-client-network
bump: patch
- name: cumulus-relay-chain-inprocess-interface
bump: patch
- name: cumulus-relay-chain-rpc-interface
bump: patch