diff --git a/account_manager/src/lib.rs b/account_manager/src/lib.rs index a59cf858aa..e98aaf6f78 100644 --- a/account_manager/src/lib.rs +++ b/account_manager/src/lib.rs @@ -179,7 +179,7 @@ fn run_new_validator_subcommand( .parse::() .map_err(|e| format!("Unable to parse testnet-dir: {}", e))?; - let eth2_testnet_dir = Eth2TestnetDir::load(testnet_dir) + let eth2_testnet_dir: Eth2TestnetDir = Eth2TestnetDir::load(testnet_dir) .map_err(|e| format!("Failed to load testnet dir: {}", e))?; // Convert from `types::Address` to `web3::types::Address`. diff --git a/beacon_node/client/src/builder.rs b/beacon_node/client/src/builder.rs index 4c1e682ab2..630832cdd4 100644 --- a/beacon_node/client/src/builder.rs +++ b/beacon_node/client/src/builder.rs @@ -194,38 +194,8 @@ where "eth1_node" => &config.endpoint ); - let genesis_service = Eth1GenesisService::new( - // Some of the configuration options for `Eth1Config` are - // hard-coded when listening for genesis from the deposit contract. - // - // The idea is that the `Eth1Config` supplied to this function - // (`config`) is intended for block production duties (i.e., - // listening for deposit events and voting on eth1 data) and that - // we can make listening for genesis more efficient if we modify - // some params. - Eth1Config { - // Truncating the block cache makes searching for genesis more - // complicated. - block_cache_truncation: None, - // Scan large ranges of blocks when awaiting genesis. - blocks_per_log_query: 1_000, - // Only perform a single log request each time the eth1 node is - // polled. - // - // For small testnets this makes finding genesis much faster, - // as it usually happens within 1,000 blocks. - max_log_requests_per_update: Some(1), - // Only perform a single block request each time the eth1 node - // is polled. - // - // For small testnets, this is much faster as they do not have - // a `MIN_GENESIS_SECONDS`, so after `MIN_GENESIS_VALIDATOR_COUNT` - // has been reached only a single block needs to be read. - max_blocks_per_update: Some(1), - ..config - }, - context.log.clone(), - ); + let genesis_service = + Eth1GenesisService::new(config, context.log.clone()); let future = genesis_service .wait_for_genesis_state( diff --git a/beacon_node/client/src/config.rs b/beacon_node/client/src/config.rs index df527c60ab..661240358a 100644 --- a/beacon_node/client/src/config.rs +++ b/beacon_node/client/src/config.rs @@ -39,6 +39,7 @@ impl Default for ClientGenesis { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Config { pub data_dir: PathBuf, + pub testnet_dir: PathBuf, pub db_type: String, pub db_name: String, pub freezer_db_path: Option, @@ -63,6 +64,7 @@ impl Default for Config { fn default() -> Self { Self { data_dir: PathBuf::from(".lighthouse"), + testnet_dir: PathBuf::from("testnet"), log_file: PathBuf::from(""), db_type: "disk".to_string(), db_name: "chain_db".to_string(), diff --git a/beacon_node/eth1/src/block_cache.rs b/beacon_node/eth1/src/block_cache.rs index f267a4d85d..a15ef86a6b 100644 --- a/beacon_node/eth1/src/block_cache.rs +++ b/beacon_node/eth1/src/block_cache.rs @@ -59,6 +59,11 @@ impl BlockCache { self.blocks.first().map(|block| block.timestamp) } + /// Returns the timestamp of the latest block in the cache (if any). + pub fn latest_block_timestamp(&self) -> Option { + self.blocks.last().map(|block| block.timestamp) + } + /// Returns the lowest block number stored. pub fn lowest_block_number(&self) -> Option { self.blocks.first().map(|block| block.number) diff --git a/beacon_node/eth1/src/service.rs b/beacon_node/eth1/src/service.rs index 3a1b20094f..efa402884b 100644 --- a/beacon_node/eth1/src/service.rs +++ b/beacon_node/eth1/src/service.rs @@ -173,6 +173,11 @@ impl Service { self.inner.block_cache.read().earliest_block_timestamp() } + /// Returns the timestamp of the latest block in the cache (if any). + pub fn latest_block_timestamp(&self) -> Option { + self.inner.block_cache.read().latest_block_timestamp() + } + /// Returns the lowest block number stored. pub fn lowest_block_number(&self) -> Option { self.inner.block_cache.read().lowest_block_number() diff --git a/beacon_node/genesis/src/eth1_genesis_service.rs b/beacon_node/genesis/src/eth1_genesis_service.rs index ed018d10ee..6cf94a5422 100644 --- a/beacon_node/genesis/src/eth1_genesis_service.rs +++ b/beacon_node/genesis/src/eth1_genesis_service.rs @@ -37,7 +37,31 @@ pub struct Eth1GenesisService { impl Eth1GenesisService { /// Creates a new service. Does not attempt to connect to the Eth1 node. + /// + /// Modifies the given `config` to make it more suitable to the task of listening to genesis. pub fn new(config: Eth1Config, log: Logger) -> Self { + let config = Eth1Config { + // Truncating the block cache makes searching for genesis more + // complicated. + block_cache_truncation: None, + // Scan large ranges of blocks when awaiting genesis. + blocks_per_log_query: 1_000, + // Only perform a single log request each time the eth1 node is + // polled. + // + // For small testnets this makes finding genesis much faster, + // as it usually happens within 1,000 blocks. + max_log_requests_per_update: Some(5), + // Only perform a single block request each time the eth1 node + // is polled. + // + // For small testnets, this is much faster as they do not have + // a `MIN_GENESIS_SECONDS`, so after `MIN_GENESIS_VALIDATOR_COUNT` + // has been reached only a single block needs to be read. + max_blocks_per_update: Some(5), + ..config + }; + Self { core: Service::new(config, log), highest_processed_block: Arc::new(Mutex::new(None)), @@ -81,6 +105,7 @@ impl Eth1GenesisService { let service_4 = service.clone(); let log = service.core.log.clone(); let min_genesis_active_validator_count = spec.min_genesis_active_validator_count; + let min_genesis_time = spec.min_genesis_time; Delay::new(Instant::now() + update_interval) .map_err(|e| format!("Delay between genesis deposit checks failed: {:?}", e)) @@ -161,6 +186,9 @@ impl Eth1GenesisService { trace!( service_4.core.log, "No eth1 genesis block found"; + "latest_block_timestamp" => service_4.core.latest_block_timestamp(), + "min_genesis_time" => min_genesis_time, + "min_validator_count" => min_genesis_active_validator_count, "cached_blocks" => service_4.core.block_cache_len(), "cached_deposits" => service_4.core.deposit_cache_len(), "cache_head" => service_4.highest_known_block(), @@ -218,7 +246,7 @@ impl Eth1GenesisService { return false; } - self.is_valid_genesis_eth1_block::(block, &spec) + self.is_valid_genesis_eth1_block::(block, &spec, &self.core.log) .and_then(|val| { *highest_processed_block = Some(block.number); Ok(val) @@ -313,6 +341,7 @@ impl Eth1GenesisService { &self, target_block: &Eth1Block, spec: &ChainSpec, + log: &Logger, ) -> Result { if target_block.timestamp < spec.min_genesis_time { Ok(false) @@ -357,8 +386,16 @@ impl Eth1GenesisService { })?; process_activations(&mut local_state, spec); + let is_valid = is_valid_genesis_state(&local_state, spec); - Ok(is_valid_genesis_state(&local_state, spec)) + trace!( + log, + "Eth1 block inspected for genesis"; + "active_validators" => local_state.get_active_validator_indices(local_state.current_epoch()).len(), + "validators" => local_state.validators.len() + ); + + Ok(is_valid) } } diff --git a/beacon_node/src/cli.rs b/beacon_node/src/cli.rs index bf388edcf5..eba09a71ca 100644 --- a/beacon_node/src/cli.rs +++ b/beacon_node/src/cli.rs @@ -13,9 +13,9 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { Arg::with_name("network-dir") .long("network-dir") .value_name("DIR") - .help("Data directory for network keys.") + .help("Data directory for network keys. Defaults to network/ inside the beacon node \ + dir.") .takes_value(true) - .global(true) ) .arg( Arg::with_name("freezer-dir") @@ -23,7 +23,14 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { .value_name("DIR") .help("Data directory for the freezer database.") .takes_value(true) - .global(true) + ) + .arg( + Arg::with_name("testnet-dir") + .long("testnet-dir") + .value_name("DIR") + .help("Path to directory containing eth2_testnet specs. Defaults to \ + ~/.lighthouse/testnet.") + .takes_value(true) ) /* * Network parameters. diff --git a/beacon_node/src/config.rs b/beacon_node/src/config.rs index faaa40de7e..475a6475d6 100644 --- a/beacon_node/src/config.rs +++ b/beacon_node/src/config.rs @@ -9,12 +9,13 @@ use slog::{crit, info, Logger}; use std::fs; use std::net::Ipv4Addr; use std::path::PathBuf; -use types::{Epoch, Fork}; +use types::{Epoch, EthSpec, Fork}; pub const CLIENT_CONFIG_FILENAME: &str = "beacon-node.toml"; pub const ETH2_CONFIG_FILENAME: &str = "eth2-spec.toml"; pub const ETH2_TESTNET_DIR: &str = "testnet"; pub const BEACON_NODE_DIR: &str = "beacon"; +pub const NETWORK_DIR: &str = "network"; pub const SECONDS_PER_ETH1_BLOCK: u64 = 15; @@ -28,7 +29,7 @@ type Config = (ClientConfig, Eth2Config, Logger); /// The output of this function depends primarily upon the given `cli_args`, however it's behaviour /// may be influenced by other external services like the contents of the file system or the /// response of some remote server. -pub fn get_configs( +pub fn get_configs( cli_args: &ArgMatches, mut eth2_config: Eth2Config, core_log: Logger, @@ -41,16 +42,20 @@ pub fn get_configs( // // If it's not present, try and find the home directory (`~`) and push the default data // directory onto it. - // - // Note: the `config.data_dir` defines the _global_ lighthouse datadir, not just the beacon - // node specific datadir. - let data_dir: PathBuf = cli_args + client_config.data_dir = cli_args .value_of("datadir") .map(PathBuf::from) .or_else(|| dirs::home_dir().map(|home| home.join(".lighthouse").join(BEACON_NODE_DIR))) .ok_or_else(|| "Unable to find a home directory for the datadir".to_string())?; - client_config.data_dir = data_dir; + // Read the `--testnet-dir` flag. + // + // If it's not present, use the default dir. + client_config.testnet_dir = cli_args + .value_of("testnet-dir") + .map(PathBuf::from) + .or_else(|| dirs::home_dir().map(|home| home.join(".lighthouse").join(ETH2_TESTNET_DIR))) + .ok_or_else(|| "Unable to find a home directory for the testnet-dir".to_string())?; // When present, use an eth1 backend that generates deterministic junk. // @@ -79,6 +84,8 @@ pub fn get_configs( // If a network dir has been specified, override the `datadir` definition. if let Some(dir) = cli_args.value_of("network-dir") { client_config.network.network_dir = PathBuf::from(dir); + } else { + client_config.network.network_dir = client_config.data_dir.join(NETWORK_DIR); }; if let Some(listen_address_str) = cli_args.value_of("listen-address") { @@ -213,7 +220,7 @@ pub fn get_configs( // Whilst there is no large testnet or mainnet force the user to specify how they want // to start a new chain (e.g., from a genesis YAML file, another node, etc). if !client_config.data_dir.exists() { - init_new_client(&mut client_config, &mut eth2_config)? + init_new_client::(&mut client_config, &mut eth2_config)? } else { // If the `testnet` command was not provided, attempt to load an existing datadir and // continue with an existing chain. @@ -288,21 +295,20 @@ fn load_from_datadir(client_config: &mut ClientConfig, eth2_config: &mut Eth2Con } /// Create a new client with the default configuration. -fn init_new_client(client_config: &mut ClientConfig, eth2_config: &mut Eth2Config) -> Result<()> { +fn init_new_client( + client_config: &mut ClientConfig, + eth2_config: &mut Eth2Config, +) -> Result<()> { let spec = &mut eth2_config.spec; 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; - spec.genesis_fork = Fork { - previous_version: [0; 4], - current_version: [0, 0, 0, 42], - epoch: Epoch::new(0), - }; - let eth2_testnet_dir = Eth2TestnetDir::load(client_config.data_dir.join(ETH2_TESTNET_DIR)) - .map_err(|e| format!("Unable to open testnet dir: {}", e))?; + let testnet_dir = client_config.testnet_dir.clone(); + let eth2_testnet_dir: Eth2TestnetDir = Eth2TestnetDir::load(testnet_dir.clone()) + .map_err(|e| format!("Unable to open testnet dir at {:?}: {}", testnet_dir, e))?; client_config.eth1.deposit_contract_address = format!("{:?}", eth2_testnet_dir.deposit_contract_address()?); diff --git a/beacon_node/src/lib.rs b/beacon_node/src/lib.rs index f127cd93bf..afa516ec7b 100644 --- a/beacon_node/src/lib.rs +++ b/beacon_node/src/lib.rs @@ -60,7 +60,7 @@ impl ProductionBeaconNode { // TODO: the eth2 config in the env is being modified. // // See https://github.com/sigp/lighthouse/issues/602 - get_configs(&matches, context.eth2_config.clone(), log) + get_configs::(&matches, context.eth2_config.clone(), log) .into_future() .and_then(move |(client_config, eth2_config, _log)| { context.eth2_config = eth2_config; diff --git a/eth2/utils/eth2_testnet/src/lib.rs b/eth2/utils/eth2_testnet/src/lib.rs index b911c242cd..e0701099cb 100644 --- a/eth2/utils/eth2_testnet/src/lib.rs +++ b/eth2/utils/eth2_testnet/src/lib.rs @@ -10,38 +10,40 @@ use eth2_libp2p::Enr; use std::fs::{create_dir_all, File}; use std::path::PathBuf; -use types::Address; +use types::{Address, BeaconState, EthSpec}; pub const ADDRESS_FILE: &str = "deposit_contract.txt"; pub const DEPLOY_BLOCK_FILE: &str = "deploy_block.txt"; pub const MIN_GENESIS_TIME_FILE: &str = "min_genesis_time.txt"; -pub const BOOT_NODES_FILE: &str = "boot_nodes.json"; +pub const BOOT_NODES_FILE: &str = "boot_enr.json"; +pub const GENESIS_STATE_FILE: &str = "genesis.ssz"; #[derive(Clone, PartialEq, Debug)] -pub struct Eth2TestnetDir { - deposit_contract_address: String, +pub struct Eth2TestnetDir { + pub deposit_contract_address: String, pub deposit_contract_deploy_block: u64, pub min_genesis_time: u64, - pub boot_nodes: Vec, + pub boot_enr: Option>, + pub genesis_state: Option>, } -impl Eth2TestnetDir { - pub fn new( - base_dir: PathBuf, - deposit_contract_address: String, - deposit_contract_deploy_block: u64, - min_genesis_time: u64, - boot_nodes: Vec, - ) -> Result { +impl Eth2TestnetDir { + // Write the files to the directory, only if the directory doesn't already exist. + pub fn write_to_file(&self, base_dir: PathBuf) -> Result<(), String> { if base_dir.exists() { return Err("Testnet directory already exists".to_string()); } + self.force_write_to_file(base_dir) + } + + // Write the files to the directory, even if the directory already exists. + pub fn force_write_to_file(&self, base_dir: PathBuf) -> Result<(), String> { create_dir_all(&base_dir) .map_err(|e| format!("Unable to create testnet directory: {:?}", e))?; macro_rules! write_to_file { - ($file: ident, $variable: ident) => { + ($file: ident, $variable: expr) => { File::create(base_dir.join($file)) .map_err(|e| format!("Unable to create {}: {:?}", $file, e)) .and_then(|file| { @@ -51,17 +53,19 @@ impl Eth2TestnetDir { }; } - write_to_file!(ADDRESS_FILE, deposit_contract_address); - write_to_file!(DEPLOY_BLOCK_FILE, deposit_contract_deploy_block); - write_to_file!(MIN_GENESIS_TIME_FILE, min_genesis_time); - write_to_file!(BOOT_NODES_FILE, boot_nodes); + write_to_file!(ADDRESS_FILE, self.deposit_contract_address); + write_to_file!(DEPLOY_BLOCK_FILE, self.deposit_contract_deploy_block); + write_to_file!(MIN_GENESIS_TIME_FILE, self.min_genesis_time); - Ok(Self { - deposit_contract_address, - deposit_contract_deploy_block, - min_genesis_time, - boot_nodes, - }) + 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); + } + + Ok(()) } pub fn load(base_dir: PathBuf) -> Result { @@ -76,16 +80,28 @@ impl Eth2TestnetDir { }; } + macro_rules! optional_load_from_file { + ($file: ident) => { + if base_dir.join($file).exists() { + Some(load_from_file!($file)) + } else { + None + } + }; + } + let deposit_contract_address = load_from_file!(ADDRESS_FILE); let deposit_contract_deploy_block = load_from_file!(DEPLOY_BLOCK_FILE); let min_genesis_time = load_from_file!(MIN_GENESIS_TIME_FILE); - let boot_nodes = load_from_file!(BOOT_NODES_FILE); + let boot_enr = optional_load_from_file!(BOOT_NODES_FILE); + let genesis_state = optional_load_from_file!(GENESIS_STATE_FILE); Ok(Self { deposit_contract_address, deposit_contract_deploy_block, min_genesis_time, - boot_nodes, + boot_enr, + genesis_state, }) } @@ -104,6 +120,9 @@ impl Eth2TestnetDir { mod tests { use super::*; use tempdir::TempDir; + use types::MinimalEthSpec; + + type E = MinimalEthSpec; #[test] fn round_trip() { @@ -113,15 +132,19 @@ mod tests { let deposit_contract_deploy_block = 42; let min_genesis_time = 1337; - let testnet = Eth2TestnetDir::new( - base_dir.clone(), - deposit_contract_address.clone(), - deposit_contract_deploy_block, + let testnet: Eth2TestnetDir = Eth2TestnetDir { + deposit_contract_address: deposit_contract_address.clone(), + deposit_contract_deploy_block: deposit_contract_deploy_block, min_genesis_time, // TODO: add some Enr for testing. - vec![], - ) - .expect("should create struct"); + boot_enr: None, + // TODO: add a genesis state for testing. + genesis_state: None, + }; + + testnet + .write_to_file(base_dir.clone()) + .expect("should write to file"); let decoded = Eth2TestnetDir::load(base_dir).expect("should load struct"); diff --git a/lcli/Cargo.toml b/lcli/Cargo.toml index 48194497d4..611ff55644 100644 --- a/lcli/Cargo.toml +++ b/lcli/Cargo.toml @@ -24,3 +24,4 @@ environment = { path = "../lighthouse/environment" } web3 = "0.8.0" eth2_testnet = { path = "../eth2/utils/eth2_testnet" } dirs = "2.0" +genesis = { path = "../beacon_node/genesis" } diff --git a/lcli/src/deploy_deposit_contract.rs b/lcli/src/deploy_deposit_contract.rs index d039f8e875..4db463f400 100644 --- a/lcli/src/deploy_deposit_contract.rs +++ b/lcli/src/deploy_deposit_contract.rs @@ -8,8 +8,6 @@ use std::path::PathBuf; use types::EthSpec; use web3::{transports::Http, Web3}; -pub const DEFAULT_DATA_DIR: &str = ".lighthouse/testnet"; - pub fn run(mut env: Environment, matches: &ArgMatches) -> Result<(), String> { let min_genesis_time = matches .value_of("min-genesis-time") @@ -29,10 +27,7 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< .and_then(|output| output.parse::().map_err(|_| ())) .unwrap_or_else(|_| { dirs::home_dir() - .map(|mut home| { - home.push(DEFAULT_DATA_DIR); - home - }) + .map(|home| home.join(".lighthouse").join("testnet")) .expect("should locate home directory") }); @@ -91,12 +86,15 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< info!("Writing config to {:?}", output_dir); - Eth2TestnetDir::new( - output_dir, - format!("{}", deposit_contract.address()), - deploy_block.as_u64(), + let testnet_dir: Eth2TestnetDir = Eth2TestnetDir { + deposit_contract_address: format!("{}", deposit_contract.address()), + deposit_contract_deploy_block: deploy_block.as_u64(), min_genesis_time, - )?; + boot_enr: None, + genesis_state: None, + }; + + testnet_dir.write_to_file(output_dir)?; Ok(()) } diff --git a/lcli/src/eth1_genesis.rs b/lcli/src/eth1_genesis.rs new file mode 100644 index 0000000000..c2e32286cd --- /dev/null +++ b/lcli/src/eth1_genesis.rs @@ -0,0 +1,67 @@ +use clap::ArgMatches; +use environment::Environment; +use eth2_testnet::Eth2TestnetDir; +use futures::Future; +use genesis::{Eth1Config, Eth1GenesisService}; +use std::path::PathBuf; +use std::time::Duration; +use types::{EthSpec, Fork}; + +/// Interval between polling the eth1 node for genesis information. +pub const ETH1_GENESIS_UPDATE_INTERVAL_MILLIS: u64 = 7_000; +pub const SECONDS_PER_ETH1_BLOCK: u64 = 15; + +pub fn run(mut env: Environment, matches: &ArgMatches) -> Result<(), String> { + let endpoint = matches + .value_of("eth1-endpoint") + .ok_or_else(|| "eth1-endpoint not specified")?; + + let testnet_dir = matches + .value_of("testnet-dir") + .ok_or_else(|| ()) + .and_then(|dir| dir.parse::().map_err(|_| ())) + .unwrap_or_else(|_| { + dirs::home_dir() + .map(|home| home.join(".lighthouse").join("testnet")) + .expect("should locate home directory") + }); + + let mut eth2_testnet_dir: Eth2TestnetDir = Eth2TestnetDir::load(testnet_dir.clone())?; + + let mut config = Eth1Config::default(); + config.endpoint = endpoint.to_string(); + config.deposit_contract_address = eth2_testnet_dir.deposit_contract_address.clone(); + config.deposit_contract_deploy_block = eth2_testnet_dir.deposit_contract_deploy_block; + config.lowest_cached_block_number = eth2_testnet_dir.deposit_contract_deploy_block; + + let genesis_service = Eth1GenesisService::new(config, env.core_context().log.clone()); + let mut spec = env.core_context().eth2_config.spec.clone(); + + spec.min_genesis_time = eth2_testnet_dir.min_genesis_time; + + 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; + + // Note: these are hard-coded hacky values. This should be fixed when we can load a testnet + // dir from the `Eth2TestnetDir`. + spec.eth1_follow_distance = 16; + spec.seconds_per_day = SECONDS_PER_ETH1_BLOCK * spec.eth1_follow_distance * 2; + + let future = genesis_service + .wait_for_genesis_state( + Duration::from_millis(ETH1_GENESIS_UPDATE_INTERVAL_MILLIS), + spec, + ) + .map(move |genesis_state| { + eth2_testnet_dir.genesis_state = Some(genesis_state); + eth2_testnet_dir.force_write_to_file(testnet_dir) + }); + + env.runtime() + .block_on(future) + .map_err(|e| format!("Failed to find genesis: {}", e))??; + + Ok(()) +} diff --git a/lcli/src/main.rs b/lcli/src/main.rs index 2999b2cfa9..bc16737c2a 100644 --- a/lcli/src/main.rs +++ b/lcli/src/main.rs @@ -2,6 +2,7 @@ extern crate log; mod deploy_deposit_contract; +mod eth1_genesis; mod parse_hex; mod pycli; mod refund_deposit_contract; @@ -198,6 +199,29 @@ fn main() { .help("The eth1 accounts[] index which will send the transaction"), ) ) + .subcommand( + SubCommand::with_name("eth1-genesis") + .about( + "Listens to the eth1 chain and finds the genesis beacon state", + ) + .arg( + Arg::with_name("testnet-dir") + .short("d") + .long("testnet-dir") + .value_name("PATH") + .takes_value(true) + .help("The testnet dir. Defaults to ~/.lighthouse/testnet"), + ) + .arg( + Arg::with_name("eth1-endpoint") + .short("e") + .long("eth1-endpoint") + .value_name("HTTP_SERVER") + .takes_value(true) + .default_value("http://localhost:8545") + .help("The URL to the eth1 JSON-RPC http API."), + ) + ) .subcommand( SubCommand::with_name("pycli") .about("TODO") @@ -216,7 +240,7 @@ fn main() { let env = EnvironmentBuilder::minimal() .multi_threaded_tokio_runtime() .expect("should start tokio runtime") - .null_logger() + .async_logger("trace") .expect("should start null logger") .build() .expect("should build env"); @@ -257,7 +281,6 @@ fn main() { "mainnet" => genesis_yaml::(num_validators, genesis_time, file), _ => unreachable!("guarded by slog possible_values"), }; - info!("Genesis state YAML file created. Exiting successfully."); } ("transition-blocks", Some(matches)) => run_transition_blocks(matches) @@ -275,6 +298,8 @@ fn main() { refund_deposit_contract::run::(env, matches) .unwrap_or_else(|e| error!("Failed to run refund-deposit-contract command: {}", e)) } + ("eth1-genesis", Some(matches)) => eth1_genesis::run::(env, matches) + .unwrap_or_else(|e| error!("Failed to run eth1-genesis command: {}", e)), (other, _) => error!("Unknown subcommand {}. See --help.", other), } } diff --git a/lcli/src/refund_deposit_contract.rs b/lcli/src/refund_deposit_contract.rs index 21e5452ea1..3f8c9cafa3 100644 --- a/lcli/src/refund_deposit_contract.rs +++ b/lcli/src/refund_deposit_contract.rs @@ -11,8 +11,6 @@ use web3::{ Web3, }; -pub const DEFAULT_DATA_DIR: &str = ".lighthouse/testnet"; - /// `keccak("steal()")[0..4]` pub const DEPOSIT_ROOT_FN_SIGNATURE: &[u8] = &[0xcf, 0x7a, 0x89, 0x65]; @@ -35,14 +33,11 @@ pub fn run(mut env: Environment, matches: &ArgMatches) -> Result< .and_then(|dir| dir.parse::().map_err(|_| ())) .unwrap_or_else(|_| { dirs::home_dir() - .map(|mut home| { - home.push(DEFAULT_DATA_DIR); - home - }) + .map(|home| home.join(".lighthouse").join("testnet")) .expect("should locate home directory") }); - let eth2_testnet_dir = Eth2TestnetDir::load(testnet_dir)?; + let eth2_testnet_dir: Eth2TestnetDir = Eth2TestnetDir::load(testnet_dir)?; let (_event_loop, transport) = Http::new(&endpoint).map_err(|e| { format!(