From ed2eaf8d9bee24c4b58091937a8f623da12d228f Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Fri, 29 Nov 2019 08:39:28 +1100 Subject: [PATCH] Write genesis state as SSZ --- eth2/utils/eth2_testnet/Cargo.toml | 1 + eth2/utils/eth2_testnet/src/lib.rs | 49 ++++++++++++++++++++++------- lcli/src/deploy_deposit_contract.rs | 35 ++++++++++++--------- lcli/src/eth1_genesis.rs | 3 ++ 4 files changed, 62 insertions(+), 26 deletions(-) diff --git a/eth2/utils/eth2_testnet/Cargo.toml b/eth2/utils/eth2_testnet/Cargo.toml index 967c28880b..cc04cb739d 100644 --- a/eth2/utils/eth2_testnet/Cargo.toml +++ b/eth2/utils/eth2_testnet/Cargo.toml @@ -14,3 +14,4 @@ serde = "1.0" serde_yaml = "0.8" types = { path = "../../types"} eth2-libp2p = { path = "../../../beacon_node/eth2-libp2p"} +eth2_ssz = { path = "../ssz"} diff --git a/eth2/utils/eth2_testnet/src/lib.rs b/eth2/utils/eth2_testnet/src/lib.rs index da4f728120..4bea7200aa 100644 --- a/eth2/utils/eth2_testnet/src/lib.rs +++ b/eth2/utils/eth2_testnet/src/lib.rs @@ -8,8 +8,9 @@ //! https://github.com/sigp/lighthouse/pull/605 use eth2_libp2p::Enr; +use ssz::{Decode, Encode}; use std::fs::{create_dir_all, File}; -use std::io::Write; +use std::io::{Read, Write}; use std::path::PathBuf; use types::{Address, BeaconState, EthSpec, YamlConfig}; @@ -75,7 +76,7 @@ impl Eth2TestnetDir { create_dir_all(&base_dir) .map_err(|e| format!("Unable to create testnet directory: {:?}", e))?; - macro_rules! write_to_file { + macro_rules! write_to_yaml_file { ($file: ident, $variable: expr) => { File::create(base_dir.join($file)) .map_err(|e| format!("Unable to create {}: {:?}", $file, e)) @@ -86,19 +87,27 @@ impl Eth2TestnetDir { }; } - write_to_file!(ADDRESS_FILE, self.deposit_contract_address); - write_to_file!(DEPLOY_BLOCK_FILE, self.deposit_contract_deploy_block); + write_to_yaml_file!(ADDRESS_FILE, self.deposit_contract_address); + write_to_yaml_file!(DEPLOY_BLOCK_FILE, self.deposit_contract_deploy_block); if let Some(boot_enr) = &self.boot_enr { - write_to_file!(BOOT_NODES_FILE, boot_enr); - } - - if let Some(genesis_state) = &self.genesis_state { - write_to_file!(GENESIS_STATE_FILE, genesis_state); + write_to_yaml_file!(BOOT_NODES_FILE, boot_enr); } if let Some(yaml_config) = &self.yaml_config { - write_to_file!(YAML_CONFIG_FILE, yaml_config); + write_to_yaml_file!(YAML_CONFIG_FILE, yaml_config); + } + + // The genesis state is a special case because it uses SSZ, not YAML. + if let Some(genesis_state) = &self.genesis_state { + let file = base_dir.join(GENESIS_STATE_FILE); + + File::create(&file) + .map_err(|e| format!("Unable to create {:?}: {:?}", file, e)) + .and_then(|mut file| { + file.write_all(&genesis_state.as_ssz_bytes()) + .map_err(|e| format!("Unable to write {:?}: {:?}", file, e)) + })?; } Ok(()) @@ -129,9 +138,27 @@ impl Eth2TestnetDir { let deposit_contract_address = load_from_file!(ADDRESS_FILE); let deposit_contract_deploy_block = load_from_file!(DEPLOY_BLOCK_FILE); let boot_enr = optional_load_from_file!(BOOT_NODES_FILE); - let genesis_state = optional_load_from_file!(GENESIS_STATE_FILE); let yaml_config = optional_load_from_file!(YAML_CONFIG_FILE); + // The genesis state is a special case because it uses SSZ, not YAML. + let file = base_dir.join(GENESIS_STATE_FILE); + let genesis_state = if base_dir.join(&file).exists() { + Some( + File::open(base_dir.join(&file)) + .map_err(|e| format!("Unable to open {:?}: {:?}", file, e)) + .and_then(|mut file| { + let mut bytes = vec![]; + file.read_to_end(&mut bytes) + .map_err(|e| format!("Unable to read {:?}: {:?}", file, e))?; + + BeaconState::from_ssz_bytes(&bytes) + .map_err(|e| format!("Unable to SSZ decode {:?}: {:?}", file, e)) + })?, + ) + } else { + None + }; + Ok(Self { deposit_contract_address, deposit_contract_deploy_block, diff --git a/lcli/src/deploy_deposit_contract.rs b/lcli/src/deploy_deposit_contract.rs index ecfcc21f41..28fd08fa3e 100644 --- a/lcli/src/deploy_deposit_contract.rs +++ b/lcli/src/deploy_deposit_contract.rs @@ -5,7 +5,7 @@ use eth2_testnet::Eth2TestnetDir; use std::fs::File; use std::io::Read; use std::path::PathBuf; -use types::{EthSpec, YamlConfig}; +use types::{ChainSpec, EthSpec, YamlConfig}; use web3::{transports::Http, Web3}; pub const SECONDS_PER_ETH1_BLOCK: u64 = 15; @@ -88,22 +88,9 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< info!("Writing config to {:?}", output_dir); - let mut spec = env.core_context().eth2_config.spec.clone(); - - spec.min_deposit_amount = 100; - spec.max_effective_balance = 3_200_000_000; - spec.ejection_balance = 1_600_000_000; - spec.effective_balance_increment = 100_000_000; + let mut spec = lighthouse_testnet_spec(env.core_context().eth2_config.spec.clone()); spec.min_genesis_time = min_genesis_time; - // This value must be at least 2x the `ETH1_FOLLOW_DISTANCE` otherwise `all_eth1_data` - // can become a subset of `new_eth1_data`. - // - // See: - // https://github.com/ethereum/eth2.0-specs/blob/v0.9.2/specs/validator/0_beacon-chain-validator.md#eth1-data - // TODO: set from 10 back to 2 - spec.seconds_per_day = SECONDS_PER_ETH1_BLOCK * spec.eth1_follow_distance * 2; - let testnet_dir: Eth2TestnetDir = Eth2TestnetDir { deposit_contract_address: format!("{}", deposit_contract.address()), deposit_contract_deploy_block: deploy_block.as_u64(), @@ -117,6 +104,24 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< Ok(()) } +/// Modfies the specification to better suit present-capacity testnets. +pub fn lighthouse_testnet_spec(mut spec: ChainSpec) -> ChainSpec { + spec.min_deposit_amount = 100; + spec.max_effective_balance = 3_200_000_000; + spec.ejection_balance = 1_600_000_000; + spec.effective_balance_increment = 100_000_000; + + // 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; + + spec +} + pub fn parse_password(matches: &ArgMatches) -> Result, String> { if let Some(password_path) = matches.value_of("password") { Ok(Some( diff --git a/lcli/src/eth1_genesis.rs b/lcli/src/eth1_genesis.rs index 07e541e3c2..d802d6cdb8 100644 --- a/lcli/src/eth1_genesis.rs +++ b/lcli/src/eth1_genesis.rs @@ -55,6 +55,9 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< eth2_testnet_dir.force_write_to_file(testnet_dir) }); + info!("Starting service to produce genesis BeaconState from eth1"); + info!("Connecting to eth1 http endpoint: {}", endpoint); + env.runtime() .block_on(future) .map_err(|e| format!("Failed to find genesis: {}", e))??;