try_runtime_core/commands/
offchain_worker.rs

1// This file is part of try-runtime-cli.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use 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/// Configuration for [`run`].
34#[derive(Debug, Clone, clap::Parser)]
35pub struct Command {
36    /// The ws uri from which to fetch the header.
37    ///
38    /// If the `live` state type is being used, then this can be omitted, and is equal to whatever
39    /// the `state::uri` is. Only use this (with care) when combined with a snapshot.
40    #[arg(
41		long,
42		value_parser = parse::url
43	)]
44    pub header_ws_uri: Option<String>,
45
46    /// The state type to use.
47    #[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
67// Runs the `offchain_worker` command.
68pub 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    // The block we want to *execute* at is the block passed by the user
89    let execute_at = live_state.at::<Block>()?;
90
91    // Get state for the prev block
92    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}