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

Unstable Backend: add back the old chainHead RPCs/tests #1137

Merged
merged 13 commits into from
Aug 29, 2023
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -704,10 +704,6 @@ impl<'a> CustomValueMetadata<'a> {
}

/// Calculates the hash for the CustomValueMetadata.
///
/// # Panics
///
/// Panics if `self.type_id` is not registered in the provided type registry
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this not true anymore?

Can't find anything in this PR about this :P

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the pub fn get_type_hash would still panic if the id passed as param is not present in the PortableRegistry 🤔

I belive the CustomValueMetadata could only panic in practice here if the metadata is broken, since that's where our value is coming from

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment was left over from when this call was taking in a PortableRegistry as an argument (which might then have different types from what he metadata knew about and thus could panic). That was since removed but I noticed that the comment wasn't updated so I tweaked it :)

pub fn hash(&self) -> [u8; HASH_LEN] {
let mut cache = HashMap::new();
get_custom_value_hash(self, &mut cache)
Expand Down
173 changes: 158 additions & 15 deletions subxt/src/backend/legacy/rpc_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,35 @@ impl<T: Config> LegacyRpcMethods<T> {
Ok(data.into_iter().map(|b| b.0).collect())
}

/// Query historical storage entries
pub async fn state_query_storage(
&self,
keys: impl IntoIterator<Item = &[u8]>,
from: T::Hash,
to: Option<T::Hash>,
) -> Result<Vec<StorageChangeSet<T::Hash>>, Error> {
let keys: Vec<String> = keys.into_iter().map(to_hex).collect();
let params = rpc_params![keys, from, to];
self.client
.request("state_queryStorage", params)
.await
.map_err(Into::into)
}

/// Query historical storage entries
pub async fn state_query_storage_at(
&self,
keys: impl IntoIterator<Item = &[u8]>,
at: Option<T::Hash>,
) -> Result<Vec<StorageChangeSet<T::Hash>>, Error> {
let keys: Vec<String> = keys.into_iter().map(to_hex).collect();
let params = rpc_params![keys, at];
self.client
.request("state_queryStorageAt", params)
.await
.map_err(Into::into)
}

/// Fetch the genesis hash
pub async fn genesis_hash(&self) -> Result<T::Hash, Error> {
let block_zero = 0u32;
Expand Down Expand Up @@ -158,6 +187,32 @@ impl<T: Config> LegacyRpcMethods<T> {
Ok(block)
}

/// Reexecute the specified `block_hash` and gather statistics while doing so.
///
/// This function requires the specified block and its parent to be available
/// at the queried node. If either the specified block or the parent is pruned,
/// this function will return `None`.
pub async fn dev_get_block_stats(
&self,
block_hash: T::Hash,
) -> Result<Option<BlockStats>, Error> {
let params = rpc_params![block_hash];
let stats = self.client.request("dev_getBlockStats", params).await?;
Ok(stats)
}

/// Get proof of storage entries at a specific block's state.
pub async fn state_get_read_proof(
&self,
keys: impl IntoIterator<Item = &[u8]>,
hash: Option<T::Hash>,
) -> Result<ReadProof<T::Hash>, Error> {
let keys: Vec<String> = keys.into_iter().map(to_hex).collect();
let params = rpc_params![keys, hash];
let proof = self.client.request("state_getReadProof", params).await?;
Ok(proof)
}

/// Fetch the runtime version
pub async fn state_get_runtime_version(
&self,
Expand Down Expand Up @@ -268,6 +323,49 @@ impl<T: Config> LegacyRpcMethods<T> {
Ok(subscription)
}

/// Insert a key into the keystore.
pub async fn author_insert_key(
&self,
key_type: String,
suri: String,
public: Vec<u8>,
) -> Result<(), Error> {
let params = rpc_params![key_type, suri, Bytes(public)];
self.client.request("author_insertKey", params).await?;
Ok(())
}

/// Generate new session keys and returns the corresponding public keys.
pub async fn author_rotate_keys(&self) -> Result<Vec<u8>, Error> {
let bytes: Bytes = self
.client
.request("author_rotateKeys", rpc_params![])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, are we adding those back to the legacy API since they might be useful for validators? 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just added back anything that I had removed earlier basically, so that if anybody happened to be using them then there is an easy migration path. I'd like to remove some of these again eventually, but ideally as part of a smaller change!

.await?;
Ok(bytes.0)
}

/// Checks if the keystore has private keys for the given session public keys.
///
/// `session_keys` is the SCALE encoded session keys object from the runtime.
///
/// Returns `true` if all private keys could be found.
pub async fn author_has_session_keys(&self, session_keys: Vec<u8>) -> Result<bool, Error> {
let params = rpc_params![Bytes(session_keys)];
self.client.request("author_hasSessionKeys", params).await
}

/// Checks if the keystore has private keys for the given public key and key type.
///
/// Returns `true` if a private key could be found.
pub async fn author_has_key(
&self,
public_key: Vec<u8>,
key_type: String,
) -> Result<bool, Error> {
let params = rpc_params![Bytes(public_key), key_type];
self.client.request("author_hasKey", params).await
}

/// Execute a runtime API call via `state_call` RPC method.
pub async fn state_call(
&self,
Expand Down Expand Up @@ -411,21 +509,6 @@ pub enum TransactionStatus<Hash> {
Invalid,
}

/// Hex-serialized shim for `Vec<u8>`.
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Hash, PartialOrd, Ord, Debug)]
pub struct Bytes(#[serde(with = "impl_serde::serialize")] pub Vec<u8>);
impl std::ops::Deref for Bytes {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.0[..]
}
}
impl From<Vec<u8>> for Bytes {
fn from(s: Vec<u8>) -> Self {
Bytes(s)
}
}

/// The decoded result returned from calling `system_dryRun` on some extrinsic.
#[derive(Debug, PartialEq, Eq)]
pub enum DryRunResult {
Expand Down Expand Up @@ -468,6 +551,51 @@ impl DryRunResultBytes {
}
}

/// Storage change set
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug)]
#[serde(rename_all = "camelCase")]
pub struct StorageChangeSet<Hash> {
/// Block hash
pub block: Hash,
/// A list of changes; tuples of storage key and optional storage data.
pub changes: Vec<(Bytes, Option<Bytes>)>,
}

