From 6f895b986f94f655547081b38eaef05c7489469f Mon Sep 17 00:00:00 2001 From: Tomasz Polaczyk Date: Mon, 26 Aug 2024 11:29:09 +0200 Subject: [PATCH 1/7] Allow calling any runtime api using RelayChainInterface --- .../src/lib.rs | 23 ++++++++++++ .../client/relay-chain-interface/src/lib.rs | 35 +++++++++++++++++-- .../relay-chain-rpc-interface/src/lib.rs | 12 +++++++ .../src/rpc_client.rs | 26 ++++++++++---- 4 files changed, 88 insertions(+), 8 deletions(-) diff --git a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs index 629fa728be37..9f09fd9188dd 100644 --- a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs +++ b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs @@ -180,6 +180,29 @@ impl RelayChainInterface for RelayChainInProcessInterface { Ok(self.backend.blockchain().info().finalized_hash) } + async fn call_remote_runtime_function_encoded( + &self, + method_name: &'static str, + hash: PHash, + payload: &[u8], + ) -> RelayChainResult> { + use sp_api::{CallApiAt, CallApiAtParams, CallContext, __private::Extensions}; + use sp_state_machine::OverlayedChanges; + use std::cell::RefCell; + + let overlayed_changes = OverlayedChanges::default(); + + Ok(self.full_client.call_api_at(CallApiAtParams { + at: hash, + function: method_name, + arguments: payload.to_vec(), + overlayed_changes: &RefCell::new(overlayed_changes), + call_context: CallContext::Offchain, + recorder: &None, + extensions: &RefCell::new(Extensions::new()), + })?) + } + async fn is_major_syncing(&self) -> RelayChainResult { Ok(self.sync_oracle.is_major_syncing()) } diff --git a/cumulus/client/relay-chain-interface/src/lib.rs b/cumulus/client/relay-chain-interface/src/lib.rs index d02035e84e92..156a60716070 100644 --- a/cumulus/client/relay-chain-interface/src/lib.rs +++ b/cumulus/client/relay-chain-interface/src/lib.rs @@ -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, @@ -117,6 +117,13 @@ pub trait RelayChainInterface: Send + Sync { /// Get the hash of the finalized block. async fn finalized_block_hash(&self) -> RelayChainResult; + async fn call_remote_runtime_function_encoded( + &self, + method_name: &'static str, + hash: RelayHash, + payload: &[u8], + ) -> RelayChainResult>; + /// Returns the whole contents of the downward message queue for the parachain we are collating /// for. /// @@ -296,6 +303,15 @@ where (**self).finalized_block_hash().await } + async fn call_remote_runtime_function_encoded( + &self, + method_name: &'static str, + hash: RelayHash, + payload: &[u8], + ) -> RelayChainResult> { + (**self).call_remote_runtime_function_encoded(method_name, hash, payload).await + } + async fn is_major_syncing(&self) -> RelayChainResult { (**self).is_major_syncing().await } @@ -364,3 +380,18 @@ where (**self).version(relay_parent).await } } + +pub async fn call_remote_runtime_function( + client: &(impl RelayChainInterface + ?Sized), + method_name: &'static str, + hash: RelayHash, + payload: impl Encode, +) -> RelayChainResult +where + R: Decode, +{ + let res = client + .call_remote_runtime_function_encoded(method_name, hash, &payload.encode()) + .await?; + Decode::decode(&mut &*res).map_err(Into::into) +} diff --git a/cumulus/client/relay-chain-rpc-interface/src/lib.rs b/cumulus/client/relay-chain-rpc-interface/src/lib.rs index e32ec6a41a4b..e16ecd45a7fa 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/lib.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/lib.rs @@ -163,6 +163,18 @@ impl RelayChainInterface for RelayChainRpcInterface { self.rpc_client.chain_get_finalized_head().await } + async fn call_remote_runtime_function_encoded( + &self, + method_name: &'static str, + hash: RelayHash, + payload: &[u8], + ) -> RelayChainResult> { + 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 { self.rpc_client.system_health().await.map(|h| h.is_syncing) } diff --git a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs index c7eaa45958b0..baf13f9658a0 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/rpc_client.rs @@ -134,15 +134,13 @@ impl RelayChainRpcClient { RelayChainRpcClient { worker_channel } } - /// Call a call to `state_call` rpc method. - pub async fn call_remote_runtime_function( + /// 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, - ) -> RelayChainResult { - let payload_bytes = - payload.map_or(sp_core::Bytes(Vec::new()), |v| sp_core::Bytes(v.encode())); + payload_bytes: &[u8], + ) -> RelayChainResult { let params = rpc_params! { method_name, payload_bytes, @@ -159,6 +157,22 @@ impl RelayChainRpcClient { ); }) .await?; + + Ok(res) + } + + /// 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 res = self + .call_remote_runtime_function_encoded(method_name, hash, &payload_bytes) + .await?; Decode::decode(&mut &*res.0).map_err(Into::into) } From 953d1231152309eb6003bf5fd1a632fee6f40289 Mon Sep 17 00:00:00 2001 From: Tomasz Polaczyk Date: Fri, 30 Aug 2024 10:38:11 +0200 Subject: [PATCH 2/7] Review --- .../relay-chain-inprocess-interface/src/lib.rs | 14 ++++---------- cumulus/client/relay-chain-interface/src/lib.rs | 11 ++++++----- .../client/relay-chain-rpc-interface/src/lib.rs | 2 +- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs index 9f09fd9188dd..0455c03fc4de 100644 --- a/cumulus/client/relay-chain-inprocess-interface/src/lib.rs +++ b/cumulus/client/relay-chain-inprocess-interface/src/lib.rs @@ -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}; @@ -180,26 +180,20 @@ impl RelayChainInterface for RelayChainInProcessInterface { Ok(self.backend.blockchain().info().finalized_hash) } - async fn call_remote_runtime_function_encoded( + async fn call_runtime_api( &self, method_name: &'static str, hash: PHash, payload: &[u8], ) -> RelayChainResult> { - use sp_api::{CallApiAt, CallApiAtParams, CallContext, __private::Extensions}; - use sp_state_machine::OverlayedChanges; - use std::cell::RefCell; - - let overlayed_changes = OverlayedChanges::default(); - Ok(self.full_client.call_api_at(CallApiAtParams { at: hash, function: method_name, arguments: payload.to_vec(), - overlayed_changes: &RefCell::new(overlayed_changes), + overlayed_changes: &Default::default(), call_context: CallContext::Offchain, recorder: &None, - extensions: &RefCell::new(Extensions::new()), + extensions: &Default::default(), })?) } diff --git a/cumulus/client/relay-chain-interface/src/lib.rs b/cumulus/client/relay-chain-interface/src/lib.rs index 156a60716070..6e67cacdd2fa 100644 --- a/cumulus/client/relay-chain-interface/src/lib.rs +++ b/cumulus/client/relay-chain-interface/src/lib.rs @@ -117,7 +117,8 @@ pub trait RelayChainInterface: Send + Sync { /// Get the hash of the finalized block. async fn finalized_block_hash(&self) -> RelayChainResult; - async fn call_remote_runtime_function_encoded( + /// Call an arbitrary runtime api. The input and output are SCALE-encoded. + async fn call_runtime_api( &self, method_name: &'static str, hash: RelayHash, @@ -303,13 +304,13 @@ where (**self).finalized_block_hash().await } - async fn call_remote_runtime_function_encoded( + async fn call_runtime_api( &self, method_name: &'static str, hash: RelayHash, payload: &[u8], ) -> RelayChainResult> { - (**self).call_remote_runtime_function_encoded(method_name, hash, payload).await + (**self).call_runtime_api(method_name, hash, payload).await } async fn is_major_syncing(&self) -> RelayChainResult { @@ -381,7 +382,7 @@ where } } -pub async fn call_remote_runtime_function( +pub async fn call_runtime_api( client: &(impl RelayChainInterface + ?Sized), method_name: &'static str, hash: RelayHash, @@ -391,7 +392,7 @@ where R: Decode, { let res = client - .call_remote_runtime_function_encoded(method_name, hash, &payload.encode()) + .call_runtime_api(method_name, hash, &payload.encode()) .await?; Decode::decode(&mut &*res).map_err(Into::into) } diff --git a/cumulus/client/relay-chain-rpc-interface/src/lib.rs b/cumulus/client/relay-chain-rpc-interface/src/lib.rs index e16ecd45a7fa..3389a77d8b61 100644 --- a/cumulus/client/relay-chain-rpc-interface/src/lib.rs +++ b/cumulus/client/relay-chain-rpc-interface/src/lib.rs @@ -163,7 +163,7 @@ impl RelayChainInterface for RelayChainRpcInterface { self.rpc_client.chain_get_finalized_head().await } - async fn call_remote_runtime_function_encoded( + async fn call_runtime_api( &self, method_name: &'static str, hash: RelayHash, From e76bc49c338bfafc42946051a27f1df91e28a3a4 Mon Sep 17 00:00:00 2001 From: Tomasz Polaczyk Date: Mon, 2 Sep 2024 11:09:05 +0200 Subject: [PATCH 3/7] Docs + fix tests --- cumulus/client/consensus/common/src/tests.rs | 9 +++++++++ cumulus/client/network/src/tests.rs | 9 +++++++++ cumulus/client/pov-recovery/src/tests.rs | 9 +++++++++ cumulus/client/relay-chain-interface/src/lib.rs | 3 +++ 4 files changed, 30 insertions(+) diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index 06f90330d474..5765506c8d34 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -268,6 +268,15 @@ impl RelayChainInterface for Relaychain { async fn version(&self, _: PHash) -> RelayChainResult { unimplemented!("Not needed for test") } + + async fn call_runtime_api( + &self, + _method_name: &'static str, + _hash: RelayHash, + _payload: &[u8], + ) -> RelayChainResult> { + unimplemented!("Not needed for test") + } } fn sproof_with_best_parent(client: &Client) -> RelayStateSproofBuilder { diff --git a/cumulus/client/network/src/tests.rs b/cumulus/client/network/src/tests.rs index cde73c4c5180..74e8a52f5009 100644 --- a/cumulus/client/network/src/tests.rs +++ b/cumulus/client/network/src/tests.rs @@ -326,6 +326,15 @@ impl RelayChainInterface for DummyRelayChainInterface { state_version: 1, }) } + + async fn call_runtime_api( + &self, + _method_name: &'static str, + _hash: RelayHash, + _payload: &[u8], + ) -> RelayChainResult> { + unimplemented!("Not needed for test") + } } fn make_validator_and_api() -> ( diff --git a/cumulus/client/pov-recovery/src/tests.rs b/cumulus/client/pov-recovery/src/tests.rs index 6f274ed18b6b..e771931f344d 100644 --- a/cumulus/client/pov-recovery/src/tests.rs +++ b/cumulus/client/pov-recovery/src/tests.rs @@ -487,6 +487,15 @@ impl RelayChainInterface for Relaychain { ) -> RelayChainResult>>> { unimplemented!("Not needed for test"); } + + async fn call_runtime_api( + &self, + _method_name: &'static str, + _hash: RelayHash, + _payload: &[u8], + ) -> RelayChainResult> { + unimplemented!("Not needed for test") + } } fn make_candidate_chain(candidate_number_range: Range) -> Vec { diff --git a/cumulus/client/relay-chain-interface/src/lib.rs b/cumulus/client/relay-chain-interface/src/lib.rs index 6e67cacdd2fa..114e7f9c8a06 100644 --- a/cumulus/client/relay-chain-interface/src/lib.rs +++ b/cumulus/client/relay-chain-interface/src/lib.rs @@ -382,6 +382,9 @@ where } } +/// 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( client: &(impl RelayChainInterface + ?Sized), method_name: &'static str, From a7901894540b0194b0d04089f9448dc7cd2d766a Mon Sep 17 00:00:00 2001 From: Tomasz Polaczyk Date: Mon, 2 Sep 2024 12:27:49 +0200 Subject: [PATCH 4/7] fix --- cumulus/client/consensus/common/src/tests.rs | 2 +- cumulus/client/network/src/tests.rs | 2 +- cumulus/client/pov-recovery/src/tests.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cumulus/client/consensus/common/src/tests.rs b/cumulus/client/consensus/common/src/tests.rs index 5765506c8d34..794ce30de3e1 100644 --- a/cumulus/client/consensus/common/src/tests.rs +++ b/cumulus/client/consensus/common/src/tests.rs @@ -272,7 +272,7 @@ impl RelayChainInterface for Relaychain { async fn call_runtime_api( &self, _method_name: &'static str, - _hash: RelayHash, + _hash: PHash, _payload: &[u8], ) -> RelayChainResult> { unimplemented!("Not needed for test") diff --git a/cumulus/client/network/src/tests.rs b/cumulus/client/network/src/tests.rs index 74e8a52f5009..eb1b89bf5888 100644 --- a/cumulus/client/network/src/tests.rs +++ b/cumulus/client/network/src/tests.rs @@ -330,7 +330,7 @@ impl RelayChainInterface for DummyRelayChainInterface { async fn call_runtime_api( &self, _method_name: &'static str, - _hash: RelayHash, + _hash: PHash, _payload: &[u8], ) -> RelayChainResult> { unimplemented!("Not needed for test") diff --git a/cumulus/client/pov-recovery/src/tests.rs b/cumulus/client/pov-recovery/src/tests.rs index e771931f344d..7b8a546b60db 100644 --- a/cumulus/client/pov-recovery/src/tests.rs +++ b/cumulus/client/pov-recovery/src/tests.rs @@ -491,7 +491,7 @@ impl RelayChainInterface for Relaychain { async fn call_runtime_api( &self, _method_name: &'static str, - _hash: RelayHash, + _hash: PHash, _payload: &[u8], ) -> RelayChainResult> { unimplemented!("Not needed for test") From f2a48f454840d368dd9a24f2f02d89cb7d365721 Mon Sep 17 00:00:00 2001 From: Tomasz Polaczyk Date: Mon, 2 Sep 2024 14:17:01 +0200 Subject: [PATCH 5/7] fmt --- cumulus/client/relay-chain-interface/src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cumulus/client/relay-chain-interface/src/lib.rs b/cumulus/client/relay-chain-interface/src/lib.rs index 114e7f9c8a06..8d172e423eb9 100644 --- a/cumulus/client/relay-chain-interface/src/lib.rs +++ b/cumulus/client/relay-chain-interface/src/lib.rs @@ -394,8 +394,6 @@ pub async fn call_runtime_api( where R: Decode, { - let res = client - .call_runtime_api(method_name, hash, &payload.encode()) - .await?; + let res = client.call_runtime_api(method_name, hash, &payload.encode()).await?; Decode::decode(&mut &*res).map_err(Into::into) } From 5c19396ef8d7a3208350b516a4345f5fef6e89fe Mon Sep 17 00:00:00 2001 From: Tomasz Polaczyk Date: Wed, 4 Sep 2024 14:57:36 +0200 Subject: [PATCH 6/7] Add pr-doc --- prdoc/pr_5521.prdoc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 prdoc/pr_5521.prdoc diff --git a/prdoc/pr_5521.prdoc b/prdoc/pr_5521.prdoc new file mode 100644 index 000000000000..c5e6d10465f4 --- /dev/null +++ b/prdoc/pr_5521.prdoc @@ -0,0 +1,14 @@ +# 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 From 248d860de83a6e3192b12c101b9ad117196c9318 Mon Sep 17 00:00:00 2001 From: Tomasz Polaczyk Date: Wed, 11 Sep 2024 10:02:44 +0200 Subject: [PATCH 7/7] More prdoc --- prdoc/pr_5521.prdoc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/prdoc/pr_5521.prdoc b/prdoc/pr_5521.prdoc index c5e6d10465f4..564d9df58ceb 100644 --- a/prdoc/pr_5521.prdoc +++ b/prdoc/pr_5521.prdoc @@ -12,3 +12,13 @@ doc: 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