Altair consensus changes and refactors (#2279)

## Proposed Changes

Implement the consensus changes necessary for the upcoming Altair hard fork.

## Additional Info

This is quite a heavy refactor, with pivotal types like the `BeaconState` and `BeaconBlock` changing from structs to enums. This ripples through the whole codebase with field accesses changing to methods, e.g. `state.slot` => `state.slot()`.


Co-authored-by: realbigsean <seananderson33@gmail.com>
This commit is contained in:
Michael Sproul
2021-07-09 06:15:32 +00:00
parent 89361573d4
commit b4689e20c6
271 changed files with 9652 additions and 8444 deletions

View File

@@ -1,11 +1,12 @@
use clap::ArgMatches;
use ssz::{Decode, Encode};
use eth2_network_config::Eth2NetworkConfig;
use ssz::Encode;
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use types::{BeaconState, EthSpec};
pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
pub fn run<T: EthSpec>(testnet_dir: PathBuf, matches: &ArgMatches) -> Result<(), String> {
let path = matches
.value_of("ssz-state")
.ok_or("ssz-state not specified")?
@@ -18,6 +19,9 @@ pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
.parse::<u64>()
.map_err(|e| format!("Unable to parse genesis-time: {}", e))?;
let eth2_network_config = Eth2NetworkConfig::load(testnet_dir)?;
let spec = &eth2_network_config.chain_spec::<T>()?;
let mut state: BeaconState<T> = {
let mut file = File::open(&path).map_err(|e| format!("Unable to open file: {}", e))?;
@@ -26,10 +30,11 @@ pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
file.read_to_end(&mut ssz)
.map_err(|e| format!("Unable to read file: {}", e))?;
BeaconState::from_ssz_bytes(&ssz).map_err(|e| format!("Unable to decode SSZ: {:?}", e))?
BeaconState::from_ssz_bytes(&ssz, spec)
.map_err(|e| format!("Unable to decode SSZ: {:?}", e))?
};
state.genesis_time = genesis_time;
*state.genesis_time_mut() = genesis_time;
let mut file = File::create(path).map_err(|e| format!("Unable to create file: {}", e))?;

View File

@@ -12,7 +12,11 @@ use types::EthSpec;
/// Interval between polling the eth1 node for genesis information.
pub const ETH1_GENESIS_UPDATE_INTERVAL: Duration = Duration::from_millis(7_000);
pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches<'_>) -> Result<(), String> {
pub fn run<T: EthSpec>(
mut env: Environment<T>,
testnet_dir: PathBuf,
matches: &ArgMatches<'_>,
) -> Result<(), String> {
let endpoints = matches
.value_of("eth1-endpoint")
.map(|e| {
@@ -25,29 +29,9 @@ pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches<'_>) -> Res
.map(|s| s.split(',').map(String::from).collect())
});
let testnet_dir = matches
.value_of("testnet-dir")
.ok_or(())
.and_then(|dir| dir.parse::<PathBuf>().map_err(|_| ()))
.unwrap_or_else(|_| {
dirs::home_dir()
.map(|home| home.join(directory::DEFAULT_ROOT_DIR).join("testnet"))
.expect("should locate home directory")
});
let mut eth2_network_config = Eth2NetworkConfig::load(testnet_dir.clone())?;
let spec = eth2_network_config
.yaml_config
.as_ref()
.ok_or("The testnet directory must contain a spec config")?
.apply_to_chain_spec::<T>(&env.core_context().eth2_config.spec)
.ok_or_else(|| {
format!(
"The loaded config is not compatible with the {} spec",
&env.core_context().eth2_config.eth_spec_id
)
})?;
let spec = eth2_network_config.chain_spec::<T>()?;
let mut config = Eth1Config::default();
if let Some(v) = endpoints.clone() {

View File

@@ -1,106 +0,0 @@
use clap::ArgMatches;
use hex;
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};
use types::Address;
pub fn time_now() -> Result<u64, String> {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|duration| duration.as_secs())
.map_err(|e| format!("Unable to get time: {:?}", e))
}
pub fn parse_path_with_default_in_home_dir(
matches: &ArgMatches,
name: &'static str,
default: PathBuf,
) -> Result<PathBuf, String> {
matches
.value_of(name)
.map(|dir| {
dir.parse::<PathBuf>()
.map_err(|e| format!("Unable to parse {}: {}", name, e))
})
.unwrap_or_else(|| {
dirs::home_dir()
.map(|home| home.join(default))
.ok_or_else(|| format!("Unable to locate home directory. Try specifying {}", name))
})
}
pub fn parse_path(matches: &ArgMatches, name: &'static str) -> Result<PathBuf, String> {
matches
.value_of(name)
.ok_or_else(|| format!("{} not specified", name))?
.parse::<PathBuf>()
.map_err(|e| format!("Unable to parse {}: {}", name, e))
}
pub fn parse_u64(matches: &ArgMatches, name: &'static str) -> Result<u64, String> {
matches
.value_of(name)
.ok_or_else(|| format!("{} not specified", name))?
.parse::<u64>()
.map_err(|e| format!("Unable to parse {}: {}", name, e))
}
pub fn parse_u64_opt(matches: &ArgMatches, name: &'static str) -> Result<Option<u64>, String> {
matches
.value_of(name)
.map(|val| {
val.parse::<u64>()
.map_err(|e| format!("Unable to parse {}: {}", name, e))
})
.transpose()
}
pub fn parse_address(matches: &ArgMatches, name: &'static str) -> Result<Address, String> {
matches
.value_of(name)
.ok_or_else(|| format!("{} not specified", name))
.and_then(|val| {
if val.starts_with("0x") {
val[2..]
.parse()
.map_err(|e| format!("Unable to parse {}: {:?}", name, e))
} else {
Err(format!("Unable to parse {}, must have 0x prefix", name))
}
})
}
pub fn parse_fork_opt(matches: &ArgMatches, name: &'static str) -> Result<Option<[u8; 4]>, String> {
matches
.value_of(name)
.map(|val| {
if val.starts_with("0x") {
let vec = hex::decode(&val[2..])
.map_err(|e| format!("Unable to parse {} as hex: {:?}", name, e))?;
if vec.len() != 4 {
Err(format!("{} must be exactly 4 bytes", name))
} else {
let mut arr = [0; 4];
arr.copy_from_slice(&vec);
Ok(arr)
}
} else {
Err(format!("Unable to parse {}, must have 0x prefix", name))
}
})
.transpose()
}
pub fn parse_hex_bytes(matches: &ArgMatches, name: &'static str) -> Result<Vec<u8>, String> {
matches
.value_of(name)
.ok_or_else(|| format!("{} not specified", name))
.and_then(|val| {
if val.starts_with("0x") {
hex::decode(&val[2..]).map_err(|e| format!("Unable to parse {}: {:?}", name, e))
} else {
Err(format!("Unable to parse {}, must have 0x prefix", name))
}
})
}

View File

@@ -1,6 +1,5 @@
use clap::ArgMatches;
use clap_utils::parse_ssz_optional;
use environment::Environment;
use eth2_network_config::Eth2NetworkConfig;
use genesis::interop_genesis_state;
use ssz::Encode;
@@ -8,7 +7,7 @@ use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};
use types::{test_utils::generate_deterministic_keypairs, EthSpec};
pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches) -> Result<(), String> {
pub fn run<T: EthSpec>(testnet_dir: PathBuf, matches: &ArgMatches) -> Result<(), String> {
let validator_count = matches
.value_of("validator-count")
.ok_or("validator-count not specified")?
@@ -26,29 +25,9 @@ pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches) -> Result<
.as_secs()
};
let testnet_dir = matches
.value_of("testnet-dir")
.ok_or(())
.and_then(|dir| dir.parse::<PathBuf>().map_err(|_| ()))
.unwrap_or_else(|_| {
dirs::home_dir()
.map(|home| home.join(directory::DEFAULT_ROOT_DIR).join("testnet"))
.expect("should locate home directory")
});
let mut eth2_network_config = Eth2NetworkConfig::load(testnet_dir.clone())?;
let mut spec = eth2_network_config
.yaml_config
.as_ref()
.ok_or("The testnet directory must contain a spec config")?
.apply_to_chain_spec::<T>(&env.core_context().eth2_config.spec)
.ok_or_else(|| {
format!(
"The loaded config is not compatible with the {} spec",
&env.core_context().eth2_config.eth_spec_id
)
})?;
let mut spec = eth2_network_config.chain_spec::<T>()?;
if let Some(v) = parse_ssz_optional(matches, "genesis-fork-version")? {
spec.genesis_fork_version = v;

View File

@@ -8,24 +8,21 @@ mod generate_bootnode_enr;
mod insecure_validators;
mod interop_genesis;
mod new_testnet;
mod parse_hex;
mod parse_ssz;
mod replace_state_pubkeys;
mod skip_slots;
mod transition_blocks;
use clap::{App, Arg, ArgMatches, SubCommand};
use clap_utils::parse_path_with_default_in_home_dir;
use environment::EnvironmentBuilder;
use log::LevelFilter;
use parse_hex::run_parse_hex;
use std::fs::File;
use parse_ssz::run_parse_ssz;
use std::path::PathBuf;
use std::process;
use std::str::FromStr;
use std::time::{SystemTime, UNIX_EPOCH};
use transition_blocks::run_transition_blocks;
use types::{
test_utils::TestingBeaconStateBuilder, EthSpec, EthSpecId, MainnetEthSpec, MinimalEthSpec,
};
use types::{EthSpec, EthSpecId};
fn main() {
simple_logger::SimpleLogger::new()
@@ -55,34 +52,6 @@ fn main() {
.global(true)
.help("The testnet dir. Defaults to ~/.lighthouse/testnet"),
)
.subcommand(
SubCommand::with_name("genesis_yaml")
.about("Generates a genesis YAML file")
.arg(
Arg::with_name("num_validators")
.short("n")
.value_name("INTEGER")
.takes_value(true)
.required(true)
.help("Number of initial validators."),
)
.arg(
Arg::with_name("genesis_time")
.short("g")
.value_name("INTEGER")
.takes_value(true)
.required(false)
.help("Eth2 genesis time (seconds since UNIX epoch)."),
)
.arg(
Arg::with_name("output_file")
.short("f")
.value_name("PATH")
.takes_value(true)
.default_value("./genesis_state.yaml")
.help("Output file for generated state."),
),
)
.subcommand(
SubCommand::with_name("skip-slots")
.about(
@@ -138,22 +107,21 @@ fn main() {
),
)
.subcommand(
SubCommand::with_name("pretty-hex")
.about("Parses SSZ encoded as ASCII 0x-prefixed hex")
SubCommand::with_name("pretty-ssz")
.about("Parses SSZ-encoded data from a file")
.arg(
Arg::with_name("type")
.value_name("TYPE")
.takes_value(true)
.required(true)
.possible_values(&["block"])
.help("The schema of the supplied SSZ."),
.help("Type to decode"),
)
.arg(
Arg::with_name("hex_ssz")
.value_name("HEX")
Arg::with_name("ssz-file")
.value_name("FILE")
.takes_value(true)
.required(true)
.help("SSZ encoded as 0x-prefixed hex"),
.help("Path to SSZ bytes"),
),
)
.subcommand(
@@ -408,7 +376,16 @@ fn main() {
"The block the deposit contract was deployed. Setting this is a huge
optimization for nodes, please do it.",
),
),
)
.arg(
Arg::with_name("altair-fork-epoch")
.long("altair-fork-epoch")
.value_name("EPOCH")
.takes_value(true)
.help(
"The epoch at which to enable the Altair hard fork",
),
)
)
.subcommand(
SubCommand::with_name("check-deposit-data")
@@ -516,7 +493,6 @@ fn main() {
.and_then(|eth_spec_id| match eth_spec_id {
EthSpecId::Minimal => run(EnvironmentBuilder::minimal(), &matches),
EthSpecId::Mainnet => run(EnvironmentBuilder::mainnet(), &matches),
EthSpecId::V012Legacy => run(EnvironmentBuilder::v012_legacy(), &matches),
});
match result {
@@ -540,66 +516,37 @@ fn run<T: EthSpec>(
.build()
.map_err(|e| format!("should build env: {:?}", e))?;
let testnet_dir = parse_path_with_default_in_home_dir(
matches,
"testnet-dir",
PathBuf::from(directory::DEFAULT_ROOT_DIR).join("testnet"),
)?;
match matches.subcommand() {
("genesis_yaml", Some(matches)) => {
let num_validators = matches
.value_of("num_validators")
.expect("slog requires num_validators")
.parse::<usize>()
.expect("num_validators must be a valid integer");
let genesis_time = if let Some(string) = matches.value_of("genesis_time") {
string
.parse::<u64>()
.expect("genesis_time must be a valid integer")
} else {
warn!("No genesis time supplied via CLI, using the current time.");
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("should obtain time since unix epoch")
.as_secs()
};
let file = matches
.value_of("output_file")
.expect("slog requires output file")
.parse::<PathBuf>()
.expect("output_file must be a valid path");
info!(
"Creating genesis state with {} validators and genesis time {}.",
num_validators, genesis_time
);
match matches.value_of("spec").expect("spec is required by slog") {
"minimal" => genesis_yaml::<MinimalEthSpec>(num_validators, genesis_time, file),
"mainnet" => genesis_yaml::<MainnetEthSpec>(num_validators, genesis_time, file),
_ => unreachable!("guarded by slog possible_values"),
};
info!("Genesis state YAML file created. Exiting successfully.");
Ok(())
}
("transition-blocks", Some(matches)) => run_transition_blocks::<T>(matches)
("transition-blocks", Some(matches)) => run_transition_blocks::<T>(testnet_dir, matches)
.map_err(|e| format!("Failed to transition blocks: {}", e)),
("skip-slots", Some(matches)) => {
skip_slots::run::<T>(matches).map_err(|e| format!("Failed to skip slots: {}", e))
}
("pretty-hex", Some(matches)) => {
run_parse_hex::<T>(matches).map_err(|e| format!("Failed to pretty print hex: {}", e))
("skip-slots", Some(matches)) => skip_slots::run::<T>(testnet_dir, matches)
.map_err(|e| format!("Failed to skip slots: {}", e)),
("pretty-ssz", Some(matches)) => {
run_parse_ssz::<T>(matches).map_err(|e| format!("Failed to pretty print hex: {}", e))
}
("deploy-deposit-contract", Some(matches)) => {
deploy_deposit_contract::run::<T>(env, matches)
.map_err(|e| format!("Failed to run deploy-deposit-contract command: {}", e))
}
("eth1-genesis", Some(matches)) => eth1_genesis::run::<T>(env, matches)
("eth1-genesis", Some(matches)) => eth1_genesis::run::<T>(env, testnet_dir, matches)
.map_err(|e| format!("Failed to run eth1-genesis command: {}", e)),
("interop-genesis", Some(matches)) => interop_genesis::run::<T>(env, matches)
("interop-genesis", Some(matches)) => interop_genesis::run::<T>(testnet_dir, matches)
.map_err(|e| format!("Failed to run interop-genesis command: {}", e)),
("change-genesis-time", Some(matches)) => change_genesis_time::run::<T>(matches)
.map_err(|e| format!("Failed to run change-genesis-time command: {}", e)),
("replace-state-pubkeys", Some(matches)) => replace_state_pubkeys::run::<T>(matches)
.map_err(|e| format!("Failed to run replace-state-pubkeys command: {}", e)),
("new-testnet", Some(matches)) => new_testnet::run::<T>(matches)
("change-genesis-time", Some(matches)) => {
change_genesis_time::run::<T>(testnet_dir, matches)
.map_err(|e| format!("Failed to run change-genesis-time command: {}", e))
}
("replace-state-pubkeys", Some(matches)) => {
replace_state_pubkeys::run::<T>(testnet_dir, matches)
.map_err(|e| format!("Failed to run replace-state-pubkeys command: {}", e))
}
("new-testnet", Some(matches)) => new_testnet::run::<T>(testnet_dir, matches)
.map_err(|e| format!("Failed to run new_testnet command: {}", e)),
("check-deposit-data", Some(matches)) => check_deposit_data::run::<T>(matches)
.map_err(|e| format!("Failed to run check-deposit-data command: {}", e)),
@@ -610,22 +557,3 @@ fn run<T: EthSpec>(
(other, _) => Err(format!("Unknown subcommand {}. See --help.", other)),
}
}
/// Creates a genesis state and writes it to a YAML file.
fn genesis_yaml<T: EthSpec>(validator_count: usize, genesis_time: u64, output: PathBuf) {
let spec = &T::default_spec();
let builder: TestingBeaconStateBuilder<T> =
TestingBeaconStateBuilder::from_deterministic_keypairs(validator_count, spec);
let (mut state, _keypairs) = builder.build();
state.genesis_time = genesis_time;
info!("Generated state root: {:?}", state.canonical_root());
info!("Writing genesis state to {:?}", output);
let file = File::create(output.clone())
.unwrap_or_else(|e| panic!("unable to create file: {:?}. Error: {:?}", output, e));
serde_yaml::to_writer(file, &state).expect("should be able to serialize BeaconState");
}

View File

@@ -1,17 +1,10 @@
use clap::ArgMatches;
use clap_utils::{
parse_optional, parse_path_with_default_in_home_dir, parse_required, parse_ssz_optional,
};
use clap_utils::{parse_optional, parse_required, parse_ssz_optional};
use eth2_network_config::Eth2NetworkConfig;
use std::path::PathBuf;
use types::{Address, EthSpec, YamlConfig};
use types::{Address, Config, EthSpec};
pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
let testnet_dir_path = parse_path_with_default_in_home_dir(
matches,
"testnet-dir",
PathBuf::from(directory::DEFAULT_ROOT_DIR).join("testnet"),
)?;
pub fn run<T: EthSpec>(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Result<(), String> {
let deposit_contract_address: Address = parse_required(matches, "deposit-contract-address")?;
let deposit_contract_deploy_block = parse_required(matches, "deposit-contract-deploy-block")?;
@@ -56,11 +49,15 @@ pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
spec.genesis_fork_version = v;
}
if let Some(fork_epoch) = parse_optional(matches, "altair-fork-epoch")? {
spec.altair_fork_epoch = Some(fork_epoch);
}
let testnet = Eth2NetworkConfig {
deposit_contract_deploy_block,
boot_enr: Some(vec![]),
genesis_state_bytes: None,
yaml_config: Some(YamlConfig::from_spec::<T>(&spec)),
config: Config::from_chain_spec::<T>(&spec),
};
testnet.write_to_file(testnet_dir_path, overwrite_files)

View File

@@ -1,41 +0,0 @@
use clap::ArgMatches;
use serde::Serialize;
use ssz::Decode;
use types::{BeaconBlock, BeaconState, EthSpec};
pub fn run_parse_hex<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
let type_str = matches.value_of("type").ok_or("No type supplied")?;
let mut hex: String = matches
.value_of("hex_ssz")
.ok_or("No hex ssz supplied")?
.to_string();
if hex.starts_with("0x") {
hex = hex[2..].to_string();
}
let hex = hex::decode(&hex).map_err(|e| format!("Failed to parse hex: {:?}", e))?;
info!("Using {} spec", T::spec_name());
info!("Type: {:?}", type_str);
match type_str {
"block" => decode_and_print::<BeaconBlock<T>>(&hex)?,
"state" => decode_and_print::<BeaconState<T>>(&hex)?,
other => return Err(format!("Unknown type: {}", other)),
};
Ok(())
}
fn decode_and_print<T: Decode + Serialize>(bytes: &[u8]) -> Result<(), String> {
let item = T::from_ssz_bytes(&bytes).map_err(|e| format!("Ssz decode failed: {:?}", e))?;
println!(
"{}",
serde_yaml::to_string(&item)
.map_err(|e| format!("Unable to write object to YAML: {:?}", e))?
);
Ok(())
}

View File

@@ -1,26 +1,28 @@
use crate::helpers::parse_path;
use clap::ArgMatches;
use serde::Serialize;
use ssz::Decode;
use std::fs::File;
use std::io::Read;
use types::{EthSpec, SignedBeaconBlock};
use types::*;
pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
let type_str = matches
.value_of("type")
.ok_or("No type supplied")?;
let path = parse_path(matches, "path")?;
info!("Type: {:?}", type_str);
pub fn run_parse_ssz<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
let type_str = matches.value_of("type").ok_or("No type supplied")?;
let filename = matches.value_of("ssz-file").ok_or("No file supplied")?;
let mut bytes = vec![];
let mut file = File::open(&path).map_err(|e| format!("Unable to open {:?}: {}", path, e))?;
let mut file =
File::open(filename).map_err(|e| format!("Unable to open {}: {}", filename, e))?;
file.read_to_end(&mut bytes)
.map_err(|e| format!("Unable to read {:?}: {}", path, e))?;
.map_err(|e| format!("Unable to read {}: {}", filename, e))?;
info!("Using {} spec", T::spec_name());
info!("Type: {:?}", type_str);
match type_str {
"SignedBeaconBlock" => decode_and_print::<SignedBeaconBlock<T>>(&bytes)?,
"block_base" => decode_and_print::<BeaconBlockBase<T>>(&bytes)?,
"block_altair" => decode_and_print::<BeaconBlockAltair<T>>(&bytes)?,
"state_base" => decode_and_print::<BeaconStateBase<T>>(&bytes)?,
"state_altair" => decode_and_print::<BeaconStateAltair<T>>(&bytes)?,
other => return Err(format!("Unknown type: {}", other)),
};
@@ -28,7 +30,7 @@ pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
}
fn decode_and_print<T: Decode + Serialize>(bytes: &[u8]) -> Result<(), String> {
let item = T::from_ssz_bytes(&bytes).map_err(|e| format!("Ssz decode failed: {:?}", e))?;
let item = T::from_ssz_bytes(&bytes).map_err(|e| format!("SSZ decode failed: {:?}", e))?;
println!(
"{}",

View File

@@ -1,14 +1,15 @@
use account_utils::{eth2_keystore::keypair_from_secret, mnemonic_from_phrase};
use clap::ArgMatches;
use eth2_network_config::Eth2NetworkConfig;
use eth2_wallet::bip39::Seed;
use eth2_wallet::{recover_validator_secret_from_mnemonic, KeyType};
use ssz::{Decode, Encode};
use ssz::Encode;
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
use types::{BeaconState, EthSpec};
pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
pub fn run<T: EthSpec>(testnet_dir: PathBuf, matches: &ArgMatches) -> Result<(), String> {
let path = matches
.value_of("ssz-state")
.ok_or("ssz-state not specified")?
@@ -19,6 +20,9 @@ pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
.value_of("mnemonic")
.ok_or("mnemonic not specified")?;
let eth2_network_config = Eth2NetworkConfig::load(testnet_dir)?;
let spec = &eth2_network_config.chain_spec::<T>()?;
let mut state: BeaconState<T> = {
let mut file = File::open(&path).map_err(|e| format!("Unable to open file: {}", e))?;
@@ -27,13 +31,14 @@ pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
file.read_to_end(&mut ssz)
.map_err(|e| format!("Unable to read file: {}", e))?;
BeaconState::from_ssz_bytes(&ssz).map_err(|e| format!("Unable to decode SSZ: {:?}", e))?
BeaconState::from_ssz_bytes(&ssz, spec)
.map_err(|e| format!("Unable to decode SSZ: {:?}", e))?
};
let mnemonic = mnemonic_from_phrase(mnemonic_phrase)?;
let seed = Seed::new(&mnemonic, "");
for (index, validator) in state.validators.iter_mut().enumerate() {
for (index, validator) in state.validators_mut().iter_mut().enumerate() {
let (secret, _) =
recover_validator_secret_from_mnemonic(seed.as_bytes(), index as u32, KeyType::Voting)
.map_err(|e| format!("Unable to generate validator key: {:?}", e))?;

View File

@@ -1,5 +1,6 @@
use crate::transition_blocks::load_from_ssz;
use crate::transition_blocks::load_from_ssz_with;
use clap::ArgMatches;
use eth2_network_config::Eth2NetworkConfig;
use ssz::Encode;
use state_processing::per_slot_processing;
use std::fs::File;
@@ -7,7 +8,7 @@ use std::io::prelude::*;
use std::path::PathBuf;
use types::{BeaconState, EthSpec};
pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
pub fn run<T: EthSpec>(testnet_dir: PathBuf, matches: &ArgMatches) -> Result<(), String> {
let pre_state_path = matches
.value_of("pre-state")
.ok_or("No pre-state file supplied")?
@@ -30,9 +31,11 @@ pub fn run<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
info!("Pre-state path: {:?}", pre_state_path);
info!("Slots: {:?}", slots);
let mut state: BeaconState<T> = load_from_ssz(pre_state_path)?;
let eth2_network_config = Eth2NetworkConfig::load(testnet_dir)?;
let spec = &eth2_network_config.chain_spec::<T>()?;
let spec = &T::default_spec();
let mut state: BeaconState<T> =
load_from_ssz_with(&pre_state_path, spec, BeaconState::from_ssz_bytes)?;
state
.build_all_caches(spec)

View File

@@ -1,12 +1,16 @@
use clap::ArgMatches;
use ssz::{Decode, Encode};
use eth2_network_config::Eth2NetworkConfig;
use ssz::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::{BeaconState, EthSpec, SignedBeaconBlock};
use std::path::{Path, PathBuf};
use types::{BeaconState, ChainSpec, EthSpec, SignedBeaconBlock};
pub fn run_transition_blocks<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
pub fn run_transition_blocks<T: EthSpec>(
testnet_dir: PathBuf,
matches: &ArgMatches,
) -> Result<(), String> {
let pre_state_path = matches
.value_of("pre-state")
.ok_or("No pre-state file supplied")?
@@ -29,10 +33,15 @@ pub fn run_transition_blocks<T: EthSpec>(matches: &ArgMatches) -> Result<(), Str
info!("Pre-state path: {:?}", pre_state_path);
info!("Block path: {:?}", block_path);
let pre_state: BeaconState<T> = load_from_ssz(pre_state_path)?;
let block: SignedBeaconBlock<T> = load_from_ssz(block_path)?;
let eth2_network_config = Eth2NetworkConfig::load(testnet_dir)?;
let spec = &eth2_network_config.chain_spec::<T>()?;
let post_state = do_transition(pre_state, block)?;
let pre_state: BeaconState<T> =
load_from_ssz_with(&pre_state_path, spec, BeaconState::from_ssz_bytes)?;
let block: SignedBeaconBlock<T> =
load_from_ssz_with(&block_path, spec, SignedBeaconBlock::from_ssz_bytes)?;
let post_state = do_transition(pre_state, block, spec)?;
let mut output_file =
File::create(output_path).map_err(|e| format!("Unable to create output file: {:?}", e))?;
@@ -47,15 +56,14 @@ pub fn run_transition_blocks<T: EthSpec>(matches: &ArgMatches) -> Result<(), Str
fn do_transition<T: EthSpec>(
mut pre_state: BeaconState<T>,
block: SignedBeaconBlock<T>,
spec: &ChainSpec,
) -> 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() {
for i in pre_state.slot().as_u64()..block.slot().as_u64() {
per_slot_processing(&mut pre_state, None, spec)
.map_err(|e| format!("Failed to advance slot on iteration {}: {:?}", i, e))?;
}
@@ -76,11 +84,15 @@ fn do_transition<T: EthSpec>(
Ok(pre_state)
}
pub fn load_from_ssz<T: Decode>(path: PathBuf) -> Result<T, String> {
pub fn load_from_ssz_with<T>(
path: &Path,
spec: &ChainSpec,
decoder: impl FnOnce(&[u8], &ChainSpec) -> Result<T, ssz::DecodeError>,
) -> Result<T, String> {
let mut file =
File::open(path.clone()).map_err(|e| format!("Unable to open file {:?}: {:?}", path, e))?;
File::open(path).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))
decoder(&bytes, spec).map_err(|e| format!("Ssz decode failed: {:?}", e))
}