try_runtime_core/commands/
offchain_worker.rs1use std::{fmt::Debug, str::FromStr};
19
20use parity_scale_codec::Encode;
21use sc_executor::sp_wasm_interface::HostFunctions;
22use sp_runtime::traits::{Block as BlockT, NumberFor};
23use substrate_rpc_client::{ws_client, ChainApi};
24
25use crate::{
26 common::{
27 parse,
28 state::{build_executor, state_machine_call, LiveState, RuntimeChecks, State},
29 },
30 full_extensions, rpc_err_handler, SharedParams, LOG_TARGET,
31};
32
33#[derive(Debug, Clone, clap::Parser)]
35pub struct Command {
36 #[arg(
41 long,
42 value_parser = parse::url
43 )]
44 pub header_ws_uri: Option<String>,
45
46 #[command(subcommand)]
48 pub state: State,
49}
50
51impl Command {
52 fn header_ws_uri(&self) -> String {
53 match (&self.header_ws_uri, &self.state) {
54 (Some(header_ws_uri), State::Snap { .. }) => header_ws_uri.to_owned(),
55 (Some(header_ws_uri), State::Live { .. }) => {
56 log::error!(target: LOG_TARGET, "--header-uri is provided while state type is live, this will most likely lead to a nonsensical result.");
57 header_ws_uri.to_owned()
58 }
59 (None, State::Live(LiveState { uri, .. })) => uri.clone(),
60 (None, State::Snap { .. }) => {
61 panic!("either `--header-uri` must be provided, or state must be `live`");
62 }
63 }
64 }
65}
66
67pub async fn run<Block, HostFns>(shared: SharedParams, command: Command) -> sc_cli::Result<()>
69where
70 Block: BlockT + serde::de::DeserializeOwned,
71 Block::Header: serde::de::DeserializeOwned,
72 <Block::Hash as FromStr>::Err: Debug,
73 NumberFor<Block>: FromStr,
74 <NumberFor<Block> as FromStr>::Err: Debug,
75 HostFns: HostFunctions,
76{
77 let executor = build_executor(&shared);
78 let block_ws_uri = command.header_ws_uri();
79 let rpc = ws_client(&block_ws_uri).await?;
80
81 let live_state = match command.state {
82 State::Live(live_state) => live_state,
83 _ => {
84 unreachable!("execute block currently only supports Live state")
85 }
86 };
87
88 let execute_at = live_state.at::<Block>()?;
90
91 let prev_block_live_state = live_state.to_prev_block_live_state::<Block>().await?;
93 let runtime_checks = RuntimeChecks {
94 name_matches: !shared.disable_spec_name_check,
95 version_increases: false,
96 try_runtime_feature_enabled: true,
97 };
98 let ext = State::Live(prev_block_live_state)
99 .to_ext::<Block, HostFns>(&shared, &executor, None, runtime_checks)
100 .await?;
101
102 let header = ChainApi::<(), Block::Hash, Block::Header, ()>::header(&rpc, execute_at)
103 .await
104 .map_err(rpc_err_handler)
105 .map(|maybe_header| maybe_header.ok_or("Header does not exist"))??;
106 let payload = header.encode();
107
108 let _ = state_machine_call::<Block, HostFns>(
109 &ext,
110 &executor,
111 "OffchainWorkerApi_offchain_worker",
112 &payload,
113 full_extensions(executor.clone()),
114 )?;
115
116 log::info!(target: LOG_TARGET, "finished execution");
117 Ok(())
118}