/// Statistics of a block returned by the `dev_getBlockStats` RPC.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BlockStats {
/// The length in bytes of the storage proof produced by executing the block.
pub witness_len: u64,
/// The length in bytes of the storage proof after compaction.
pub witness_compact_len: u64,
/// Length of the block in bytes.
///
/// This information can also be acquired by downloading the whole block. This merely
/// saves some complexity on the client side.
pub block_len: u64,
/// Number of extrinsics in the block.
///
/// This information can also be acquired by downloading the whole block. This merely
/// saves some complexity on the client side.
pub num_extrinsics: u64,
}

/// ReadProof struct returned by the RPC
///
/// # Note
///
/// This is copied from `sc-rpc-api` to avoid a dependency on that crate. Therefore it
/// must be kept compatible with that type from the target substrate version.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ReadProof<Hash> {
/// Block hash used to generate the proof
pub at: Hash,
/// A proof used to prove that storage entries are included in the storage trie
pub proof: Vec<Bytes>,
}

/// A number type that can be serialized both as a number or a string that encodes a number in a
/// string.
///
Expand Down Expand Up @@ -530,3 +658,18 @@ impl From<U256> for NumberOrHex {
fn to_hex(bytes: impl AsRef<[u8]>) -> String {
format!("0x{}", hex::encode(bytes.as_ref()))
}

/// Hex-serialized shim for `Vec<u8>`.
#[derive(PartialEq, Eq, Clone, Serialize, Deserialize, Hash, PartialOrd, Ord, Debug)]
pub struct Bytes(#[serde(with = "impl_serde::serialize")] pub Vec<u8>);
impl std::ops::Deref for Bytes {
type Target = [u8];
fn deref(&self) -> &[u8] {
&self.0[..]
}
}
impl From<Vec<u8>> for Bytes {
fn from(s: Vec<u8>) -> Self {
Bytes(s)
}
}
1 change: 1 addition & 0 deletions subxt/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

pub mod legacy;
pub mod rpc;
pub mod unstable;

use crate::error::Error;
use crate::metadata::Metadata;
Expand Down
16 changes: 16 additions & 0 deletions subxt/src/backend/unstable/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
// see LICENSE for license details.

//! This module will expose a backend implementation based on the new APIs
//! described at <https://github.com/paritytech/json-rpc-interface-spec/>. See
//! [`rpc_methods`] for the raw API calls.
//!
//! # Warning
//!
//! Everything in this module is **unstable**, meaning that it could change without
//! warning at any time.

pub mod rpc_methods;

pub use rpc_methods::UnstableRpcMethods;
Loading