Add block transition to cli_util
This commit is contained in:
parent
e1d6e187d1
commit
cce76f0bd2
@ -13,3 +13,5 @@ serde = "1.0"
|
|||||||
serde_yaml = "0.8"
|
serde_yaml = "0.8"
|
||||||
simple_logger = "1.0"
|
simple_logger = "1.0"
|
||||||
types = { path = "../../eth2/types" }
|
types = { path = "../../eth2/types" }
|
||||||
|
state_processing = { path = "../../eth2/state_processing" }
|
||||||
|
eth2_ssz = { path = "../../eth2/utils/ssz" }
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
|
mod transition_blocks;
|
||||||
|
|
||||||
use clap::{App, Arg, SubCommand};
|
use clap::{App, Arg, SubCommand};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
use transition_blocks::run_transition_blocks;
|
||||||
use types::{test_utils::TestingBeaconStateBuilder, EthSpec, MainnetEthSpec, MinimalEthSpec};
|
use types::{test_utils::TestingBeaconStateBuilder, EthSpec, MainnetEthSpec, MinimalEthSpec};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -54,47 +57,78 @@ fn main() {
|
|||||||
.help("Output file for generated state."),
|
.help("Output file for generated state."),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.subcommand(
|
||||||
|
SubCommand::with_name("transition-blocks")
|
||||||
|
.about("Performs a state transition given a pre-state and block")
|
||||||
|
.version("0.1.0")
|
||||||
|
.author("Paul Hauner <paul@sigmaprime.io>")
|
||||||
|
.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("block")
|
||||||
|
.value_name("BEACON_BLOCK")
|
||||||
|
.takes_value(true)
|
||||||
|
.required(true)
|
||||||
|
.help("Path to a SSZ file of the block to apply to pre-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."),
|
||||||
|
),
|
||||||
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("genesis_yaml") {
|
match matches.subcommand() {
|
||||||
let num_validators = matches
|
("genesis_yaml", Some(matches)) => {
|
||||||
.value_of("num_validators")
|
let num_validators = matches
|
||||||
.expect("slog requires num_validators")
|
.value_of("num_validators")
|
||||||
.parse::<usize>()
|
.expect("slog requires num_validators")
|
||||||
.expect("num_validators must be a valid integer");
|
.parse::<usize>()
|
||||||
|
.expect("num_validators must be a valid integer");
|
||||||
|
|
||||||
let genesis_time = if let Some(string) = matches.value_of("genesis_time") {
|
let genesis_time = if let Some(string) = matches.value_of("genesis_time") {
|
||||||
string
|
string
|
||||||
.parse::<u64>()
|
.parse::<u64>()
|
||||||
.expect("genesis_time must be a valid integer")
|
.expect("genesis_time must be a valid integer")
|
||||||
} else {
|
} else {
|
||||||
warn!("No genesis time supplied via CLI, using the current time.");
|
warn!("No genesis time supplied via CLI, using the current time.");
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(UNIX_EPOCH)
|
.duration_since(UNIX_EPOCH)
|
||||||
.expect("should obtain time since unix epoch")
|
.expect("should obtain time since unix epoch")
|
||||||
.as_secs()
|
.as_secs()
|
||||||
};
|
};
|
||||||
|
|
||||||
let file = matches
|
let file = matches
|
||||||
.value_of("output_file")
|
.value_of("output_file")
|
||||||
.expect("slog requires output file")
|
.expect("slog requires output file")
|
||||||
.parse::<PathBuf>()
|
.parse::<PathBuf>()
|
||||||
.expect("output_file must be a valid path");
|
.expect("output_file must be a valid path");
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Creating genesis state with {} validators and genesis time {}.",
|
"Creating genesis state with {} validators and genesis time {}.",
|
||||||
num_validators, genesis_time
|
num_validators, genesis_time
|
||||||
);
|
);
|
||||||
|
|
||||||
match matches.value_of("spec").expect("spec is required by slog") {
|
match matches.value_of("spec").expect("spec is required by slog") {
|
||||||
"minimal" => genesis_yaml::<MinimalEthSpec>(num_validators, genesis_time, file),
|
"minimal" => genesis_yaml::<MinimalEthSpec>(num_validators, genesis_time, file),
|
||||||
"mainnet" => genesis_yaml::<MainnetEthSpec>(num_validators, genesis_time, file),
|
"mainnet" => genesis_yaml::<MainnetEthSpec>(num_validators, genesis_time, file),
|
||||||
_ => unreachable!("guarded by slog possible_values"),
|
_ => unreachable!("guarded by slog possible_values"),
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("Genesis state YAML file created. Exiting successfully.");
|
info!("Genesis state YAML file created. Exiting successfully.");
|
||||||
} else {
|
}
|
||||||
error!("No subcommand supplied.")
|
("transition-blocks", Some(matches)) => run_transition_blocks(matches)
|
||||||
|
.unwrap_or_else(|e| error!("Failed to transition blocks: {}", e)),
|
||||||
|
(other, _) => error!("Unknown subcommand supplied: {}", other),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
93
tests/cli_util/src/transition_blocks.rs
Normal file
93
tests/cli_util/src/transition_blocks.rs
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
use clap::ArgMatches;
|
||||||
|
use ssz::{Decode, Encode};
|
||||||
|
use state_processing::{per_block_processing, per_slot_processing, BlockSignatureStrategy};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use types::{BeaconBlock, BeaconState, EthSpec, MinimalEthSpec};
|
||||||
|
|
||||||
|
pub fn run_transition_blocks(matches: &ArgMatches) -> Result<(), String> {
|
||||||
|
let pre_state_path = matches
|
||||||
|
.value_of("pre-state")
|
||||||
|
.ok_or_else(|| "No pre-state file supplied".to_string())?
|
||||||
|
.parse::<PathBuf>()
|
||||||
|
.map_err(|e| format!("Failed to parse pre-state path: {}", e))?;
|
||||||
|
|
||||||
|
let block_path = matches
|
||||||
|
.value_of("block")
|
||||||
|
.ok_or_else(|| "No block file supplied".to_string())?
|
||||||
|
.parse::<PathBuf>()
|
||||||
|
.map_err(|e| format!("Failed to parse block path: {}", e))?;
|
||||||
|
|
||||||
|
let output_path = matches
|
||||||
|
.value_of("output")
|
||||||
|
.ok_or_else(|| "No output file supplied".to_string())?
|
||||||
|
.parse::<PathBuf>()
|
||||||
|
.map_err(|e| format!("Failed to parse output path: {}", e))?;
|
||||||
|
|
||||||
|
info!("Using minimal spec");
|
||||||
|
info!("Pre-state path: {:?}", pre_state_path);
|
||||||
|
info!("Block path: {:?}", block_path);
|
||||||
|
|
||||||
|
let pre_state: BeaconState<MinimalEthSpec> = load_from_ssz(pre_state_path)?;
|
||||||
|
let block: BeaconBlock<MinimalEthSpec> = load_from_ssz(block_path)?;
|
||||||
|
|
||||||
|
let post_state = do_transition(pre_state, block)?;
|
||||||
|
|
||||||
|
let mut output_file = File::create(output_path.clone())
|
||||||
|
.map_err(|e| format!("Unable to create output file: {:?}", e))?;
|
||||||
|
|
||||||
|
output_file
|
||||||
|
.write_all(&post_state.as_ssz_bytes())
|
||||||
|
.map_err(|e| format!("Unable to write to output file: {:?}", e))?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
serde_yaml::to_string(&post_state).expect("Should serialize state")
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_transition<T: EthSpec>(
|
||||||
|
mut pre_state: BeaconState<T>,
|
||||||
|
block: BeaconBlock<T>,
|
||||||
|
) -> Result<BeaconState<T>, String> {
|
||||||
|
let spec = &T::default_spec();
|
||||||
|
|
||||||
|
pre_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 pre_state.slot.as_u64()..block.slot.as_u64() {
|
||||||
|
per_slot_processing(&mut pre_state, spec)
|
||||||
|
.map_err(|e| format!("Failed to advance slot on iteration {}: {:?}", i, e))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre_state
|
||||||
|
.build_all_caches(spec)
|
||||||
|
.map_err(|e| format!("Unable to build caches: {:?}", e))?;
|
||||||
|
|
||||||
|
per_block_processing(
|
||||||
|
&mut pre_state,
|
||||||
|
&block,
|
||||||
|
None,
|
||||||
|
BlockSignatureStrategy::VerifyIndividual,
|
||||||
|
spec,
|
||||||
|
)
|
||||||
|
.map_err(|e| format!("State transition failed: {:?}", e))?;
|
||||||
|
|
||||||
|
Ok(pre_state)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_from_ssz<T: Decode>(path: PathBuf) -> Result<T, String> {
|
||||||
|
let mut file =
|
||||||
|
File::open(path.clone()).map_err(|e| format!("Unable to open file {:?}: {:?}", path, e))?;
|
||||||
|
let mut bytes = vec![];
|
||||||
|
file.read_to_end(&mut bytes)
|
||||||
|
.map_err(|e| format!("Unable to read from file {:?}: {:?}", path, e))?;
|
||||||
|
T::from_ssz_bytes(&bytes).map_err(|e| format!("Ssz decode failed: {:?}", e))
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user