mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 08:47:57 +00:00
Runtime State Test + Integration with try-runtime (#10174)
* add missing version to dependencies * Huh * add features more * more fixing * last touches * it all finally works * remove some feature gates * remove unused * fix old macro * make it work again * fmt * remove unused import * ".git/.scripts/fmt.sh" 1 * Cleanup more * fix and rename everything * a few clippy fixes * Add try-runtime feature Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> * small fixes * fmt * Update bin/node-template/runtime/src/lib.rs * fix build * Update utils/frame/try-runtime/cli/src/lib.rs Co-authored-by: David <dvdplm@gmail.com> * Update utils/frame/try-runtime/cli/src/commands/execute_block.rs Co-authored-by: David <dvdplm@gmail.com> * address all review comments * fix typos * revert spec change * last touches * update docs * fmt * remove some debug_assertions * fmt Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: command-bot <> Co-authored-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io> Co-authored-by: David <dvdplm@gmail.com>
This commit is contained in:
@@ -19,6 +19,7 @@ use crate::{
|
||||
build_executor, ensure_matching_spec, extract_code, full_extensions, hash_of, local_spec,
|
||||
state_machine_call_with_proof, SharedParams, State, LOG_TARGET,
|
||||
};
|
||||
use parity_scale_codec::Encode;
|
||||
use remote_externalities::rpc_api;
|
||||
use sc_service::{Configuration, NativeExecutionDispatch};
|
||||
use sp_core::storage::well_known_keys;
|
||||
@@ -26,17 +27,30 @@ use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
|
||||
use std::{fmt::Debug, str::FromStr};
|
||||
|
||||
/// Configurations of the [`Command::ExecuteBlock`].
|
||||
///
|
||||
/// This will always call into `TryRuntime_execute_block`, which can optionally skip the state-root
|
||||
/// check (useful for trying a unreleased runtime), and can execute runtime sanity checks as well.
|
||||
#[derive(Debug, Clone, clap::Parser)]
|
||||
pub struct ExecuteBlockCmd {
|
||||
/// Overwrite the wasm code in state or not.
|
||||
#[clap(long)]
|
||||
overwrite_wasm_code: bool,
|
||||
|
||||
/// If set, then the state root check is disabled by the virtue of calling into
|
||||
/// `TryRuntime_execute_block_no_check` instead of
|
||||
/// `Core_execute_block`.
|
||||
/// If set the state root check is disabled.
|
||||
#[clap(long)]
|
||||
no_check: bool,
|
||||
no_state_root_check: bool,
|
||||
|
||||
/// Which try-state targets to execute when running this command.
|
||||
///
|
||||
/// Expected values:
|
||||
/// - `all`
|
||||
/// - `none`
|
||||
/// - A comma separated list of pallets, as per pallet names in `construct_runtime!()` (e.g.
|
||||
/// `Staking, System`).
|
||||
/// - `rr-[x]` where `[x]` is a number. Then, the given number of pallets are checked in a
|
||||
/// round-robin fashion.
|
||||
#[clap(long, default_value = "none")]
|
||||
try_state: frame_try_runtime::TryStateSelect,
|
||||
|
||||
/// The block hash at which to fetch the block.
|
||||
///
|
||||
@@ -70,7 +84,7 @@ pub struct ExecuteBlockCmd {
|
||||
}
|
||||
|
||||
impl ExecuteBlockCmd {
|
||||
fn block_at<Block: BlockT>(&self) -> sc_cli::Result<Block::Hash>
|
||||
async fn block_at<Block: BlockT>(&self, ws_uri: String) -> sc_cli::Result<Block::Hash>
|
||||
where
|
||||
Block::Hash: FromStr,
|
||||
<Block::Hash as FromStr>::Err: Debug,
|
||||
@@ -81,6 +95,15 @@ impl ExecuteBlockCmd {
|
||||
log::warn!(target: LOG_TARGET, "--block-at is provided while state type is live. the `Live::at` will be ignored");
|
||||
hash_of::<Block>(block_at)
|
||||
},
|
||||
(None, State::Live { at: None, .. }) => {
|
||||
log::warn!(
|
||||
target: LOG_TARGET,
|
||||
"No --block-at or --at provided, using the latest finalized block instead"
|
||||
);
|
||||
remote_externalities::rpc_api::get_finalized_head::<Block, _>(ws_uri)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
},
|
||||
(None, State::Live { at: Some(at), .. }) => hash_of::<Block>(at),
|
||||
_ => {
|
||||
panic!("either `--block-at` must be provided, or state must be `live with a proper `--at``");
|
||||
@@ -123,13 +146,14 @@ where
|
||||
let executor = build_executor::<ExecDispatch>(&shared, &config);
|
||||
let execution = shared.execution;
|
||||
|
||||
let block_at = command.block_at::<Block>()?;
|
||||
let block_ws_uri = command.block_ws_uri::<Block>();
|
||||
let block_at = command.block_at::<Block>(block_ws_uri.clone()).await?;
|
||||
let block: Block = rpc_api::get_block::<Block, _>(block_ws_uri.clone(), block_at).await?;
|
||||
let parent_hash = block.header().parent_hash();
|
||||
log::info!(
|
||||
target: LOG_TARGET,
|
||||
"fetched block from {:?}, parent_hash to fetch the state {:?}",
|
||||
"fetched block #{:?} from {:?}, parent_hash to fetch the state {:?}",
|
||||
block.header().number(),
|
||||
block_ws_uri,
|
||||
parent_hash
|
||||
);
|
||||
@@ -162,6 +186,7 @@ where
|
||||
let (mut header, extrinsics) = block.deconstruct();
|
||||
header.digest_mut().pop();
|
||||
let block = Block::new(header, extrinsics);
|
||||
let payload = (block.clone(), !command.no_state_root_check, command.try_state).encode();
|
||||
|
||||
let (expected_spec_name, expected_spec_version, _) =
|
||||
local_spec::<Block, ExecDispatch>(&ext, &executor);
|
||||
@@ -177,8 +202,8 @@ where
|
||||
&ext,
|
||||
&executor,
|
||||
execution,
|
||||
if command.no_check { "TryRuntime_execute_block_no_check" } else { "Core_execute_block" },
|
||||
block.encode().as_ref(),
|
||||
"TryRuntime_execute_block",
|
||||
&payload,
|
||||
full_extensions(),
|
||||
)?;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ use jsonrpsee::{
|
||||
core::client::{Subscription, SubscriptionClientT},
|
||||
ws_client::WsClientBuilder,
|
||||
};
|
||||
use parity_scale_codec::Decode;
|
||||
use parity_scale_codec::{Decode, Encode};
|
||||
use remote_externalities::{rpc_api, Builder, Mode, OnlineConfig};
|
||||
use sc_executor::NativeExecutionDispatch;
|
||||
use sc_service::Configuration;
|
||||
@@ -40,6 +40,22 @@ pub struct FollowChainCmd {
|
||||
/// The url to connect to.
|
||||
#[clap(short, long, parse(try_from_str = parse::url))]
|
||||
uri: String,
|
||||
|
||||
/// If set, then the state root check is enabled.
|
||||
#[clap(long)]
|
||||
state_root_check: bool,
|
||||
|
||||
/// Which try-state targets to execute when running this command.
|
||||
///
|
||||
/// Expected values:
|
||||
/// - `all`
|
||||
/// - `none`
|
||||
/// - A comma separated list of pallets, as per pallet names in `construct_runtime!()` (e.g.
|
||||
/// `Staking, System`).
|
||||
/// - `rr-[x]` where `[x]` is a number. Then, the given number of pallets are checked in a
|
||||
/// round-robin fashion.
|
||||
#[clap(long, default_value = "none")]
|
||||
try_state: frame_try_runtime::TryStateSelect,
|
||||
}
|
||||
|
||||
pub(crate) async fn follow_chain<Block, ExecDispatch>(
|
||||
@@ -141,8 +157,8 @@ where
|
||||
state_ext,
|
||||
&executor,
|
||||
execution,
|
||||
"TryRuntime_execute_block_no_check",
|
||||
block.encode().as_ref(),
|
||||
"TryRuntime_execute_block",
|
||||
(block, command.state_root_check, command.try_state.clone()).encode().as_ref(),
|
||||
full_extensions(),
|
||||
)?;
|
||||
|
||||
|
||||
@@ -335,17 +335,18 @@ pub enum Command {
|
||||
/// different state transition function.
|
||||
///
|
||||
/// To make testing slightly more dynamic, you can disable the state root check by enabling
|
||||
/// `ExecuteBlockCmd::no_check`. If you get signature verification errors, you should
|
||||
/// manually tweak your local runtime's spec version to fix this.
|
||||
/// `ExecuteBlockCmd::no_check`. If you get signature verification errors, you should manually
|
||||
/// tweak your local runtime's spec version to fix this.
|
||||
///
|
||||
/// A subtle detail of execute block is that if you want to execute block 100 of a live chain
|
||||
/// again, you need to scrape the state of block 99. This is already done automatically if you
|
||||
/// use [`State::Live`], and the parent hash of the target block is used to scrape the state.
|
||||
/// If [`State::Snap`] is being used, then this needs to be manually taken into consideration.
|
||||
///
|
||||
/// This executes the same runtime api as normal block import, namely `Core_execute_block`. If
|
||||
/// `ExecuteBlockCmd::no_check` is set, it uses a custom, try-runtime-only runtime
|
||||
/// api called `TryRuntime_execute_block_no_check`.
|
||||
/// This does not execute the same runtime api as normal block import do, namely
|
||||
/// `Core_execute_block`. Instead, it uses `TryRuntime_execute_block`, which can optionally
|
||||
/// skip state-root check (useful for trying a unreleased runtime), and can execute runtime
|
||||
/// sanity checks as well.
|
||||
ExecuteBlock(commands::execute_block::ExecuteBlockCmd),
|
||||
|
||||
/// Executes *the offchain worker hooks* of a given block against some state.
|
||||
@@ -656,21 +657,27 @@ pub(crate) async fn ensure_matching_spec<Block: BlockT + serde::de::DeserializeO
|
||||
if expected_spec_version == version {
|
||||
log::info!(target: LOG_TARGET, "found matching spec version: {:?}", version);
|
||||
} else {
|
||||
log::warn!(
|
||||
target: LOG_TARGET,
|
||||
let msg = format!(
|
||||
"spec version mismatch (local {} != remote {}). This could cause some issues.",
|
||||
expected_spec_version,
|
||||
version
|
||||
expected_spec_version, version
|
||||
);
|
||||
if relaxed {
|
||||
log::warn!(target: LOG_TARGET, "{}", msg);
|
||||
} else {
|
||||
panic!("{}", msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(why) => {
|
||||
log::error!(
|
||||
target: LOG_TARGET,
|
||||
let msg = format!(
|
||||
"failed to fetch runtime version from {}: {:?}. Skipping the check",
|
||||
uri,
|
||||
why
|
||||
uri, why
|
||||
);
|
||||
if relaxed {
|
||||
log::error!(target: LOG_TARGET, "{}", msg);
|
||||
} else {
|
||||
panic!("{}", msg);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -801,15 +808,15 @@ pub(crate) fn state_machine_call_with_proof<Block: BlockT, D: NativeExecutionDis
|
||||
)
|
||||
}
|
||||
};
|
||||
log::info!(
|
||||
log::debug!(
|
||||
target: LOG_TARGET,
|
||||
"proof: {} / {} nodes",
|
||||
HexDisplay::from(&proof_nodes.iter().flatten().cloned().collect::<Vec<_>>()),
|
||||
proof_nodes.len()
|
||||
);
|
||||
log::info!(target: LOG_TARGET, "proof size: {}", humanize(proof_size));
|
||||
log::info!(target: LOG_TARGET, "compact proof size: {}", humanize(compact_proof_size),);
|
||||
log::info!(
|
||||
log::debug!(target: LOG_TARGET, "proof size: {}", humanize(proof_size));
|
||||
log::debug!(target: LOG_TARGET, "compact proof size: {}", humanize(compact_proof_size),);
|
||||
log::debug!(
|
||||
target: LOG_TARGET,
|
||||
"zstd-compressed compact proof {}",
|
||||
humanize(compressed_proof.len()),
|
||||
|
||||
Reference in New Issue
Block a user