Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit e72f109

Browse files
emostovkianenigmacoriolinus
authored andcommitted
try-runtime-cli: Add execute-block subcommand (#9077)
* Refactor remote_externalities::rpc_api * try-runtime-cli: Adde `execute-block` subcommand * Trivial * Address some comments * Use required_if & remove header-at usage * Improve doc * Update comment * small tweaks * add overwrite-code to shared params * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: Peter Goodspeed-Niklaus <[email protected]> * make url a shared param * add helper for block_at (#9153) * add helper for block_at * remove redundant bound * doc for fn block_at * Update error message Co-authored-by: kianenigma <[email protected]> Co-authored-by: Peter Goodspeed-Niklaus <[email protected]>
1 parent 9aadecd commit e72f109

File tree

6 files changed

+298
-102
lines changed

6 files changed

+298
-102
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frame/election-provider-multi-phase/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ pub mod pallet {
608608
type Fallback: Get<FallbackStrategy>;
609609

610610
/// Origin that can control this pallet. Note that any action taken by this origin (such)
611-
/// as providing an emergency solution is not checked. Thus, it must be a trusted origin.
611+
/// as providing an emergency solution is not checked. Thus, it must be a trusted origin.
612612
type ForceOrigin: EnsureOrigin<Self::Origin>;
613613

614614
/// The configuration of benchmarking.

utils/frame/remote-externalities/src/lib.rs

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ type KeyPair = (StorageKey, StorageData);
4343

4444
const LOG_TARGET: &str = "remote-ext";
4545
const DEFAULT_TARGET: &str = "wss://rpc.polkadot.io";
46-
const BATCH_SIZE: usize = 512;
46+
const BATCH_SIZE: usize = 1000;
4747

4848
jsonrpsee_proc_macros::rpc_client_api! {
4949
RpcApi<B: BlockT> {
50+
#[rpc(method = "state_getStorage", positional_params)]
51+
fn get_storage(prefix: StorageKey, hash: Option<B::Hash>) -> StorageData;
5052
#[rpc(method = "state_getKeysPaged", positional_params)]
5153
fn get_keys_paged(
5254
prefix: Option<StorageKey>,
@@ -107,7 +109,7 @@ impl From<String> for Transport {
107109
/// A state snapshot config may be present and will be written to in that case.
108110
#[derive(Clone)]
109111
pub struct OnlineConfig<B: BlockT> {
110-
/// The block number at which to connect. Will be latest finalized head if not provided.
112+
/// The block hash at which to get the runtime state. Will be latest finalized head if not provided.
111113
pub at: Option<B::Hash>,
112114
/// An optional state snapshot file to WRITE to, not for reading. Not written if set to `None`.
113115
pub state_snapshot: Option<SnapshotConfig>,
@@ -159,8 +161,11 @@ impl Default for SnapshotConfig {
159161
pub struct Builder<B: BlockT> {
160162
/// Custom key-pairs to be injected into the externalities.
161163
inject: Vec<KeyPair>,
162-
/// Storage entry key prefixes to be injected into the externalities. The *hashed* prefix must be given.
164+
/// Storage entry key prefixes to be injected into the externalities. The *hashed* prefix must
165+
/// be given.
163166
hashed_prefixes: Vec<Vec<u8>>,
167+
/// Storage entry keys to be injected into the externalities. The *hashed* key must be given.
168+
hashed_keys: Vec<Vec<u8>>,
164169
/// connectivity mode, online or offline.
165170
mode: Mode<B>,
166171
}
@@ -169,7 +174,12 @@ pub struct Builder<B: BlockT> {
169174
// that.
170175
impl<B: BlockT> Default for Builder<B> {
171176
fn default() -> Self {
172-
Self { inject: Default::default(), mode: Default::default(), hashed_prefixes: Default::default() }
177+
Self {
178+
inject: Default::default(),
179+
mode: Default::default(),
180+
hashed_prefixes: Default::default(),
181+
hashed_keys: Default::default(),
182+
}
173183
}
174184
}
175185

@@ -192,6 +202,17 @@ impl<B: BlockT> Builder<B> {
192202

193203
// RPC methods
194204
impl<B: BlockT> Builder<B> {
205+
async fn rpc_get_storage(
206+
&self,
207+
key: StorageKey,
208+
maybe_at: Option<B::Hash>,
209+
) -> Result<StorageData, &'static str> {
210+
trace!(target: LOG_TARGET, "rpc: get_storage");
211+
RpcApi::<B>::get_storage(self.as_online().rpc_client(), key, maybe_at).await.map_err(|e| {
212+
error!("Error = {:?}", e);
213+
"rpc get_storage failed."
214+
})
215+
}
195216
/// Get the latest finalized head.
196217
async fn rpc_get_head(&self) -> Result<B::Hash, &'static str> {
197218
trace!(target: LOG_TARGET, "rpc: finalized_head");
@@ -281,7 +302,7 @@ impl<B: BlockT> Builder<B> {
281302
let values = client.batch_request::<Option<StorageData>>(batch)
282303
.await
283304
.map_err(|e| {
284-
log::error!(target: LOG_TARGET, "failed to execute batch {:?} due to {:?}", chunk_keys, e);
305+
log::error!(target: LOG_TARGET, "failed to execute batch: {:?}. Error: {:?}", chunk_keys, e);
285306
"batch failed."
286307
})?;
287308
assert_eq!(chunk_keys.len(), values.len());
@@ -356,11 +377,23 @@ impl<B: BlockT> Builder<B> {
356377
};
357378

358379
for prefix in &self.hashed_prefixes {
359-
info!(target: LOG_TARGET, "adding data for hashed prefix: {:?}", HexDisplay::from(prefix));
360-
let additional_key_values = self.rpc_get_pairs_paged(StorageKey(prefix.to_vec()), at).await?;
380+
debug!(
381+
target: LOG_TARGET,
382+
"adding data for hashed prefix: {:?}",
383+
HexDisplay::from(prefix)
384+
);
385+
let additional_key_values =
386+
self.rpc_get_pairs_paged(StorageKey(prefix.to_vec()), at).await?;
361387
keys_and_values.extend(additional_key_values);
362388
}
363389

390+
for key in &self.hashed_keys {
391+
let key = StorageKey(key.to_vec());
392+
debug!(target: LOG_TARGET, "adding data for hashed key: {:?}", HexDisplay::from(&key));
393+
let value = self.rpc_get_storage(key.clone(), Some(at)).await?;
394+
keys_and_values.push((key, value));
395+
}
396+
364397
Ok(keys_and_values)
365398
}
366399

@@ -400,7 +433,7 @@ impl<B: BlockT> Builder<B> {
400433

401434
info!(
402435
target: LOG_TARGET,
403-
"extending externalities with {} manually injected keys",
436+
"extending externalities with {} manually injected key-values",
404437
self.inject.len()
405438
);
406439
base_kv.extend(self.inject.clone());
@@ -416,19 +449,29 @@ impl<B: BlockT> Builder<B> {
416449
}
417450

418451
/// Inject a manual list of key and values to the storage.
419-
pub fn inject(mut self, injections: &[KeyPair]) -> Self {
452+
pub fn inject_key_value(mut self, injections: &[KeyPair]) -> Self {
420453
for i in injections {
421454
self.inject.push(i.clone());
422455
}
423456
self
424457
}
425458

426-
/// Inject a hashed prefix. This is treated as-is, and should be pre-hashed.
459+
/// Inject a hashed prefix. This is treated as-is, and should be pre-hashed.
460+
///
461+
/// This should be used to inject a "PREFIX", like a storage (double) map.
427462
pub fn inject_hashed_prefix(mut self, hashed: &[u8]) -> Self {
428463
self.hashed_prefixes.push(hashed.to_vec());
429464
self
430465
}
431466

467+
/// Inject a hashed key to scrape. This is treated as-is, and should be pre-hashed.
468+
///
469+
/// This should be used to inject a "KEY", like a storage value.
470+
pub fn inject_hashed_key(mut self, hashed: &[u8]) -> Self {
471+
self.hashed_keys.push(hashed.to_vec());
472+
self
473+
}
474+
432475
/// Configure a state snapshot to be used.
433476
pub fn mode(mut self, mode: Mode<B>) -> Self {
434477
self.mode = mode;

utils/frame/remote-externalities/src/rpc_api.rs

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,65 @@
1818
//! WS RPC API for one off RPC calls to a substrate node.
1919
// TODO: Consolidate one off RPC calls https://github.com/paritytech/substrate/issues/8988
2020

21-
use super::*;
21+
use sp_runtime::{generic::SignedBlock, traits::{Block as BlockT, Header as HeaderT}};
22+
use jsonrpsee_ws_client::{WsClientBuilder, WsClient, v2::params::JsonRpcParams, traits::Client};
2223

2324
/// Get the header of the block identified by `at`
24-
pub async fn get_header<B: BlockT, S: AsRef<str>>(from: S, at: B::Hash) -> Result<B::Header, String>
25+
pub async fn get_header<Block, S>(from: S, at: Block::Hash) -> Result<Block::Header, String>
2526
where
26-
B::Header: serde::de::DeserializeOwned,
27+
Block: BlockT,
28+
Block::Header: serde::de::DeserializeOwned,
29+
S: AsRef<str>,
2730
{
28-
use jsonrpsee_ws_client::traits::Client;
29-
let at = serde_json::to_value(at)
30-
.map_err(|e| format!("Block hash could not be converted to JSON due to {:?}", e))?;
31-
let params = vec![at];
32-
let client = WsClientBuilder::default()
33-
.max_request_body_size(u32::MAX)
34-
.build(from.as_ref())
35-
.await
36-
.map_err(|e| format!("`WsClientBuilder` failed to build do to {:?}", e))?;
37-
client.request::<B::Header>("chain_getHeader", JsonRpcParams::Array(params))
31+
let params = vec![hash_to_json::<Block>(at)?];
32+
let client = build_client(from).await?;
33+
34+
client.request::<Block::Header>("chain_getHeader", JsonRpcParams::Array(params))
3835
.await
39-
.map_err(|e| format!("chain_getHeader request failed due to {:?}", e))
36+
.map_err(|e| format!("chain_getHeader request failed: {:?}", e))
4037
}
4138

4239
/// Get the finalized head
43-
pub async fn get_finalized_head<B: BlockT, S: AsRef<str>>(from: S) -> Result<B::Hash, String> {
44-
use jsonrpsee_ws_client::traits::Client;
45-
let client = WsClientBuilder::default()
40+
pub async fn get_finalized_head<Block, S>(from: S) -> Result<Block::Hash, String>
41+
where
42+
Block: BlockT,
43+
S: AsRef<str>,
44+
{
45+
let client = build_client(from).await?;
46+
47+
client.request::<Block::Hash>("chain_getFinalizedHead", JsonRpcParams::NoParams)
48+
.await
49+
.map_err(|e| format!("chain_getFinalizedHead request failed: {:?}", e))
50+
}
51+
52+
/// Get the signed block identified by `at`.
53+
pub async fn get_block<Block, S>(from: S, at: Block::Hash) -> Result<Block, String>
54+
where
55+
S: AsRef<str>,
56+
Block: BlockT + serde::de::DeserializeOwned,
57+
Block::Header: HeaderT,
58+
{
59+
let params = vec![hash_to_json::<Block>(at)?];
60+
let client = build_client(from).await?;
61+
let signed_block = client
62+
.request::<SignedBlock<Block>>("chain_getBlock", JsonRpcParams::Array(params))
63+
.await
64+
.map_err(|e| format!("chain_getBlock request failed: {:?}", e))?;
65+
66+
Ok(signed_block.block)
67+
}
68+
69+
/// Convert a block hash to a serde json value.
70+
fn hash_to_json<Block: BlockT>(hash: Block::Hash) -> Result<serde_json::Value, String> {
71+
serde_json::to_value(hash)
72+
.map_err(|e| format!("Block hash could not be converted to JSON: {:?}", e))
73+
}
74+
75+
/// Build a website client that connects to `from`.
76+
async fn build_client<S: AsRef<str>>(from: S) -> Result<WsClient, String> {
77+
WsClientBuilder::default()
4678
.max_request_body_size(u32::MAX)
4779
.build(from.as_ref())
4880
.await
49-
.map_err(|e| format!("`WsClientBuilder` failed to build do to {:?}", e))?;
50-
client.request::<B::Hash>("chain_getFinalizedHead", JsonRpcParams::NoParams)
51-
.await
52-
.map_err(|e| format!("chain_getFinalizedHead request failed due to {:?}", e))
81+
.map_err(|e| format!("`WsClientBuilder` failed to build: {:?}", e))
5382
}

utils/frame/try-runtime/cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ sp-blockchain = { version = "3.0.0", path = "../../../../primitives/blockchain"
2929
sp-runtime = { version = "3.0.0", path = "../../../../primitives/runtime" }
3030
sp-externalities = { version = "0.9.0", path = "../../../../primitives/externalities" }
3131
sp-core = { version = "3.0.0", path = "../../../../primitives/core" }
32+
sp-io = { version = "3.0.0", path = "../../../../primitives/io" }
3233
sp-keystore = { version = "0.9.0", path = "../../../../primitives/keystore" }
3334
frame-try-runtime = { version = "0.9.0", path = "../../../../frame/try-runtime" }
3435

0 commit comments

Comments
 (0)