use std::{fmt::Debug, str::FromStr};
use sc_executor::sp_wasm_interface::HostFunctions;
use sp_runtime::traits::{Block as BlockT, NumberFor};
use substrate_rpc_client::{ws_client, StateApi};
use crate::{
common::{
shared_parameters,
state::{build_executor, LiveState, RuntimeChecks, State},
},
SharedParams, LOG_TARGET,
};
#[derive(Debug, Clone, clap::Parser)]
pub struct Command {
#[clap(flatten)]
pub from: LiveState,
#[clap(index = 1)]
pub snapshot_path: Option<String>,
}
pub async fn run<Block, HostFns>(shared: SharedParams, command: Command) -> sc_cli::Result<()>
where
Block: BlockT + serde::de::DeserializeOwned,
Block::Hash: serde::de::DeserializeOwned,
Block::Header: serde::de::DeserializeOwned,
<Block::Hash as FromStr>::Err: Debug,
NumberFor<Block>: FromStr,
<NumberFor<Block> as FromStr>::Err: Debug,
HostFns: HostFunctions,
{
let snapshot_path = command.snapshot_path;
if !matches!(shared.runtime, shared_parameters::Runtime::Existing) {
return Err("creating a snapshot is only possible with --runtime existing.".into());
}
let path = match snapshot_path {
Some(path) => path,
None => {
let rpc = ws_client(&command.from.uri).await.unwrap();
let remote_spec = StateApi::<Block::Hash>::runtime_version(&rpc, None)
.await
.unwrap();
let path_str = format!(
"{}-{}@{}.snap",
remote_spec.spec_name.to_lowercase(),
remote_spec.spec_version,
command.from.at.clone().unwrap_or("latest".to_owned())
);
log::info!(target: LOG_TARGET, "snapshot path not provided (-s), using '{}'", path_str);
path_str
}
};
let executor = build_executor::<HostFns>(&shared);
let runtime_checks = RuntimeChecks {
name_matches: false,
version_increases: false,
try_runtime_feature_enabled: false,
};
let _ = State::Live(command.from)
.to_ext::<Block, HostFns>(&shared, &executor, Some(path.into()), runtime_checks)
.await?;
Ok(())
}