try_runtime_core/commands/
execute_block.rs1use std::{fmt::Debug, str::FromStr};
19
20use parity_scale_codec::Encode;
21use sc_executor::sp_wasm_interface::HostFunctions;
22use sp_runtime::{
23 generic::SignedBlock,
24 traits::{Block as BlockT, Header as HeaderT, NumberFor},
25};
26use substrate_rpc_client::{ws_client, ChainApi};
27
28use crate::{
29 common::state::{
30 build_executor, state_machine_call_with_proof, LiveState, RuntimeChecks, State,
31 },
32 full_extensions, rpc_err_handler, SharedParams, LOG_TARGET,
33};
34
35#[derive(Debug, Clone, clap::Parser)]
40pub struct Command {
41 #[arg(long, default_value = "all")]
51 pub try_state: frame_try_runtime::TryStateSelect,
52
53 #[arg(
61 long,
62 value_parser = crate::common::parse::url
63 )]
64 pub block_ws_uri: Option<String>,
65
66 #[command(subcommand)]
68 pub state: State,
69}
70
71impl Command {
72 fn block_ws_uri(&self) -> String {
73 match (&self.block_ws_uri, &self.state) {
74 (Some(block_ws_uri), State::Snap { .. }) => block_ws_uri.to_owned(),
75 (Some(block_ws_uri), State::Live { .. }) => {
76 log::error!(target: LOG_TARGET, "--block-uri is provided while state type is live, Are you sure you know what you are doing?");
77 block_ws_uri.to_owned()
78 }
79 (None, State::Live(LiveState { uri, .. })) => uri.clone(),
80 (None, State::Snap { .. }) => {
81 panic!("either `--block-uri` must be provided, or state must be `live`");
82 }
83 }
84 }
85}
86
87pub async fn run<Block, HostFns>(shared: SharedParams, command: Command) -> sc_cli::Result<()>
89where
90 Block: BlockT + serde::de::DeserializeOwned,
91 <Block::Hash as FromStr>::Err: Debug,
92 Block::Hash: serde::de::DeserializeOwned,
93 Block::Header: serde::de::DeserializeOwned,
94 <NumberFor<Block> as TryInto<u64>>::Error: Debug,
95 HostFns: HostFunctions,
96{
97 let executor = build_executor::<HostFns>(&shared);
98 let block_ws_uri = command.block_ws_uri();
99 let rpc = ws_client(&block_ws_uri).await?;
100
101 let live_state = match command.state {
102 State::Live(live_state) => {
103 if live_state.at.is_some() {
105 live_state
106 } else {
107 let header =
108 ChainApi::<(), Block::Hash, Block::Header, SignedBlock<Block>>::header(
109 &rpc, None,
110 )
111 .await
112 .map_err(rpc_err_handler)?
113 .expect("header exists, block should also exist; qed");
114 LiveState {
115 uri: block_ws_uri,
116 at: Some(hex::encode(header.hash().encode())),
117 pallet: Default::default(),
118 hashed_prefixes: Default::default(),
119 child_tree: Default::default(),
120 }
121 }
122 }
123 _ => {
124 unreachable!("execute block currently only supports Live state")
125 }
126 };
127
128 let execute_at = live_state.at::<Block>()?;
130
131 let prev_block_live_state = live_state.to_prev_block_live_state::<Block>().await?;
132
133 let runtime_checks = RuntimeChecks {
135 name_matches: !shared.disable_spec_name_check,
136 version_increases: false,
137 try_runtime_feature_enabled: true,
138 };
139 let ext = State::Live(prev_block_live_state)
140 .to_ext::<Block, HostFns>(&shared, &executor, None, runtime_checks)
141 .await?;
142
143 let block =
145 ChainApi::<(), Block::Hash, Block::Header, SignedBlock<Block>>::block(&rpc, execute_at)
146 .await
147 .map_err(rpc_err_handler)?
148 .expect("header exists, block should also exist; qed")
149 .block;
150
151 let (mut header, extrinsics) = block.deconstruct();
154 header.digest_mut().pop();
155 let block = Block::new(header, extrinsics);
156
157 let state_root_check = false;
159 let signature_check = false;
160 let payload = (
161 block.clone(),
162 state_root_check,
163 signature_check,
164 command.try_state,
165 )
166 .encode();
167
168 let _ = state_machine_call_with_proof::<Block, HostFns>(
169 &ext,
170 &mut Default::default(),
171 &executor,
172 "TryRuntime_execute_block",
173 &payload,
174 full_extensions(executor.clone()),
175 shared.export_proof,
176 )?;
177
178 Ok(())
179}