Fix issues when starting with mainnet spec (#674)
* Update lcli to parse spec at boot, remove pycli * Fix issues when starting with mainnet spec * Set default spec to mainnet * Ensure ETH1_FOLLOW_DISTANCE is in YamlConfig * Set testnet ETH1_FOLLOW_DISTANCE to 16 * Set testnet min validator count * Add validator count CLI flag to lcli contract deploy * Extend genesis delay time
This commit is contained in:
parent
bfbb556f02
commit
988059bc9c
@ -36,6 +36,8 @@ pub fn get_configs<E: EthSpec>(
|
||||
|
||||
let mut client_config = ClientConfig::default();
|
||||
|
||||
client_config.spec_constants = eth2_config.spec_constants.clone();
|
||||
|
||||
// Read the `--datadir` flag.
|
||||
//
|
||||
// If it's not present, try and find the home directory (`~`) and push the default data
|
||||
@ -57,9 +59,23 @@ pub fn get_configs<E: EthSpec>(
|
||||
// Load the eth2 config, if it exists .
|
||||
let path = client_config.data_dir.join(ETH2_CONFIG_FILENAME);
|
||||
if path.exists() {
|
||||
eth2_config = read_from_file(path.clone())
|
||||
let loaded_eth2_config: Eth2Config = read_from_file(path.clone())
|
||||
.map_err(|e| format!("Unable to parse {:?} file: {:?}", path, e))?
|
||||
.ok_or_else(|| format!("{:?} file does not exist", path))?;
|
||||
|
||||
// The loaded spec must be using the same spec constants (e.g., minimal, mainnet) as the
|
||||
// client expects.
|
||||
if loaded_eth2_config.spec_constants == client_config.spec_constants {
|
||||
eth2_config = loaded_eth2_config
|
||||
} else {
|
||||
return Err(
|
||||
format!(
|
||||
"Eth2 config loaded from disk does not match client spec version. Got {} expected {}",
|
||||
&loaded_eth2_config.spec_constants,
|
||||
&client_config.spec_constants
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the `--testnet-dir` flag.
|
||||
|
@ -407,6 +407,9 @@ pub struct YamlConfig {
|
||||
max_deposits: u32,
|
||||
max_voluntary_exits: u32,
|
||||
|
||||
// Eth1
|
||||
eth1_follow_distance: u64,
|
||||
|
||||
// Unused
|
||||
#[serde(skip_serializing)]
|
||||
early_derived_secret_penalty_max_future_epochs: u32,
|
||||
@ -503,6 +506,9 @@ impl YamlConfig {
|
||||
max_deposits: T::MaxDeposits::to_u32(),
|
||||
max_voluntary_exits: T::MaxVoluntaryExits::to_u32(),
|
||||
|
||||
// Eth1
|
||||
eth1_follow_distance: spec.eth1_follow_distance,
|
||||
|
||||
// Unused
|
||||
early_derived_secret_penalty_max_future_epochs: 0,
|
||||
max_seed_lookahead: 0,
|
||||
@ -580,6 +586,7 @@ impl YamlConfig {
|
||||
domain_voluntary_exit: self.domain_voluntary_exit,
|
||||
boot_nodes: chain_spec.boot_nodes.clone(),
|
||||
genesis_fork: chain_spec.genesis_fork.clone(),
|
||||
eth1_follow_distance: self.eth1_follow_distance,
|
||||
..*chain_spec
|
||||
})
|
||||
}
|
||||
|
@ -17,6 +17,12 @@ pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches) -> Result<
|
||||
.parse::<u64>()
|
||||
.map_err(|e| format!("Failed to parse min_genesis_time: {}", e))?;
|
||||
|
||||
let min_genesis_active_validator_count = matches
|
||||
.value_of("min-genesis-active-validator-count")
|
||||
.ok_or_else(|| "min-genesis-active-validator-count not specified")?
|
||||
.parse::<u64>()
|
||||
.map_err(|e| format!("Failed to parse min-genesis-active-validator-count: {}", e))?;
|
||||
|
||||
let confirmations = matches
|
||||
.value_of("confirmations")
|
||||
.ok_or_else(|| "Confirmations not specified")?
|
||||
@ -90,6 +96,7 @@ pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches) -> Result<
|
||||
|
||||
let mut spec = lighthouse_testnet_spec(env.core_context().eth2_config.spec.clone());
|
||||
spec.min_genesis_time = min_genesis_time;
|
||||
spec.min_genesis_active_validator_count = min_genesis_active_validator_count;
|
||||
|
||||
let testnet_config: Eth2TestnetConfig<T> = Eth2TestnetConfig {
|
||||
deposit_contract_address: format!("{}", deposit_contract.address()),
|
||||
@ -111,13 +118,17 @@ pub fn lighthouse_testnet_spec(mut spec: ChainSpec) -> ChainSpec {
|
||||
spec.ejection_balance = 1_600_000_000;
|
||||
spec.effective_balance_increment = 100_000_000;
|
||||
|
||||
spec.eth1_follow_distance = 16;
|
||||
|
||||
// This value must be at least 2x the `ETH1_FOLLOW_DISTANCE` otherwise `all_eth1_data` can
|
||||
// become a subset of `new_eth1_data` which may result in an Exception in the spec
|
||||
// implementation.
|
||||
//
|
||||
// This value determines the delay between the eth1 block that triggers genesis and the first
|
||||
// slot of that new chain.
|
||||
spec.seconds_per_day = SECONDS_PER_ETH1_BLOCK * spec.eth1_follow_distance * 2;
|
||||
//
|
||||
// With a follow distance of 16, this is 40mins.
|
||||
spec.seconds_per_day = SECONDS_PER_ETH1_BLOCK * spec.eth1_follow_distance * 2 * 5;
|
||||
|
||||
spec
|
||||
}
|
||||
|
@ -4,23 +4,19 @@ extern crate log;
|
||||
mod deploy_deposit_contract;
|
||||
mod eth1_genesis;
|
||||
mod parse_hex;
|
||||
mod pycli;
|
||||
mod refund_deposit_contract;
|
||||
mod transition_blocks;
|
||||
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use clap::{App, Arg, ArgMatches, SubCommand};
|
||||
use environment::EnvironmentBuilder;
|
||||
use log::Level;
|
||||
use parse_hex::run_parse_hex;
|
||||
use pycli::run_pycli;
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use transition_blocks::run_transition_blocks;
|
||||
use types::{test_utils::TestingBeaconStateBuilder, EthSpec, MainnetEthSpec, MinimalEthSpec};
|
||||
|
||||
type LocalEthSpec = MinimalEthSpec;
|
||||
|
||||
fn main() {
|
||||
simple_logger::init_with_level(Level::Info).expect("logger should initialize");
|
||||
|
||||
@ -55,7 +51,7 @@ fn main() {
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.possible_values(&["minimal", "mainnet"])
|
||||
.default_value("minimal")
|
||||
.default_value("mainnet")
|
||||
.help("Eth2 genesis time (seconds since UNIX epoch)."),
|
||||
)
|
||||
.arg(
|
||||
@ -135,6 +131,15 @@ fn main() {
|
||||
.default_value("0")
|
||||
.help("The MIN_GENESIS_TIME constant."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("min-genesis-active-validator-count")
|
||||
.short("v")
|
||||
.long("min-genesis-active-validator-count")
|
||||
.value_name("INTEGER")
|
||||
.takes_value(true)
|
||||
.default_value("64")
|
||||
.help("The MIN_GENESIS_ACTIVE_VALIDATOR_COUNT constant."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("eth1-endpoint")
|
||||
.short("e")
|
||||
@ -222,22 +227,27 @@ fn main() {
|
||||
.help("The URL to the eth1 JSON-RPC http API."),
|
||||
)
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("pycli")
|
||||
.about("TODO")
|
||||
.arg(
|
||||
Arg::with_name("pycli-path")
|
||||
.long("pycli-path")
|
||||
.short("p")
|
||||
.value_name("PATH")
|
||||
.takes_value(true)
|
||||
.default_value("../../pycli")
|
||||
.help("Path to the pycli repository."),
|
||||
),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
let env = EnvironmentBuilder::minimal()
|
||||
macro_rules! run_with_spec {
|
||||
($env_builder: expr) => {
|
||||
run($env_builder, &matches)
|
||||
};
|
||||
}
|
||||
|
||||
match matches.value_of("spec") {
|
||||
Some("minimal") => run_with_spec!(EnvironmentBuilder::minimal()),
|
||||
Some("mainnet") => run_with_spec!(EnvironmentBuilder::mainnet()),
|
||||
Some("interop") => run_with_spec!(EnvironmentBuilder::interop()),
|
||||
spec => {
|
||||
// This path should be unreachable due to slog having a `default_value`
|
||||
unreachable!("Unknown spec configuration: {:?}", spec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run<T: EthSpec>(env_builder: EnvironmentBuilder<T>, matches: &ArgMatches) {
|
||||
let env = env_builder
|
||||
.multi_threaded_tokio_runtime()
|
||||
.expect("should start tokio runtime")
|
||||
.async_logger("trace")
|
||||
@ -283,22 +293,19 @@ fn main() {
|
||||
};
|
||||
info!("Genesis state YAML file created. Exiting successfully.");
|
||||
}
|
||||
("transition-blocks", Some(matches)) => run_transition_blocks(matches)
|
||||
("transition-blocks", Some(matches)) => run_transition_blocks::<T>(matches)
|
||||
.unwrap_or_else(|e| error!("Failed to transition blocks: {}", e)),
|
||||
("pretty-hex", Some(matches)) => {
|
||||
run_parse_hex(matches).unwrap_or_else(|e| error!("Failed to pretty print hex: {}", e))
|
||||
}
|
||||
("pycli", Some(matches)) => run_pycli::<LocalEthSpec>(matches)
|
||||
.unwrap_or_else(|e| error!("Failed to run pycli: {}", e)),
|
||||
("pretty-hex", Some(matches)) => run_parse_hex::<T>(matches)
|
||||
.unwrap_or_else(|e| error!("Failed to pretty print hex: {}", e)),
|
||||
("deploy-deposit-contract", Some(matches)) => {
|
||||
deploy_deposit_contract::run::<LocalEthSpec>(env, matches)
|
||||
deploy_deposit_contract::run::<T>(env, matches)
|
||||
.unwrap_or_else(|e| error!("Failed to run deploy-deposit-contract command: {}", e))
|
||||
}
|
||||
("refund-deposit-contract", Some(matches)) => {
|
||||
refund_deposit_contract::run::<LocalEthSpec>(env, matches)
|
||||
refund_deposit_contract::run::<T>(env, matches)
|
||||
.unwrap_or_else(|e| error!("Failed to run refund-deposit-contract command: {}", e))
|
||||
}
|
||||
("eth1-genesis", Some(matches)) => eth1_genesis::run::<LocalEthSpec>(env, matches)
|
||||
("eth1-genesis", Some(matches)) => eth1_genesis::run::<T>(env, matches)
|
||||
.unwrap_or_else(|e| error!("Failed to run eth1-genesis command: {}", e)),
|
||||
(other, _) => error!("Unknown subcommand {}. See --help.", other),
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
use clap::ArgMatches;
|
||||
use serde::Serialize;
|
||||
use ssz::Decode;
|
||||
use types::{BeaconBlock, BeaconState, MinimalEthSpec};
|
||||
use types::{BeaconBlock, BeaconState, EthSpec};
|
||||
|
||||
pub fn run_parse_hex(matches: &ArgMatches) -> Result<(), String> {
|
||||
pub fn run_parse_hex<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
|
||||
let type_str = matches
|
||||
.value_of("type")
|
||||
.ok_or_else(|| "No type supplied".to_string())?;
|
||||
@ -22,8 +22,8 @@ pub fn run_parse_hex(matches: &ArgMatches) -> Result<(), String> {
|
||||
info!("Type: {:?}", type_str);
|
||||
|
||||
match type_str {
|
||||
"block" => decode_and_print::<BeaconBlock<MinimalEthSpec>>(&hex)?,
|
||||
"state" => decode_and_print::<BeaconState<MinimalEthSpec>>(&hex)?,
|
||||
"block" => decode_and_print::<BeaconBlock<T>>(&hex)?,
|
||||
"state" => decode_and_print::<BeaconState<T>>(&hex)?,
|
||||
other => return Err(format!("Unknown type: {}", other)),
|
||||
};
|
||||
|
||||
|
@ -1,79 +0,0 @@
|
||||
use clap::ArgMatches;
|
||||
use ssz::Decode;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use types::{BeaconState, EthSpec};
|
||||
|
||||
pub fn run_pycli<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
|
||||
let cmd_path = matches
|
||||
.value_of("pycli-path")
|
||||
.ok_or_else(|| "No pycli-path supplied")?;
|
||||
|
||||
let pycli = PyCli::new(cmd_path.to_string())?;
|
||||
|
||||
let block_path = PathBuf::from("/tmp/trinity/block_16.ssz");
|
||||
let pre_state_path = PathBuf::from("/tmp/trinity/state_15.ssz");
|
||||
|
||||
pycli
|
||||
.transition_blocks::<T>(block_path, pre_state_path)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A wrapper around Danny Ryan's `pycli` utility:
|
||||
///
|
||||
/// https://github.com/djrtwo/pycli
|
||||
///
|
||||
/// Provides functions for testing consensus logic against the executable Python spec.
|
||||
pub struct PyCli {
|
||||
cmd_path: PathBuf,
|
||||
}
|
||||
|
||||
impl PyCli {
|
||||
/// Create a new instance, parsing the given `cmd_path` as a canonical path.
|
||||
pub fn new(cmd_path: String) -> Result<Self, String> {
|
||||
Ok(Self {
|
||||
cmd_path: fs::canonicalize(cmd_path)
|
||||
.map_err(|e| format!("Failed to canonicalize pycli path: {:?}", e))?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Performs block processing on the state at the given `pre_state_path`, using the block at
|
||||
/// `block_path`.
|
||||
///
|
||||
/// Returns an SSZ-encoded `BeaconState` on success.
|
||||
pub fn transition_blocks<T: EthSpec>(
|
||||
&self,
|
||||
block_path: PathBuf,
|
||||
pre_state_path: PathBuf,
|
||||
) -> Result<BeaconState<T>, String> {
|
||||
let output = Command::new("python")
|
||||
.current_dir(self.cmd_path.clone())
|
||||
.arg("pycli.py")
|
||||
.arg("transition")
|
||||
.arg("blocks")
|
||||
.arg(format!("--pre={}", path_string(pre_state_path)?))
|
||||
.arg(path_string(block_path)?)
|
||||
.output()
|
||||
.map_err(|e| format!("Failed to run command: {:?}", e))?;
|
||||
|
||||
if output.status.success() {
|
||||
let state = BeaconState::from_ssz_bytes(&output.stdout)
|
||||
.map_err(|e| format!("Failed to parse SSZ: {:?}", e))?;
|
||||
Ok(state)
|
||||
} else {
|
||||
Err(format!("pycli returned an error: {:?}", output))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn path_string(path: PathBuf) -> Result<String, String> {
|
||||
let path =
|
||||
fs::canonicalize(path).map_err(|e| format!("Unable to canonicalize path: {:?}", e))?;
|
||||
|
||||
path.into_os_string()
|
||||
.into_string()
|
||||
.map_err(|p| format!("Unable to stringify path: {:?}", p))
|
||||
}
|
@ -4,9 +4,9 @@ use state_processing::{per_block_processing, per_slot_processing, BlockSignature
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::path::PathBuf;
|
||||
use types::{BeaconBlock, BeaconState, EthSpec, MinimalEthSpec};
|
||||
use types::{BeaconBlock, BeaconState, EthSpec};
|
||||
|
||||
pub fn run_transition_blocks(matches: &ArgMatches) -> Result<(), String> {
|
||||
pub fn run_transition_blocks<T: EthSpec>(matches: &ArgMatches) -> Result<(), String> {
|
||||
let pre_state_path = matches
|
||||
.value_of("pre-state")
|
||||
.ok_or_else(|| "No pre-state file supplied".to_string())?
|
||||
@ -29,8 +29,8 @@ pub fn run_transition_blocks(matches: &ArgMatches) -> Result<(), String> {
|
||||
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 pre_state: BeaconState<T> = load_from_ssz(pre_state_path)?;
|
||||
let block: BeaconBlock<T> = load_from_ssz(block_path)?;
|
||||
|
||||
let post_state = do_transition(pre_state, block)?;
|
||||
|
||||
|
@ -33,7 +33,7 @@ fn main() {
|
||||
.takes_value(true)
|
||||
.possible_values(&["mainnet", "minimal", "interop"])
|
||||
.global(true)
|
||||
.default_value("minimal"),
|
||||
.default_value("mainnet"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("logfile")
|
||||
|
Loading…
Reference in New Issue
Block a user