diff --git a/lcli/src/main.rs b/lcli/src/main.rs index f4cd748f2..99621c1b1 100644 --- a/lcli/src/main.rs +++ b/lcli/src/main.rs @@ -10,6 +10,7 @@ mod interop_genesis; mod new_testnet; mod parse_hex; mod refund_deposit_contract; +mod skip_slots; mod transition_blocks; use clap::{App, Arg, ArgMatches, SubCommand}; @@ -77,6 +78,32 @@ fn main() { .help("Output file for generated state."), ), ) + .subcommand( + SubCommand::with_name("skip-slots") + .about("Performs a state transition from some state across some number of skip slots") + .arg( + Arg::with_name("pre-state") + .value_name("BEACON_STATE") + .takes_value(true) + .required(true) + .help("Path to a SSZ file of the pre-state."), + ) + .arg( + Arg::with_name("slots") + .value_name("SLOT_COUNT") + .takes_value(true) + .required(true) + .help("Number of slots to skip before outputting a state.."), + ) + .arg( + Arg::with_name("output") + .value_name("SSZ_FILE") + .takes_value(true) + .required(true) + .default_value("./output.ssz") + .help("Path to output a SSZ file."), + ), + ) .subcommand( SubCommand::with_name("transition-blocks") .about("Performs a state transition given a pre-state and block") @@ -488,6 +515,9 @@ fn run(env_builder: EnvironmentBuilder, matches: &ArgMatches) -> } ("transition-blocks", Some(matches)) => run_transition_blocks::(matches) .map_err(|e| format!("Failed to transition blocks: {}", e)), + ("skip-slots", Some(matches)) => { + skip_slots::run::(matches).map_err(|e| format!("Failed to skip slots: {}", e)) + } ("pretty-hex", Some(matches)) => { run_parse_hex::(matches).map_err(|e| format!("Failed to pretty print hex: {}", e)) } diff --git a/lcli/src/skip_slots.rs b/lcli/src/skip_slots.rs new file mode 100644 index 000000000..92cd48262 --- /dev/null +++ b/lcli/src/skip_slots.rs @@ -0,0 +1,55 @@ +use crate::transition_blocks::load_from_ssz; +use clap::ArgMatches; +use ssz::Encode; +use state_processing::per_slot_processing; +use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; +use types::{BeaconState, EthSpec}; + +pub fn run(matches: &ArgMatches) -> Result<(), String> { + let pre_state_path = matches + .value_of("pre-state") + .ok_or_else(|| "No pre-state file supplied".to_string())? + .parse::() + .map_err(|e| format!("Failed to parse pre-state path: {}", e))?; + + let slots = matches + .value_of("slots") + .ok_or_else(|| "No slots supplied".to_string())? + .parse::() + .map_err(|e| format!("Failed to parse slots: {}", e))?; + + let output_path = matches + .value_of("output") + .ok_or_else(|| "No output file supplied".to_string())? + .parse::() + .map_err(|e| format!("Failed to parse output path: {}", e))?; + + info!("Using minimal spec"); + info!("Pre-state path: {:?}", pre_state_path); + info!("Slots: {:?}", slots); + + let mut state: BeaconState = load_from_ssz(pre_state_path)?; + + let spec = &T::default_spec(); + + state + .build_all_caches(spec) + .map_err(|e| format!("Unable to build caches: {:?}", e))?; + + // Transition the parent state to the block slot. + for i in 0..slots { + per_slot_processing(&mut state, None, spec) + .map_err(|e| format!("Failed to advance slot on iteration {}: {:?}", i, e))?; + } + + let mut output_file = + File::create(output_path).map_err(|e| format!("Unable to create output file: {:?}", e))?; + + output_file + .write_all(&state.as_ssz_bytes()) + .map_err(|e| format!("Unable to write to output file: {:?}", e))?; + + Ok(()) +} diff --git a/lcli/src/transition_blocks.rs b/lcli/src/transition_blocks.rs index 6a13f7ce1..28e4b0657 100644 --- a/lcli/src/transition_blocks.rs +++ b/lcli/src/transition_blocks.rs @@ -76,7 +76,7 @@ fn do_transition( Ok(pre_state) } -fn load_from_ssz(path: PathBuf) -> Result { +pub fn load_from_ssz(path: PathBuf) -> Result { let mut file = File::open(path.clone()).map_err(|e| format!("Unable to open file {:?}: {:?}", path, e))?; let mut bytes = vec![];