Directory restructure (#1532)
Closes #1487 Closes #1427 Directory restructure in accordance with #1487. Also has temporary migration code to move the old directories into new structure. Also extracts all default directory names and utility functions into a `directory` crate to avoid repetitio. ~Since `validator_definition.yaml` stores absolute paths, users will have to manually change the keystore paths or delete the file to get the validators picked up by the vc.~. `validator_definition.yaml` is migrated as well from the default directories. Co-authored-by: realbigsean <seananderson33@gmail.com> Co-authored-by: Paul Hauner <paul@paulhauner.com>
This commit is contained in:
		
							parent
							
								
									dffc56ef1d
								
							
						
					
					
						commit
						8e20176337
					
				
							
								
								
									
										18
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										18
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -9,6 +9,7 @@ dependencies = [ | ||||
|  "clap", | ||||
|  "clap_utils", | ||||
|  "deposit_contract", | ||||
|  "directory", | ||||
|  "dirs", | ||||
|  "environment", | ||||
|  "eth2_keystore", | ||||
| @ -377,6 +378,7 @@ dependencies = [ | ||||
|  "clap_utils", | ||||
|  "client", | ||||
|  "ctrlc", | ||||
|  "directory", | ||||
|  "dirs", | ||||
|  "environment", | ||||
|  "eth2_config", | ||||
| @ -758,6 +760,7 @@ version = "0.2.0" | ||||
| dependencies = [ | ||||
|  "beacon_chain", | ||||
|  "bus", | ||||
|  "directory", | ||||
|  "dirs", | ||||
|  "environment", | ||||
|  "error-chain", | ||||
| @ -1216,6 +1219,16 @@ dependencies = [ | ||||
|  "generic-array 0.14.4", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "directory" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "clap", | ||||
|  "clap_utils", | ||||
|  "dirs", | ||||
|  "eth2_testnet_config", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "dirs" | ||||
| version = "2.0.2" | ||||
| @ -1522,6 +1535,7 @@ name = "eth2_libp2p" | ||||
| version = "0.2.0" | ||||
| dependencies = [ | ||||
|  "base64 0.12.3", | ||||
|  "directory", | ||||
|  "dirs", | ||||
|  "discv5", | ||||
|  "environment", | ||||
| @ -2567,6 +2581,7 @@ dependencies = [ | ||||
|  "clap", | ||||
|  "clap_utils", | ||||
|  "deposit_contract", | ||||
|  "directory", | ||||
|  "dirs", | ||||
|  "environment", | ||||
|  "eth2_keystore", | ||||
| @ -2929,6 +2944,7 @@ dependencies = [ | ||||
|  "boot_node", | ||||
|  "clap", | ||||
|  "clap_utils", | ||||
|  "directory", | ||||
|  "env_logger", | ||||
|  "environment", | ||||
|  "eth2_testnet_config", | ||||
| @ -5829,7 +5845,6 @@ dependencies = [ | ||||
|  "compare_fields_derive", | ||||
|  "criterion", | ||||
|  "derivative", | ||||
|  "dirs", | ||||
|  "eth2_hashing", | ||||
|  "eth2_interop_keypairs", | ||||
|  "eth2_ssz", | ||||
| @ -6022,6 +6037,7 @@ dependencies = [ | ||||
|  "clap", | ||||
|  "clap_utils", | ||||
|  "deposit_contract", | ||||
|  "directory", | ||||
|  "dirs", | ||||
|  "environment", | ||||
|  "eth2_config", | ||||
|  | ||||
| @ -20,6 +20,7 @@ members = [ | ||||
|     "common/compare_fields", | ||||
|     "common/compare_fields_derive", | ||||
|     "common/deposit_contract", | ||||
|     "common/directory", | ||||
|     "common/eth2_config", | ||||
|     "common/eth2_interop_keypairs", | ||||
|     "common/eth2_testnet_config", | ||||
|  | ||||
| @ -24,6 +24,7 @@ eth2_testnet_config = { path = "../common/eth2_testnet_config" } | ||||
| web3 = "0.11.0" | ||||
| futures = { version = "0.3.5", features = ["compat"] } | ||||
| clap_utils = { path = "../common/clap_utils" } | ||||
| directory = { path = "../common/directory" } | ||||
| eth2_wallet = { path = "../crypto/eth2_wallet" } | ||||
| eth2_wallet_manager = { path = "../common/eth2_wallet_manager" } | ||||
| rand = "0.7.2" | ||||
|  | ||||
| @ -1,10 +1,8 @@ | ||||
| use account_utils::PlainText; | ||||
| use account_utils::{read_input_from_user, strip_off_newlines}; | ||||
| use clap::ArgMatches; | ||||
| use eth2_wallet::bip39::{Language, Mnemonic}; | ||||
| use std::fs; | ||||
| use std::fs::create_dir_all; | ||||
| use std::path::{Path, PathBuf}; | ||||
| use std::path::PathBuf; | ||||
| use std::str::from_utf8; | ||||
| use std::thread::sleep; | ||||
| use std::time::Duration; | ||||
| @ -12,26 +10,6 @@ use std::time::Duration; | ||||
| pub const MNEMONIC_PROMPT: &str = "Enter the mnemonic phrase:"; | ||||
| pub const WALLET_NAME_PROMPT: &str = "Enter wallet name:"; | ||||
| 
 | ||||
| pub fn ensure_dir_exists<P: AsRef<Path>>(path: P) -> Result<(), String> { | ||||
|     let path = path.as_ref(); | ||||
| 
 | ||||
|     if !path.exists() { | ||||
|         create_dir_all(path).map_err(|e| format!("Unable to create {:?}: {:?}", path, e))?; | ||||
|     } | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub fn base_wallet_dir(matches: &ArgMatches, arg: &'static str) -> Result<PathBuf, String> { | ||||
|     clap_utils::parse_path_with_default_in_home_dir( | ||||
|         matches, | ||||
|         arg, | ||||
|         PathBuf::new().join(".lighthouse").join("wallets"), | ||||
|     ) | ||||
| } | ||||
| 
 | ||||
| /// Reads in a mnemonic from the user. If the file path is provided, read from it. Otherwise, read
 | ||||
| /// from an interactive prompt using tty, unless the `--stdin-inputs` flag is provided.
 | ||||
| pub fn read_mnemonic_from_cli( | ||||
|     mnemonic_path: Option<PathBuf>, | ||||
|     stdin_inputs: bool, | ||||
|  | ||||
| @ -10,7 +10,7 @@ use types::EthSpec; | ||||
| pub const CMD: &str = "account_manager"; | ||||
| pub const SECRETS_DIR_FLAG: &str = "secrets-dir"; | ||||
| pub const VALIDATOR_DIR_FLAG: &str = "validator-dir"; | ||||
| pub const BASE_DIR_FLAG: &str = "base-dir"; | ||||
| pub const WALLETS_DIR_FLAG: &str = "wallets-dir"; | ||||
| 
 | ||||
| pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|     App::new(CMD) | ||||
|  | ||||
| @ -1,10 +1,13 @@ | ||||
| use crate::common::read_wallet_name_from_cli; | ||||
| use crate::wallet::create::STDIN_INPUTS_FLAG; | ||||
| use crate::{common::ensure_dir_exists, SECRETS_DIR_FLAG, VALIDATOR_DIR_FLAG}; | ||||
| use crate::{SECRETS_DIR_FLAG, WALLETS_DIR_FLAG}; | ||||
| use account_utils::{ | ||||
|     random_password, read_password_from_user, strip_off_newlines, validator_definitions, PlainText, | ||||
| }; | ||||
| use clap::{App, Arg, ArgMatches}; | ||||
| use directory::{ | ||||
|     ensure_dir_exists, parse_path_or_default_with_flag, DEFAULT_SECRET_DIR, DEFAULT_WALLET_DIR, | ||||
| }; | ||||
| use environment::Environment; | ||||
| use eth2_wallet_manager::WalletManager; | ||||
| use std::ffi::OsStr; | ||||
| @ -14,7 +17,6 @@ use types::EthSpec; | ||||
| use validator_dir::Builder as ValidatorDirBuilder; | ||||
| 
 | ||||
| pub const CMD: &str = "create"; | ||||
| pub const BASE_DIR_FLAG: &str = "base-dir"; | ||||
| pub const WALLET_NAME_FLAG: &str = "wallet-name"; | ||||
| pub const WALLET_PASSWORD_FLAG: &str = "wallet-password"; | ||||
| pub const DEPOSIT_GWEI_FLAG: &str = "deposit-gwei"; | ||||
| @ -44,14 +46,12 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|                 .takes_value(true), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name(VALIDATOR_DIR_FLAG) | ||||
|                 .long(VALIDATOR_DIR_FLAG) | ||||
|                 .value_name("VALIDATOR_DIRECTORY") | ||||
|                 .help( | ||||
|                     "The path where the validator directories will be created. \ | ||||
|                     Defaults to ~/.lighthouse/validators",
 | ||||
|                 ) | ||||
|                 .takes_value(true), | ||||
|             Arg::with_name(WALLETS_DIR_FLAG) | ||||
|                 .long(WALLETS_DIR_FLAG) | ||||
|                 .value_name(WALLETS_DIR_FLAG) | ||||
|                 .help("A path containing Eth2 EIP-2386 wallets. Defaults to ~/.lighthouse/{testnet}/wallets") | ||||
|                 .takes_value(true) | ||||
|                 .conflicts_with("datadir"), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name(SECRETS_DIR_FLAG) | ||||
| @ -59,8 +59,9 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|                 .value_name("SECRETS_DIR") | ||||
|                 .help( | ||||
|                     "The path where the validator keystore passwords will be stored. \ | ||||
|                     Defaults to ~/.lighthouse/secrets",
 | ||||
|                     Defaults to ~/.lighthouse/{testnet}/secrets",
 | ||||
|                 ) | ||||
|                 .conflicts_with("datadir") | ||||
|                 .takes_value(true), | ||||
|         ) | ||||
|         .arg( | ||||
| @ -111,23 +112,25 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
| pub fn cli_run<T: EthSpec>( | ||||
|     matches: &ArgMatches, | ||||
|     mut env: Environment<T>, | ||||
|     wallet_base_dir: PathBuf, | ||||
|     validator_dir: PathBuf, | ||||
| ) -> Result<(), String> { | ||||
|     let spec = env.core_context().eth2_config.spec; | ||||
| 
 | ||||
|     let name: Option<String> = clap_utils::parse_optional(matches, WALLET_NAME_FLAG)?; | ||||
|     let stdin_inputs = matches.is_present(STDIN_INPUTS_FLAG); | ||||
|     let wallet_base_dir = if matches.value_of("datadir").is_some() { | ||||
|         let path: PathBuf = clap_utils::parse_required(matches, "datadir")?; | ||||
|         path.join(DEFAULT_WALLET_DIR) | ||||
|     } else { | ||||
|         parse_path_or_default_with_flag(matches, WALLETS_DIR_FLAG, DEFAULT_WALLET_DIR)? | ||||
|     }; | ||||
|     let secrets_dir = if matches.value_of("datadir").is_some() { | ||||
|         let path: PathBuf = clap_utils::parse_required(matches, "datadir")?; | ||||
|         path.join(DEFAULT_SECRET_DIR) | ||||
|     } else { | ||||
|         parse_path_or_default_with_flag(matches, SECRETS_DIR_FLAG, DEFAULT_SECRET_DIR)? | ||||
|     }; | ||||
| 
 | ||||
|     let validator_dir = clap_utils::parse_path_with_default_in_home_dir( | ||||
|         matches, | ||||
|         VALIDATOR_DIR_FLAG, | ||||
|         PathBuf::new().join(".lighthouse").join("validators"), | ||||
|     )?; | ||||
|     let secrets_dir = clap_utils::parse_path_with_default_in_home_dir( | ||||
|         matches, | ||||
|         SECRETS_DIR_FLAG, | ||||
|         PathBuf::new().join(".lighthouse").join("secrets"), | ||||
|     )?; | ||||
|     let deposit_gwei = clap_utils::parse_optional(matches, DEPOSIT_GWEI_FLAG)? | ||||
|         .unwrap_or_else(|| spec.max_effective_balance); | ||||
|     let count: Option<usize> = clap_utils::parse_optional(matches, COUNT_FLAG)?; | ||||
| @ -136,6 +139,9 @@ pub fn cli_run<T: EthSpec>( | ||||
|     ensure_dir_exists(&validator_dir)?; | ||||
|     ensure_dir_exists(&secrets_dir)?; | ||||
| 
 | ||||
|     eprintln!("secrets-dir path {:?}", secrets_dir); | ||||
|     eprintln!("wallets-dir path {:?}", wallet_base_dir); | ||||
| 
 | ||||
|     let starting_validator_count = existing_validator_count(&validator_dir)?; | ||||
| 
 | ||||
|     let n = match (count, at_most) { | ||||
| @ -166,7 +172,7 @@ pub fn cli_run<T: EthSpec>( | ||||
|     let wallet_password = read_wallet_password_from_cli(wallet_password_path, stdin_inputs)?; | ||||
| 
 | ||||
|     let mgr = WalletManager::open(&wallet_base_dir) | ||||
|         .map_err(|e| format!("Unable to open --{}: {:?}", BASE_DIR_FLAG, e))?; | ||||
|         .map_err(|e| format!("Unable to open --{}: {:?}", WALLETS_DIR_FLAG, e))?; | ||||
| 
 | ||||
|     let mut wallet = mgr | ||||
|         .wallet_by_name(&wallet_name) | ||||
|  | ||||
| @ -46,16 +46,6 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|             The deposit contract address will be determined by the --testnet-dir flag on the \ | ||||
|             primary Lighthouse binary.",
 | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name(VALIDATOR_DIR_FLAG) | ||||
|                 .long(VALIDATOR_DIR_FLAG) | ||||
|                 .value_name("VALIDATOR_DIRECTORY") | ||||
|                 .help( | ||||
|                     "The path to the validator client data directory. \ | ||||
|                     Defaults to ~/.lighthouse/validators",
 | ||||
|                 ) | ||||
|                 .takes_value(true), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name(VALIDATOR_FLAG) | ||||
|                 .long(VALIDATOR_FLAG) | ||||
| @ -209,14 +199,10 @@ where | ||||
| pub fn cli_run<T: EthSpec>( | ||||
|     matches: &ArgMatches<'_>, | ||||
|     mut env: Environment<T>, | ||||
|     validator_dir: PathBuf, | ||||
| ) -> Result<(), String> { | ||||
|     let log = env.core_context().log().clone(); | ||||
| 
 | ||||
|     let data_dir = clap_utils::parse_path_with_default_in_home_dir( | ||||
|         matches, | ||||
|         VALIDATOR_DIR_FLAG, | ||||
|         PathBuf::new().join(".lighthouse").join("validators"), | ||||
|     )?; | ||||
|     let validator: String = clap_utils::parse_required(matches, VALIDATOR_FLAG)?; | ||||
|     let eth1_ipc_path: Option<PathBuf> = clap_utils::parse_optional(matches, ETH1_IPC_FLAG)?; | ||||
|     let eth1_http_url: Option<String> = clap_utils::parse_optional(matches, ETH1_HTTP_FLAG)?; | ||||
| @ -225,7 +211,7 @@ pub fn cli_run<T: EthSpec>( | ||||
|     let confirmation_batch_size: usize = | ||||
|         clap_utils::parse_required(matches, CONFIRMATION_BATCH_SIZE_FLAG)?; | ||||
| 
 | ||||
|     let manager = ValidatorManager::open(&data_dir) | ||||
|     let manager = ValidatorManager::open(&validator_dir) | ||||
|         .map_err(|e| format!("Unable to read --{}: {:?}", VALIDATOR_DIR_FLAG, e))?; | ||||
| 
 | ||||
|     let validators = match validator.as_ref() { | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| use crate::wallet::create::STDIN_INPUTS_FLAG; | ||||
| use crate::{common::ensure_dir_exists, VALIDATOR_DIR_FLAG}; | ||||
| use account_utils::{ | ||||
|     eth2_keystore::Keystore, | ||||
|     read_password_from_user, | ||||
| @ -55,16 +54,6 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|                 .required_unless(KEYSTORE_FLAG) | ||||
|                 .takes_value(true), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name(VALIDATOR_DIR_FLAG) | ||||
|                 .long(VALIDATOR_DIR_FLAG) | ||||
|                 .value_name("VALIDATOR_DIRECTORY") | ||||
|                 .help( | ||||
|                     "The path where the validator directories will be created. \ | ||||
|                     Defaults to ~/.lighthouse/validators",
 | ||||
|                 ) | ||||
|                 .takes_value(true), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name(STDIN_INPUTS_FLAG) | ||||
|                 .long(STDIN_INPUTS_FLAG) | ||||
| @ -77,19 +66,12 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|         ) | ||||
| } | ||||
| 
 | ||||
| pub fn cli_run(matches: &ArgMatches) -> Result<(), String> { | ||||
| pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), String> { | ||||
|     let keystore: Option<PathBuf> = clap_utils::parse_optional(matches, KEYSTORE_FLAG)?; | ||||
|     let keystores_dir: Option<PathBuf> = clap_utils::parse_optional(matches, DIR_FLAG)?; | ||||
|     let validator_dir = clap_utils::parse_path_with_default_in_home_dir( | ||||
|         matches, | ||||
|         VALIDATOR_DIR_FLAG, | ||||
|         PathBuf::new().join(".lighthouse").join("validators"), | ||||
|     )?; | ||||
|     let stdin_inputs = matches.is_present(STDIN_INPUTS_FLAG); | ||||
|     let reuse_password = matches.is_present(REUSE_PASSWORD_FLAG); | ||||
| 
 | ||||
|     ensure_dir_exists(&validator_dir)?; | ||||
| 
 | ||||
|     let mut defs = ValidatorDefinitions::open_or_create(&validator_dir) | ||||
|         .map_err(|e| format!("Unable to open {}: {:?}", CONFIG_FILENAME, e))?; | ||||
| 
 | ||||
|  | ||||
| @ -1,38 +1,21 @@ | ||||
| use crate::VALIDATOR_DIR_FLAG; | ||||
| use clap::{App, Arg, ArgMatches}; | ||||
| use clap::App; | ||||
| use std::path::PathBuf; | ||||
| use validator_dir::Manager as ValidatorManager; | ||||
| 
 | ||||
| pub const CMD: &str = "list"; | ||||
| 
 | ||||
| pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|     App::new(CMD) | ||||
|         .arg( | ||||
|             Arg::with_name(VALIDATOR_DIR_FLAG) | ||||
|                 .long(VALIDATOR_DIR_FLAG) | ||||
|                 .value_name("VALIDATOR_DIRECTORY") | ||||
|                 .help( | ||||
|                     "The path to search for validator directories. \ | ||||
|                     Defaults to ~/.lighthouse/validators",
 | ||||
|                 ) | ||||
|                 .takes_value(true), | ||||
|         ) | ||||
|         .about("Lists the names of all validators.") | ||||
|     App::new(CMD).about("Lists the names of all validators.") | ||||
| } | ||||
| 
 | ||||
| pub fn cli_run(matches: &ArgMatches<'_>) -> Result<(), String> { | ||||
|     let data_dir = clap_utils::parse_path_with_default_in_home_dir( | ||||
|         matches, | ||||
|         VALIDATOR_DIR_FLAG, | ||||
|         PathBuf::new().join(".lighthouse").join("validators"), | ||||
|     )?; | ||||
| 
 | ||||
|     let mgr = ValidatorManager::open(&data_dir) | ||||
| pub fn cli_run(validator_dir: PathBuf) -> Result<(), String> { | ||||
|     let mgr = ValidatorManager::open(&validator_dir) | ||||
|         .map_err(|e| format!("Unable to read --{}: {:?}", VALIDATOR_DIR_FLAG, e))?; | ||||
| 
 | ||||
|     for (name, _path) in mgr | ||||
|         .directory_names() | ||||
|         .map_err(|e| format!("Unable to list wallets: {:?}", e))? | ||||
|         .map_err(|e| format!("Unable to list validators: {:?}", e))? | ||||
|     { | ||||
|         println!("{}", name) | ||||
|     } | ||||
|  | ||||
| @ -4,9 +4,11 @@ pub mod import; | ||||
| pub mod list; | ||||
| pub mod recover; | ||||
| 
 | ||||
| use crate::common::base_wallet_dir; | ||||
| use crate::VALIDATOR_DIR_FLAG; | ||||
| use clap::{App, Arg, ArgMatches}; | ||||
| use directory::{parse_path_or_default_with_flag, DEFAULT_VALIDATOR_DIR}; | ||||
| use environment::Environment; | ||||
| use std::path::PathBuf; | ||||
| use types::EthSpec; | ||||
| 
 | ||||
| pub const CMD: &str = "validator"; | ||||
| @ -15,11 +17,16 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|     App::new(CMD) | ||||
|         .about("Provides commands for managing Eth2 validators.") | ||||
|         .arg( | ||||
|             Arg::with_name("base-dir") | ||||
|                 .long("base-dir") | ||||
|                 .value_name("BASE_DIRECTORY") | ||||
|                 .help("A path containing Eth2 EIP-2386 wallets. Defaults to ~/.lighthouse/wallets") | ||||
|                 .takes_value(true), | ||||
|             Arg::with_name(VALIDATOR_DIR_FLAG) | ||||
|                 .long(VALIDATOR_DIR_FLAG) | ||||
|                 .value_name("VALIDATOR_DIRECTORY") | ||||
|                 .help( | ||||
|                     "The path to search for validator directories. \ | ||||
|                     Defaults to ~/.lighthouse/{testnet}/validators",
 | ||||
|                 ) | ||||
|                 .takes_value(true) | ||||
|                 .global(true) | ||||
|                 .conflicts_with("datadir"), | ||||
|         ) | ||||
|         .subcommand(create::cli_app()) | ||||
|         .subcommand(deposit::cli_app()) | ||||
| @ -29,14 +36,20 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
| } | ||||
| 
 | ||||
| pub fn cli_run<T: EthSpec>(matches: &ArgMatches, env: Environment<T>) -> Result<(), String> { | ||||
|     let base_wallet_dir = base_wallet_dir(matches, "base-dir")?; | ||||
|     let validator_base_dir = if matches.value_of("datadir").is_some() { | ||||
|         let path: PathBuf = clap_utils::parse_required(matches, "datadir")?; | ||||
|         path.join(DEFAULT_VALIDATOR_DIR) | ||||
|     } else { | ||||
|         parse_path_or_default_with_flag(matches, VALIDATOR_DIR_FLAG, DEFAULT_VALIDATOR_DIR)? | ||||
|     }; | ||||
|     eprintln!("validator-dir path: {:?}", validator_base_dir); | ||||
| 
 | ||||
|     match matches.subcommand() { | ||||
|         (create::CMD, Some(matches)) => create::cli_run::<T>(matches, env, base_wallet_dir), | ||||
|         (deposit::CMD, Some(matches)) => deposit::cli_run::<T>(matches, env), | ||||
|         (import::CMD, Some(matches)) => import::cli_run(matches), | ||||
|         (list::CMD, Some(matches)) => list::cli_run(matches), | ||||
|         (recover::CMD, Some(matches)) => recover::cli_run(matches), | ||||
|         (create::CMD, Some(matches)) => create::cli_run::<T>(matches, env, validator_base_dir), | ||||
|         (deposit::CMD, Some(matches)) => deposit::cli_run::<T>(matches, env, validator_base_dir), | ||||
|         (import::CMD, Some(matches)) => import::cli_run(matches, validator_base_dir), | ||||
|         (list::CMD, Some(_)) => list::cli_run(validator_base_dir), | ||||
|         (recover::CMD, Some(matches)) => recover::cli_run(matches, validator_base_dir), | ||||
|         (unknown, _) => Err(format!( | ||||
|             "{} does not have a {} command. See --help", | ||||
|             CMD, unknown | ||||
|  | ||||
| @ -1,11 +1,13 @@ | ||||
| use super::create::STORE_WITHDRAW_FLAG; | ||||
| use crate::common::{ensure_dir_exists, read_mnemonic_from_cli}; | ||||
| use crate::common::read_mnemonic_from_cli; | ||||
| use crate::validator::create::COUNT_FLAG; | ||||
| use crate::wallet::create::STDIN_INPUTS_FLAG; | ||||
| use crate::{SECRETS_DIR_FLAG, VALIDATOR_DIR_FLAG}; | ||||
| use crate::SECRETS_DIR_FLAG; | ||||
| use account_utils::eth2_keystore::{keypair_from_secret, Keystore, KeystoreBuilder}; | ||||
| use account_utils::random_password; | ||||
| use clap::{App, Arg, ArgMatches}; | ||||
| use directory::ensure_dir_exists; | ||||
| use directory::{parse_path_or_default_with_flag, DEFAULT_SECRET_DIR}; | ||||
| use eth2_wallet::bip39::Seed; | ||||
| use eth2_wallet::{recover_validator_secret_from_mnemonic, KeyType, ValidatorKeystores}; | ||||
| use std::path::PathBuf; | ||||
| @ -48,23 +50,13 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|                 ) | ||||
|                 .takes_value(true) | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name(VALIDATOR_DIR_FLAG) | ||||
|                 .long(VALIDATOR_DIR_FLAG) | ||||
|                 .value_name("VALIDATOR_DIRECTORY") | ||||
|                 .help( | ||||
|                     "The path where the validator directories will be created. \ | ||||
|                     Defaults to ~/.lighthouse/validators",
 | ||||
|                 ) | ||||
|                 .takes_value(true), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name(SECRETS_DIR_FLAG) | ||||
|                 .long(SECRETS_DIR_FLAG) | ||||
|                 .value_name("SECRETS_DIR") | ||||
|                 .help( | ||||
|                     "The path where the validator keystore passwords will be stored. \ | ||||
|                     Defaults to ~/.lighthouse/secrets",
 | ||||
|                     Defaults to ~/.lighthouse/{testnet}/secrets",
 | ||||
|                 ) | ||||
|                 .takes_value(true), | ||||
|         ) | ||||
| @ -84,17 +76,13 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|         ) | ||||
| } | ||||
| 
 | ||||
| pub fn cli_run(matches: &ArgMatches) -> Result<(), String> { | ||||
|     let validator_dir = clap_utils::parse_path_with_default_in_home_dir( | ||||
|         matches, | ||||
|         VALIDATOR_DIR_FLAG, | ||||
|         PathBuf::new().join(".lighthouse").join("validators"), | ||||
|     )?; | ||||
|     let secrets_dir = clap_utils::parse_path_with_default_in_home_dir( | ||||
|         matches, | ||||
|         SECRETS_DIR_FLAG, | ||||
|         PathBuf::new().join(".lighthouse").join("secrets"), | ||||
|     )?; | ||||
| pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), String> { | ||||
|     let secrets_dir = if matches.value_of("datadir").is_some() { | ||||
|         let path: PathBuf = clap_utils::parse_required(matches, "datadir")?; | ||||
|         path.join(DEFAULT_SECRET_DIR) | ||||
|     } else { | ||||
|         parse_path_or_default_with_flag(matches, SECRETS_DIR_FLAG, DEFAULT_SECRET_DIR)? | ||||
|     }; | ||||
|     let first_index: u32 = clap_utils::parse_required(matches, FIRST_INDEX_FLAG)?; | ||||
|     let count: u32 = clap_utils::parse_required(matches, COUNT_FLAG)?; | ||||
|     let mnemonic_path: Option<PathBuf> = clap_utils::parse_optional(matches, MNEMONIC_FLAG)?; | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| use crate::common::read_wallet_name_from_cli; | ||||
| use crate::BASE_DIR_FLAG; | ||||
| use crate::WALLETS_DIR_FLAG; | ||||
| use account_utils::{ | ||||
|     is_password_sufficiently_complex, random_password, read_password_from_user, strip_off_newlines, | ||||
| }; | ||||
| @ -80,7 +80,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|         ) | ||||
| } | ||||
| 
 | ||||
| pub fn cli_run(matches: &ArgMatches, base_dir: PathBuf) -> Result<(), String> { | ||||
| pub fn cli_run(matches: &ArgMatches, wallet_base_dir: PathBuf) -> Result<(), String> { | ||||
|     let mnemonic_output_path: Option<PathBuf> = clap_utils::parse_optional(matches, MNEMONIC_FLAG)?; | ||||
| 
 | ||||
|     // Create a new random mnemonic.
 | ||||
| @ -88,7 +88,7 @@ pub fn cli_run(matches: &ArgMatches, base_dir: PathBuf) -> Result<(), String> { | ||||
|     // The `tiny-bip39` crate uses `thread_rng()` for this entropy.
 | ||||
|     let mnemonic = Mnemonic::new(MnemonicType::Words12, Language::English); | ||||
| 
 | ||||
|     let wallet = create_wallet_from_mnemonic(matches, &base_dir.as_path(), &mnemonic)?; | ||||
|     let wallet = create_wallet_from_mnemonic(matches, &wallet_base_dir.as_path(), &mnemonic)?; | ||||
| 
 | ||||
|     if let Some(path) = mnemonic_output_path { | ||||
|         create_with_600_perms(&path, mnemonic.phrase().as_bytes()) | ||||
| @ -121,7 +121,7 @@ pub fn cli_run(matches: &ArgMatches, base_dir: PathBuf) -> Result<(), String> { | ||||
| 
 | ||||
| pub fn create_wallet_from_mnemonic( | ||||
|     matches: &ArgMatches, | ||||
|     base_dir: &Path, | ||||
|     wallet_base_dir: &Path, | ||||
|     mnemonic: &Mnemonic, | ||||
| ) -> Result<LockedWallet, String> { | ||||
|     let name: Option<String> = clap_utils::parse_optional(matches, NAME_FLAG)?; | ||||
| @ -134,8 +134,8 @@ pub fn create_wallet_from_mnemonic( | ||||
|         unknown => return Err(format!("--{} {} is not supported", TYPE_FLAG, unknown)), | ||||
|     }; | ||||
| 
 | ||||
|     let mgr = WalletManager::open(&base_dir) | ||||
|         .map_err(|e| format!("Unable to open --{}: {:?}", BASE_DIR_FLAG, e))?; | ||||
|     let mgr = WalletManager::open(&wallet_base_dir) | ||||
|         .map_err(|e| format!("Unable to open --{}: {:?}", WALLETS_DIR_FLAG, e))?; | ||||
| 
 | ||||
|     let wallet_password: PlainText = match wallet_password_path { | ||||
|         Some(path) => { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| use crate::BASE_DIR_FLAG; | ||||
| use crate::WALLETS_DIR_FLAG; | ||||
| use clap::App; | ||||
| use eth2_wallet_manager::WalletManager; | ||||
| use std::path::PathBuf; | ||||
| @ -9,9 +9,9 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|     App::new(CMD).about("Lists the names of all wallets.") | ||||
| } | ||||
| 
 | ||||
| pub fn cli_run(base_dir: PathBuf) -> Result<(), String> { | ||||
|     let mgr = WalletManager::open(&base_dir) | ||||
|         .map_err(|e| format!("Unable to open --{}: {:?}", BASE_DIR_FLAG, e))?; | ||||
| pub fn cli_run(wallet_base_dir: PathBuf) -> Result<(), String> { | ||||
|     let mgr = WalletManager::open(&wallet_base_dir) | ||||
|         .map_err(|e| format!("Unable to open --{}: {:?}", WALLETS_DIR_FLAG, e))?; | ||||
| 
 | ||||
|     for (name, _uuid) in mgr | ||||
|         .wallets() | ||||
|  | ||||
| @ -2,11 +2,10 @@ pub mod create; | ||||
| pub mod list; | ||||
| pub mod recover; | ||||
| 
 | ||||
| use crate::{ | ||||
|     common::{base_wallet_dir, ensure_dir_exists}, | ||||
|     BASE_DIR_FLAG, | ||||
| }; | ||||
| use crate::WALLETS_DIR_FLAG; | ||||
| use clap::{App, Arg, ArgMatches}; | ||||
| use directory::{ensure_dir_exists, parse_path_or_default_with_flag, DEFAULT_WALLET_DIR}; | ||||
| use std::path::PathBuf; | ||||
| 
 | ||||
| pub const CMD: &str = "wallet"; | ||||
| 
 | ||||
| @ -14,11 +13,13 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|     App::new(CMD) | ||||
|         .about("Manage wallets, from which validator keys can be derived.") | ||||
|         .arg( | ||||
|             Arg::with_name(BASE_DIR_FLAG) | ||||
|                 .long(BASE_DIR_FLAG) | ||||
|                 .value_name("BASE_DIRECTORY") | ||||
|                 .help("A path containing Eth2 EIP-2386 wallets. Defaults to ~/.lighthouse/wallets") | ||||
|                 .takes_value(true), | ||||
|             Arg::with_name(WALLETS_DIR_FLAG) | ||||
|                 .long(WALLETS_DIR_FLAG) | ||||
|                 .value_name("WALLETS_DIRECTORY") | ||||
|                 .help("A path containing Eth2 EIP-2386 wallets. Defaults to ~/.lighthouse/{testnet}/wallets") | ||||
|                 .takes_value(true) | ||||
|                 .global(true) | ||||
|                 .conflicts_with("datadir"), | ||||
|         ) | ||||
|         .subcommand(create::cli_app()) | ||||
|         .subcommand(list::cli_app()) | ||||
| @ -26,13 +27,20 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
| } | ||||
| 
 | ||||
| pub fn cli_run(matches: &ArgMatches) -> Result<(), String> { | ||||
|     let base_dir = base_wallet_dir(matches, BASE_DIR_FLAG)?; | ||||
|     ensure_dir_exists(&base_dir)?; | ||||
|     let wallet_base_dir = if matches.value_of("datadir").is_some() { | ||||
|         let path: PathBuf = clap_utils::parse_required(matches, "datadir")?; | ||||
|         path.join(DEFAULT_WALLET_DIR) | ||||
|     } else { | ||||
|         parse_path_or_default_with_flag(matches, WALLETS_DIR_FLAG, DEFAULT_WALLET_DIR)? | ||||
|     }; | ||||
|     ensure_dir_exists(&wallet_base_dir)?; | ||||
| 
 | ||||
|     eprintln!("wallet-dir path: {:?}", wallet_base_dir); | ||||
| 
 | ||||
|     match matches.subcommand() { | ||||
|         (create::CMD, Some(matches)) => create::cli_run(matches, base_dir), | ||||
|         (list::CMD, Some(_)) => list::cli_run(base_dir), | ||||
|         (recover::CMD, Some(matches)) => recover::cli_run(matches, base_dir), | ||||
|         (create::CMD, Some(matches)) => create::cli_run(matches, wallet_base_dir), | ||||
|         (list::CMD, Some(_)) => list::cli_run(wallet_base_dir), | ||||
|         (recover::CMD, Some(matches)) => recover::cli_run(matches, wallet_base_dir), | ||||
|         (unknown, _) => Err(format!( | ||||
|             "{} does not have a {} command. See --help", | ||||
|             CMD, unknown | ||||
|  | ||||
| @ -30,6 +30,7 @@ tokio = { version = "0.2.21", features = ["time"] } | ||||
| exit-future = "0.2.0" | ||||
| dirs = "2.0.2" | ||||
| logging = { path = "../common/logging" } | ||||
| directory = {path = "../common/directory"} | ||||
| futures = "0.3.5" | ||||
| environment = { path = "../lighthouse/environment" } | ||||
| genesis = { path = "genesis" } | ||||
|  | ||||
| @ -41,3 +41,4 @@ lazy_static = "1.4.0" | ||||
| lighthouse_metrics = { path = "../../common/lighthouse_metrics" } | ||||
| time = "0.2.16" | ||||
| bus = "2.2.3" | ||||
| directory = {path = "../../common/directory"} | ||||
|  | ||||
| @ -1,11 +1,10 @@ | ||||
| use directory::DEFAULT_ROOT_DIR; | ||||
| use network::NetworkConfig; | ||||
| use serde_derive::{Deserialize, Serialize}; | ||||
| use std::fs; | ||||
| use std::path::PathBuf; | ||||
| use types::Graffiti; | ||||
| 
 | ||||
| pub const DEFAULT_DATADIR: &str = ".lighthouse"; | ||||
| 
 | ||||
| /// The number initial validators when starting the `Minimal`.
 | ||||
| const TESTNET_SPEC_CONSTANTS: &str = "minimal"; | ||||
| 
 | ||||
| @ -72,7 +71,7 @@ pub struct Config { | ||||
| impl Default for Config { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|             data_dir: PathBuf::from(DEFAULT_DATADIR), | ||||
|             data_dir: PathBuf::from(DEFAULT_ROOT_DIR), | ||||
|             db_name: "chain_db".to_string(), | ||||
|             freezer_db_path: None, | ||||
|             log_file: PathBuf::from(""), | ||||
|  | ||||
| @ -36,6 +36,7 @@ discv5 = { version = "0.1.0-alpha.12", features = ["libp2p"] } | ||||
| tiny-keccak = "2.0.2" | ||||
| environment = { path = "../../lighthouse/environment" } | ||||
| rand = "0.7.3" | ||||
| directory = { path = "../../common/directory" } | ||||
| regex = "1.3.9" | ||||
| 
 | ||||
| [dependencies.libp2p] | ||||
|  | ||||
| @ -1,5 +1,8 @@ | ||||
| use crate::types::GossipKind; | ||||
| use crate::{Enr, PeerIdSerialized}; | ||||
| use directory::{ | ||||
|     DEFAULT_BEACON_NODE_DIR, DEFAULT_HARDCODED_TESTNET, DEFAULT_NETWORK_DIR, DEFAULT_ROOT_DIR, | ||||
| }; | ||||
| use discv5::{Discv5Config, Discv5ConfigBuilder}; | ||||
| use libp2p::gossipsub::{ | ||||
|     GossipsubConfig, GossipsubConfigBuilder, GossipsubMessage, MessageId, ValidationMode, | ||||
| @ -74,9 +77,14 @@ pub struct Config { | ||||
| impl Default for Config { | ||||
|     /// Generate a default network configuration.
 | ||||
|     fn default() -> Self { | ||||
|         let mut network_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from(".")); | ||||
|         network_dir.push(".lighthouse"); | ||||
|         network_dir.push("network"); | ||||
|         // WARNING: this directory default should be always overrided with parameters
 | ||||
|         // from cli for specific networks.
 | ||||
|         let network_dir = dirs::home_dir() | ||||
|             .unwrap_or_else(|| PathBuf::from(".")) | ||||
|             .join(DEFAULT_ROOT_DIR) | ||||
|             .join(DEFAULT_HARDCODED_TESTNET) | ||||
|             .join(DEFAULT_BEACON_NODE_DIR) | ||||
|             .join(DEFAULT_NETWORK_DIR); | ||||
| 
 | ||||
|         // The function used to generate a gossipsub message id
 | ||||
|         // We use the first 8 bytes of SHA256(data) for content addressing
 | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| use beacon_chain::builder::PUBKEY_CACHE_FILENAME; | ||||
| use clap::ArgMatches; | ||||
| use clap_utils::BAD_TESTNET_DIR_MESSAGE; | ||||
| use client::{config::DEFAULT_DATADIR, ClientConfig, ClientGenesis}; | ||||
| use client::{ClientConfig, ClientGenesis}; | ||||
| use directory::{DEFAULT_BEACON_NODE_DIR, DEFAULT_NETWORK_DIR, DEFAULT_ROOT_DIR}; | ||||
| use eth2_libp2p::{multiaddr::Protocol, Enr, Multiaddr, NetworkConfig, PeerIdSerialized}; | ||||
| use eth2_testnet_config::Eth2TestnetConfig; | ||||
| use slog::{crit, info, warn, Logger}; | ||||
| @ -13,9 +14,6 @@ use std::net::{TcpListener, UdpSocket}; | ||||
| use std::path::PathBuf; | ||||
| use types::{ChainSpec, EthSpec, GRAFFITI_BYTES_LEN}; | ||||
| 
 | ||||
| pub const BEACON_NODE_DIR: &str = "beacon"; | ||||
| pub const NETWORK_DIR: &str = "network"; | ||||
| 
 | ||||
| /// Gets the fully-initialized global client.
 | ||||
| ///
 | ||||
| /// The top-level `clap` arguments should be provided as `cli_args`.
 | ||||
| @ -295,7 +293,7 @@ pub fn set_network_config( | ||||
|     if let Some(dir) = cli_args.value_of("network-dir") { | ||||
|         config.network_dir = PathBuf::from(dir); | ||||
|     } else { | ||||
|         config.network_dir = data_dir.join(NETWORK_DIR); | ||||
|         config.network_dir = data_dir.join(DEFAULT_NETWORK_DIR); | ||||
|     }; | ||||
| 
 | ||||
|     if let Some(listen_address_str) = cli_args.value_of("listen-address") { | ||||
| @ -456,11 +454,18 @@ pub fn get_data_dir(cli_args: &ArgMatches) -> PathBuf { | ||||
|     // Read the `--datadir` flag.
 | ||||
|     //
 | ||||
|     // If it's not present, try and find the home directory (`~`) and push the default data
 | ||||
|     // directory onto it.
 | ||||
|     // directory and the testnet name onto it.
 | ||||
| 
 | ||||
|     cli_args | ||||
|         .value_of("datadir") | ||||
|         .map(|path| PathBuf::from(path).join(BEACON_NODE_DIR)) | ||||
|         .or_else(|| dirs::home_dir().map(|home| home.join(DEFAULT_DATADIR).join(BEACON_NODE_DIR))) | ||||
|         .map(|path| PathBuf::from(path).join(DEFAULT_BEACON_NODE_DIR)) | ||||
|         .or_else(|| { | ||||
|             dirs::home_dir().map(|home| { | ||||
|                 home.join(DEFAULT_ROOT_DIR) | ||||
|                     .join(directory::get_testnet_name(cli_args)) | ||||
|                     .join(DEFAULT_BEACON_NODE_DIR) | ||||
|             }) | ||||
|         }) | ||||
|         .unwrap_or_else(|| PathBuf::from(".")) | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -40,12 +40,12 @@ keypairs. Creating a single validator looks like this: | ||||
| 	- `lighthouse account validator create --wallet-name wally --wallet-password wally.pass --count 1` | ||||
| 
 | ||||
| 
 | ||||
| In step (1), we created a wallet in `~/.lighthouse/wallets` with the name | ||||
| In step (1), we created a wallet in `~/.lighthouse/{testnet}/wallets` with the name | ||||
| `wally`. We encrypted this using a pre-defined password in the | ||||
| `wally.pass` file. Then, in step (2), we created one new validator in the | ||||
| `~/.lighthouse/validators` directory using `wally` (unlocking it with | ||||
| `~/.lighthouse/{testnet}/validators` directory using `wally` (unlocking it with | ||||
| `wally.pass`) and storing the passwords to the validators voting key in | ||||
| `~/.lighthouse/secrets`. | ||||
| `~/.lighthouse/{testnet}/secrets`. | ||||
| 
 | ||||
| Thanks to the hierarchical key derivation scheme, we can delete all of the | ||||
| aforementioned directories and then regenerate them as long as we remembered | ||||
| @ -63,14 +63,16 @@ There are three important directories in Lighthouse validator key management: | ||||
| 
 | ||||
| - `wallets/`: contains encrypted wallets which are used for hierarchical | ||||
| 	key derivation. | ||||
| 	- Defaults to `~/.lighthouse/wallets` | ||||
| 	- Defaults to `~/.lighthouse/{testnet}/wallets` | ||||
| - `validators/`: contains a directory for each validator containing | ||||
| 	encrypted keystores and other validator-specific data. | ||||
| 	- Defaults to `~/.lighthouse/validators` | ||||
| 	- Defaults to `~/.lighthouse/{testnet}/validators` | ||||
| - `secrets/`: since the validator signing keys are "hot", the validator process | ||||
| 	needs access to the passwords to decrypt the keystores in the validators | ||||
| 	dir. These passwords are stored here. | ||||
| 	- Defaults to `~/.lighthouse/secrets` | ||||
| 	- Defaults to `~/.lighthouse/{testnet}/secrets` | ||||
| 
 | ||||
| where `testnet` is the name of the testnet passed in the `--testnet` parameter (default is `medalla`). | ||||
| 
 | ||||
| When the validator client boots, it searches the `validators/` for directories | ||||
| containing voting keystores. When it discovers a keystore, it searches the | ||||
|  | ||||
| @ -41,7 +41,7 @@ OPTIONS: | ||||
|             The GWEI value of the deposit amount. Defaults to the minimum amount required for an active validator | ||||
|             (MAX_EFFECTIVE_BALANCE) | ||||
|         --secrets-dir <SECRETS_DIR> | ||||
|             The path where the validator keystore passwords will be stored. Defaults to ~/.lighthouse/secrets | ||||
|             The path where the validator keystore passwords will be stored. Defaults to ~/.lighthouse/{testnet}/secrets | ||||
| 
 | ||||
|     -s, --spec <TITLE> | ||||
|             Specifies the default eth2 spec type. [default: mainnet]  [possible values: mainnet, minimal, interop] | ||||
| @ -53,7 +53,7 @@ OPTIONS: | ||||
|             Path to directory containing eth2_testnet specs. Defaults to a hard-coded Lighthouse testnet. Only effective | ||||
|             if there is no existing database. | ||||
|         --validator-dir <VALIDATOR_DIRECTORY> | ||||
|             The path where the validator directories will be created. Defaults to ~/.lighthouse/validators | ||||
|             The path where the validator directories will be created. Defaults to ~/.lighthouse/{testnet}/validators | ||||
| 
 | ||||
|         --wallet-name <WALLET_NAME>                   Use the wallet identified by this name | ||||
|         --wallet-password <WALLET_PASSWORD_PATH> | ||||
| @ -73,10 +73,12 @@ This command will: | ||||
| 
 | ||||
| - Derive a single new BLS keypair from `wally`, updating it so that it generates a | ||||
|     new key next time. | ||||
| - Create a new directory in `~/.lighthouse/validators` containing: | ||||
| - Create a new directory in `~/.lighthouse/{testnet}/validators` containing: | ||||
|     - An encrypted keystore containing the validators voting keypair. | ||||
| 	- An `eth1_deposit_data.rlp` assuming the default deposit amount (`32 ETH` | ||||
| 		for most testnets and mainnet) which can be submitted to the deposit | ||||
| 		contract for the medalla testnet. Other testnets can be set via the | ||||
| 		`--testnet` CLI param. | ||||
| - Store a password to the validators voting keypair in `~/.lighthouse/secrets`. | ||||
| - Store a password to the validators voting keypair in `~/.lighthouse/{testnet}/secrets`. | ||||
| 
 | ||||
| where `testnet` is the name of the testnet passed in the `--testnet` parameter (default is `medalla`). | ||||
| @ -16,7 +16,7 @@ useful. | ||||
| ## Introducing the `validator_definitions.yml` file | ||||
| 
 | ||||
| The `validator_definitions.yml` file is located in the `validator-dir`, which | ||||
| defaults to `~/.lighthouse/validators`. It is a | ||||
| defaults to `~/.lighthouse/{testnet}/validators`. It is a | ||||
| [YAML](https://en.wikipedia.org/wiki/YAML) encoded file defining exactly which | ||||
| validators the validator client will (and won't) act for. | ||||
| 
 | ||||
| @ -92,7 +92,7 @@ name identical to the `voting_public_key` value. | ||||
| Lets assume the following directory structure: | ||||
| 
 | ||||
| ``` | ||||
| ~/.lighthouse/validators | ||||
| ~/.lighthouse/{testnet}/validators | ||||
| ├── john | ||||
| │   └── voting-keystore.json | ||||
| ├── sally | ||||
| @ -135,7 +135,7 @@ In order for the validator client to decrypt the validators, they will need to | ||||
| ensure their `secrets-dir` is organised as below: | ||||
| 
 | ||||
| ``` | ||||
| ~/.lighthouse/secrets | ||||
| ~/.lighthouse/{testnet}/secrets | ||||
| ├── 0xa5566f9ec3c6e1fdf362634ebec9ef7aceb0e460e5079714808388e5d48f4ae1e12897fed1bea951c17fa389d511e477 | ||||
| ├── 0xaa440c566fcf34dedf233baf56cf5fb05bb420d9663b4208272545608c27c13d5b08174518c758ecd814f158f2b4a337 | ||||
| └── 0x87a580d31d7bc69069b55f5a01995a610dd391a26dc9e36e81057a17211983a79266800ab8531f21f1083d7d84085007 | ||||
|  | ||||
							
								
								
									
										13
									
								
								common/directory/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								common/directory/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| [package] | ||||
| name = "directory" | ||||
| version = "0.1.0" | ||||
| authors = ["pawan <pawandhananjay@gmail.com>"] | ||||
| edition = "2018" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| clap = "2.33.0" | ||||
| clap_utils = {path = "../clap_utils"} | ||||
| dirs = "2.0.2" | ||||
| eth2_testnet_config = { path = "../eth2_testnet_config" } | ||||
							
								
								
									
										60
									
								
								common/directory/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								common/directory/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| use clap::ArgMatches; | ||||
| pub use eth2_testnet_config::DEFAULT_HARDCODED_TESTNET; | ||||
| use std::fs::create_dir_all; | ||||
| use std::path::{Path, PathBuf}; | ||||
| 
 | ||||
| /// Names for the default directories.
 | ||||
| pub const DEFAULT_ROOT_DIR: &str = ".lighthouse"; | ||||
| pub const DEFAULT_BEACON_NODE_DIR: &str = "beacon"; | ||||
| pub const DEFAULT_NETWORK_DIR: &str = "network"; | ||||
| pub const DEFAULT_VALIDATOR_DIR: &str = "validators"; | ||||
| pub const DEFAULT_SECRET_DIR: &str = "secrets"; | ||||
| pub const DEFAULT_WALLET_DIR: &str = "wallets"; | ||||
| 
 | ||||
| /// Base directory name for unnamed testnets passed through the --testnet-dir flag
 | ||||
| pub const CUSTOM_TESTNET_DIR: &str = "custom"; | ||||
| 
 | ||||
| /// Gets the testnet directory name
 | ||||
| ///
 | ||||
| /// Tries to get the name first from the "testnet" flag,
 | ||||
| /// if not present, then checks the "testnet-dir" flag and returns a custom name
 | ||||
| /// If neither flags are present, returns the default hardcoded network name.
 | ||||
| pub fn get_testnet_name(matches: &ArgMatches) -> String { | ||||
|     if let Some(testnet_name) = matches.value_of("testnet") { | ||||
|         testnet_name.to_string() | ||||
|     } else if matches.value_of("testnet-dir").is_some() { | ||||
|         CUSTOM_TESTNET_DIR.to_string() | ||||
|     } else { | ||||
|         eth2_testnet_config::DEFAULT_HARDCODED_TESTNET.to_string() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Checks if a directory exists in the given path and creates a directory if it does not exist.
 | ||||
| pub fn ensure_dir_exists<P: AsRef<Path>>(path: P) -> Result<(), String> { | ||||
|     let path = path.as_ref(); | ||||
| 
 | ||||
|     if !path.exists() { | ||||
|         create_dir_all(path).map_err(|e| format!("Unable to create {:?}: {:?}", path, e))?; | ||||
|     } | ||||
| 
 | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| /// If `arg` is in `matches`, parses the value as a path.
 | ||||
| ///
 | ||||
| /// Otherwise, attempts to find the default directory for the `testnet` from the `matches`
 | ||||
| /// and appends `flag` to it.
 | ||||
| pub fn parse_path_or_default_with_flag( | ||||
|     matches: &ArgMatches, | ||||
|     arg: &'static str, | ||||
|     flag: &str, | ||||
| ) -> Result<PathBuf, String> { | ||||
|     clap_utils::parse_path_with_default_in_home_dir( | ||||
|         matches, | ||||
|         arg, | ||||
|         PathBuf::new() | ||||
|             .join(DEFAULT_ROOT_DIR) | ||||
|             .join(get_testnet_name(matches)) | ||||
|             .join(flag), | ||||
|     ) | ||||
| } | ||||
| @ -12,7 +12,6 @@ harness = false | ||||
| bls = { path = "../../crypto/bls" } | ||||
| compare_fields = { path = "../../common/compare_fields" } | ||||
| compare_fields_derive = { path = "../../common/compare_fields_derive" } | ||||
| dirs = "2.0.2" | ||||
| eth2_interop_keypairs = { path = "../../common/eth2_interop_keypairs" } | ||||
| ethereum-types = "0.9.1" | ||||
| eth2_hashing = "0.1.0" | ||||
|  | ||||
| @ -4,21 +4,9 @@ use crate::*; | ||||
| use bls::get_withdrawal_credentials; | ||||
| use log::debug; | ||||
| use rayon::prelude::*; | ||||
| use std::path::PathBuf; | ||||
| 
 | ||||
| pub const KEYPAIRS_FILE: &str = "keypairs.raw_keypairs"; | ||||
| 
 | ||||
| /// Returns the directory where the generated keypairs should be stored.
 | ||||
| ///
 | ||||
| /// It is either `$HOME/.lighthouse/keypairs.raw_keypairs` or, if `$HOME` is not available,
 | ||||
| /// `./keypairs.raw_keypairs`.
 | ||||
| pub fn keypairs_path() -> PathBuf { | ||||
|     let dir = dirs::home_dir() | ||||
|         .map(|home| (home.join(".lighthouse"))) | ||||
|         .unwrap_or_else(|| PathBuf::from("")); | ||||
|     dir.join(KEYPAIRS_FILE) | ||||
| } | ||||
| 
 | ||||
| /// Builds a beacon state to be used for testing purposes.
 | ||||
| ///
 | ||||
| /// This struct should **never be used for production purposes.**
 | ||||
|  | ||||
| @ -35,3 +35,4 @@ validator_dir = { path = "../common/validator_dir", features = ["insecure_keys"] | ||||
| rand = "0.7.2" | ||||
| eth2_keystore = { path = "../crypto/eth2_keystore" } | ||||
| lighthouse_version = { path = "../common/lighthouse_version" } | ||||
| directory = { path = "../common/directory" } | ||||
|  | ||||
| @ -20,7 +20,7 @@ pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches<'_>) -> Res | ||||
|         .and_then(|dir| dir.parse::<PathBuf>().map_err(|_| ())) | ||||
|         .unwrap_or_else(|_| { | ||||
|             dirs::home_dir() | ||||
|                 .map(|home| home.join(".lighthouse").join("testnet")) | ||||
|                 .map(|home| home.join(directory::DEFAULT_ROOT_DIR).join("testnet")) | ||||
|                 .expect("should locate home directory") | ||||
|         }); | ||||
| 
 | ||||
|  | ||||
| @ -31,7 +31,7 @@ pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches) -> Result< | ||||
|         .and_then(|dir| dir.parse::<PathBuf>().map_err(|_| ())) | ||||
|         .unwrap_or_else(|_| { | ||||
|             dirs::home_dir() | ||||
|                 .map(|home| home.join(".lighthouse").join("testnet")) | ||||
|                 .map(|home| home.join(directory::DEFAULT_ROOT_DIR).join("testnet")) | ||||
|                 .expect("should locate home directory") | ||||
|         }); | ||||
| 
 | ||||
|  | ||||
| @ -10,7 +10,7 @@ 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(".lighthouse/testnet"), | ||||
|         PathBuf::from(directory::DEFAULT_ROOT_DIR).join("testnet"), | ||||
|     )?; | ||||
|     let deposit_contract_address: Address = parse_required(matches, "deposit-contract-address")?; | ||||
|     let deposit_contract_deploy_block = parse_required(matches, "deposit-contract-deploy-block")?; | ||||
|  | ||||
| @ -31,9 +31,10 @@ validator_client = { "path" = "../validator_client" } | ||||
| account_manager = { "path" = "../account_manager" } | ||||
| clap_utils = { path = "../common/clap_utils" } | ||||
| eth2_testnet_config = { path = "../common/eth2_testnet_config" } | ||||
| directory = { path = "../common/directory" } | ||||
| lighthouse_version = { path = "../common/lighthouse_version" } | ||||
| account_utils = { path = "../common/account_utils" } | ||||
| 
 | ||||
| [dev-dependencies] | ||||
| tempfile = "3.1.0" | ||||
| validator_dir = { path = "../common/validator_dir" } | ||||
| account_utils = { path = "../common/account_utils" } | ||||
|  | ||||
| @ -10,7 +10,6 @@ use std::process::exit; | ||||
| use types::EthSpec; | ||||
| use validator_client::ProductionValidatorClient; | ||||
| 
 | ||||
| pub const DEFAULT_DATA_DIR: &str = ".lighthouse"; | ||||
| pub const ETH2_CONFIG_FILENAME: &str = "eth2-spec.toml"; | ||||
| 
 | ||||
| fn bls_library_name() -> &'static str { | ||||
| @ -91,7 +90,10 @@ fn main() { | ||||
|                 .short("d") | ||||
|                 .value_name("DIR") | ||||
|                 .global(true) | ||||
|                 .help("Data directory for lighthouse keys and databases.") | ||||
|                 .help( | ||||
|                     "Root data directory for lighthouse keys and databases. \ | ||||
|                     Defaults to $HOME/.lighthouse/{default-testnet}, \ | ||||
|                     currently, $HOME/.lighthouse/medalla")
 | ||||
|                 .takes_value(true), | ||||
|         ) | ||||
|         .arg( | ||||
|  | ||||
| @ -11,7 +11,7 @@ use account_manager::{ | ||||
|         list::CMD as LIST_CMD, | ||||
|         CMD as WALLET_CMD, | ||||
|     }, | ||||
|     BASE_DIR_FLAG, CMD as ACCOUNT_CMD, *, | ||||
|     CMD as ACCOUNT_CMD, WALLETS_DIR_FLAG, *, | ||||
| }; | ||||
| use account_utils::{ | ||||
|     eth2_keystore::KeystoreBuilder, | ||||
| @ -73,7 +73,7 @@ fn dir_child_count<P: AsRef<Path>>(dir: P) -> usize { | ||||
| fn list_wallets<P: AsRef<Path>>(base_dir: P) -> Vec<String> { | ||||
|     let output = output_result( | ||||
|         wallet_cmd() | ||||
|             .arg(format!("--{}", BASE_DIR_FLAG)) | ||||
|             .arg(format!("--{}", WALLETS_DIR_FLAG)) | ||||
|             .arg(base_dir.as_ref().as_os_str()) | ||||
|             .arg(LIST_CMD), | ||||
|     ) | ||||
| @ -97,7 +97,7 @@ fn create_wallet<P: AsRef<Path>>( | ||||
| ) -> Result<Output, String> { | ||||
|     output_result( | ||||
|         wallet_cmd() | ||||
|             .arg(format!("--{}", BASE_DIR_FLAG)) | ||||
|             .arg(format!("--{}", WALLETS_DIR_FLAG)) | ||||
|             .arg(base_dir.as_ref().as_os_str()) | ||||
|             .arg(CREATE_CMD) | ||||
|             .arg(format!("--{}", NAME_FLAG)) | ||||
| @ -233,15 +233,15 @@ impl TestValidator { | ||||
|         store_withdrawal_key: bool, | ||||
|     ) -> Result<Vec<String>, String> { | ||||
|         let mut cmd = validator_cmd(); | ||||
|         cmd.arg(format!("--{}", BASE_DIR_FLAG)) | ||||
|             .arg(self.wallet.base_dir().into_os_string()) | ||||
|         cmd.arg(format!("--{}", VALIDATOR_DIR_FLAG)) | ||||
|             .arg(self.validator_dir.clone().into_os_string()) | ||||
|             .arg(CREATE_CMD) | ||||
|             .arg(format!("--{}", WALLETS_DIR_FLAG)) | ||||
|             .arg(self.wallet.base_dir().into_os_string()) | ||||
|             .arg(format!("--{}", WALLET_NAME_FLAG)) | ||||
|             .arg(&self.wallet.name) | ||||
|             .arg(format!("--{}", WALLET_PASSWORD_FLAG)) | ||||
|             .arg(self.wallet.password_path().into_os_string()) | ||||
|             .arg(format!("--{}", VALIDATOR_DIR_FLAG)) | ||||
|             .arg(self.validator_dir.clone().into_os_string()) | ||||
|             .arg(format!("--{}", SECRETS_DIR_FLAG)) | ||||
|             .arg(self.secrets_dir.clone().into_os_string()) | ||||
|             .arg(format!("--{}", DEPOSIT_GWEI_FLAG)) | ||||
| @ -375,13 +375,6 @@ fn validator_create() { | ||||
|     assert_eq!(dir_child_count(validator_dir.path()), 6); | ||||
| } | ||||
| 
 | ||||
| /// Returns the `lighthouse account validator import` command.
 | ||||
| fn validator_import_cmd() -> Command { | ||||
|     let mut cmd = validator_cmd(); | ||||
|     cmd.arg(IMPORT_CMD); | ||||
|     cmd | ||||
| } | ||||
| 
 | ||||
| #[test] | ||||
| fn validator_import_launchpad() { | ||||
|     const PASSWORD: &str = "cats"; | ||||
| @ -407,12 +400,13 @@ fn validator_import_launchpad() { | ||||
|     // Create a not-keystore file in the src dir.
 | ||||
|     File::create(src_dir.path().join(NOT_KEYSTORE_NAME)).unwrap(); | ||||
| 
 | ||||
|     let mut child = validator_import_cmd() | ||||
|     let mut child = validator_cmd() | ||||
|         .arg(format!("--{}", VALIDATOR_DIR_FLAG)) | ||||
|         .arg(dst_dir.path().as_os_str()) | ||||
|         .arg(IMPORT_CMD) | ||||
|         .arg(format!("--{}", STDIN_INPUTS_FLAG)) // Using tty does not work well with tests.
 | ||||
|         .arg(format!("--{}", import::DIR_FLAG)) | ||||
|         .arg(src_dir.path().as_os_str()) | ||||
|         .arg(format!("--{}", VALIDATOR_DIR_FLAG)) | ||||
|         .arg(dst_dir.path().as_os_str()) | ||||
|         .stderr(Stdio::piped()) | ||||
|         .stdin(Stdio::piped()) | ||||
|         .spawn() | ||||
|  | ||||
| @ -96,7 +96,7 @@ pub fn testing_client_config() -> ClientConfig { | ||||
| /// This struct is separate to `LocalValidatorClient` to allow for pre-computation of validator
 | ||||
| /// keypairs since the task is quite resource intensive.
 | ||||
| pub struct ValidatorFiles { | ||||
|     pub datadir: TempDir, | ||||
|     pub validator_dir: TempDir, | ||||
|     pub secrets_dir: TempDir, | ||||
| } | ||||
| 
 | ||||
| @ -110,7 +110,7 @@ impl ValidatorFiles { | ||||
|             .map_err(|e| format!("Unable to create VC secrets dir: {:?}", e))?; | ||||
| 
 | ||||
|         Ok(Self { | ||||
|             datadir, | ||||
|             validator_dir: datadir, | ||||
|             secrets_dir, | ||||
|         }) | ||||
|     } | ||||
| @ -120,7 +120,7 @@ impl ValidatorFiles { | ||||
|         let this = Self::new()?; | ||||
| 
 | ||||
|         build_deterministic_validator_dirs( | ||||
|             this.datadir.path().into(), | ||||
|             this.validator_dir.path().into(), | ||||
|             this.secrets_dir.path().into(), | ||||
|             keypair_indices, | ||||
|         ) | ||||
| @ -170,7 +170,7 @@ impl<E: EthSpec> LocalValidatorClient<E> { | ||||
|         mut config: ValidatorConfig, | ||||
|         files: ValidatorFiles, | ||||
|     ) -> Result<Self, String> { | ||||
|         config.data_dir = files.datadir.path().into(); | ||||
|         config.validator_dir = files.validator_dir.path().into(); | ||||
|         config.secrets_dir = files.secrets_dir.path().into(); | ||||
| 
 | ||||
|         ProductionValidatorClient::new(context, config) | ||||
|  | ||||
| @ -31,6 +31,7 @@ slog-term = "2.5.0" | ||||
| tokio = { version = "0.2.21", features = ["time"] } | ||||
| futures = { version = "0.3.5", features = ["compat"] } | ||||
| dirs = "2.0.2" | ||||
| directory = {path = "../common/directory"} | ||||
| logging = { path = "../common/logging" } | ||||
| environment = { path = "../lighthouse/environment" } | ||||
| parking_lot = "0.11.0" | ||||
|  | ||||
| @ -16,6 +16,19 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|                 .default_value(&DEFAULT_HTTP_SERVER) | ||||
|                 .takes_value(true), | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name("validators-dir") | ||||
|                 .long("validators-dir") | ||||
|                 .value_name("VALIDATORS_DIR") | ||||
|                 .help( | ||||
|                     "The directory which contains the validator keystores, deposit data for \ | ||||
|                     each validator along with the common slashing protection database \ | ||||
|                     and the validator_definitions.yml" | ||||
|                 ) | ||||
|                 .takes_value(true) | ||||
|                 .conflicts_with("datadir") | ||||
|                 .requires("secrets-dir") | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name("secrets-dir") | ||||
|                 .long("secrets-dir") | ||||
| @ -24,9 +37,11 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|                     "The directory which contains the password to unlock the validator \ | ||||
|                     voting keypairs. Each password should be contained in a file where the \ | ||||
|                     name is the 0x-prefixed hex representation of the validators voting public \ | ||||
|                     key. Defaults to ~/.lighthouse/secrets.",
 | ||||
|                     key. Defaults to ~/.lighthouse/{testnet}/secrets.",
 | ||||
|                 ) | ||||
|                 .takes_value(true), | ||||
|                 .takes_value(true) | ||||
|                 .conflicts_with("datadir") | ||||
|                 .requires("validators-dir"), | ||||
|         ) | ||||
|         .arg(Arg::with_name("auto-register").long("auto-register").help( | ||||
|             "If present, the validator client will register any new signing keys with \ | ||||
| @ -48,6 +63,16 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { | ||||
|                 that might also be using the same keystores." | ||||
|             ) | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name("strict-slashing-protection") | ||||
|             .long("strict-slashing-protection") | ||||
|             .help( | ||||
|                 "If present, do not create a new slashing database. This is to ensure that users \ | ||||
|                 do not accidentally get slashed in case their slashing protection db ends up in the \ | ||||
|                 wrong directory during directory restructure and vc creates a new empty db and \ | ||||
|                 re-registers all validators." | ||||
|             ) | ||||
|         ) | ||||
|         .arg( | ||||
|             Arg::with_name("disable-auto-discover") | ||||
|             .long("disable-auto-discover") | ||||
|  | ||||
| @ -1,12 +1,14 @@ | ||||
| use clap::ArgMatches; | ||||
| use clap_utils::{parse_optional, parse_path_with_default_in_home_dir}; | ||||
| use clap_utils::{parse_optional, parse_required}; | ||||
| use directory::{ | ||||
|     get_testnet_name, DEFAULT_HARDCODED_TESTNET, DEFAULT_ROOT_DIR, DEFAULT_SECRET_DIR, | ||||
|     DEFAULT_VALIDATOR_DIR, | ||||
| }; | ||||
| use serde_derive::{Deserialize, Serialize}; | ||||
| use std::path::PathBuf; | ||||
| use types::{Graffiti, GRAFFITI_BYTES_LEN}; | ||||
| 
 | ||||
| pub const DEFAULT_HTTP_SERVER: &str = "http://localhost:5052/"; | ||||
| pub const DEFAULT_DATA_DIR: &str = ".lighthouse/validators"; | ||||
| pub const DEFAULT_SECRETS_DIR: &str = ".lighthouse/secrets"; | ||||
| /// Path to the slashing protection database within the datadir.
 | ||||
| pub const SLASHING_PROTECTION_FILENAME: &str = "slashing_protection.sqlite"; | ||||
| 
 | ||||
| @ -14,7 +16,7 @@ pub const SLASHING_PROTECTION_FILENAME: &str = "slashing_protection.sqlite"; | ||||
| #[derive(Clone, Serialize, Deserialize)] | ||||
| pub struct Config { | ||||
|     /// The data directory, which stores all validator databases
 | ||||
|     pub data_dir: PathBuf, | ||||
|     pub validator_dir: PathBuf, | ||||
|     /// The directory containing the passwords to unlock validator keystores.
 | ||||
|     pub secrets_dir: PathBuf, | ||||
|     /// The http endpoint of the beacon node API.
 | ||||
| @ -28,6 +30,8 @@ pub struct Config { | ||||
|     pub delete_lockfiles: bool, | ||||
|     /// If true, don't scan the validators dir for new keystores.
 | ||||
|     pub disable_auto_discover: bool, | ||||
|     /// If true, don't re-register existing validators in definitions.yml for slashing protection.
 | ||||
|     pub strict_slashing_protection: bool, | ||||
|     /// Graffiti to be inserted everytime we create a block.
 | ||||
|     pub graffiti: Option<Graffiti>, | ||||
| } | ||||
| @ -35,19 +39,22 @@ pub struct Config { | ||||
| impl Default for Config { | ||||
|     /// Build a new configuration from defaults.
 | ||||
|     fn default() -> Self { | ||||
|         let data_dir = dirs::home_dir() | ||||
|             .map(|home| home.join(DEFAULT_DATA_DIR)) | ||||
|             .unwrap_or_else(|| PathBuf::from(".")); | ||||
|         let secrets_dir = dirs::home_dir() | ||||
|             .map(|home| home.join(DEFAULT_SECRETS_DIR)) | ||||
|             .unwrap_or_else(|| PathBuf::from(".")); | ||||
|         // WARNING: these directory defaults should be always overrided with parameters
 | ||||
|         // from cli for specific networks.
 | ||||
|         let base_dir = dirs::home_dir() | ||||
|             .unwrap_or_else(|| PathBuf::from(".")) | ||||
|             .join(DEFAULT_ROOT_DIR) | ||||
|             .join(DEFAULT_HARDCODED_TESTNET); | ||||
|         let validator_dir = base_dir.join(DEFAULT_VALIDATOR_DIR); | ||||
|         let secrets_dir = base_dir.join(DEFAULT_SECRET_DIR); | ||||
|         Self { | ||||
|             data_dir, | ||||
|             validator_dir, | ||||
|             secrets_dir, | ||||
|             http_server: DEFAULT_HTTP_SERVER.to_string(), | ||||
|             allow_unsynced_beacon_node: false, | ||||
|             delete_lockfiles: false, | ||||
|             disable_auto_discover: false, | ||||
|             strict_slashing_protection: false, | ||||
|             graffiti: None, | ||||
|         } | ||||
|     } | ||||
| @ -59,16 +66,39 @@ impl Config { | ||||
|     pub fn from_cli(cli_args: &ArgMatches) -> Result<Config, String> { | ||||
|         let mut config = Config::default(); | ||||
| 
 | ||||
|         config.data_dir = parse_path_with_default_in_home_dir( | ||||
|             cli_args, | ||||
|             "datadir", | ||||
|             PathBuf::from(".lighthouse").join("validators"), | ||||
|         )?; | ||||
|         let default_root_dir = dirs::home_dir() | ||||
|             .map(|home| home.join(DEFAULT_ROOT_DIR)) | ||||
|             .unwrap_or_else(|| PathBuf::from(".")); | ||||
| 
 | ||||
|         if !config.data_dir.exists() { | ||||
|         let (mut validator_dir, mut secrets_dir) = (None, None); | ||||
|         if cli_args.value_of("datadir").is_some() { | ||||
|             let base_dir: PathBuf = parse_required(cli_args, "datadir")?; | ||||
|             validator_dir = Some(base_dir.join(DEFAULT_VALIDATOR_DIR)); | ||||
|             secrets_dir = Some(base_dir.join(DEFAULT_SECRET_DIR)); | ||||
|         } | ||||
|         if cli_args.value_of("validators-dir").is_some() | ||||
|             && cli_args.value_of("secrets-dir").is_some() | ||||
|         { | ||||
|             validator_dir = Some(parse_required(cli_args, "validators-dir")?); | ||||
|             secrets_dir = Some(parse_required(cli_args, "secrets-dir")?); | ||||
|         } | ||||
| 
 | ||||
|         config.validator_dir = validator_dir.unwrap_or_else(|| { | ||||
|             default_root_dir | ||||
|                 .join(get_testnet_name(cli_args)) | ||||
|                 .join(DEFAULT_VALIDATOR_DIR) | ||||
|         }); | ||||
| 
 | ||||
|         config.secrets_dir = secrets_dir.unwrap_or_else(|| { | ||||
|             default_root_dir | ||||
|                 .join(get_testnet_name(cli_args)) | ||||
|                 .join(DEFAULT_SECRET_DIR) | ||||
|         }); | ||||
| 
 | ||||
|         if !config.validator_dir.exists() { | ||||
|             return Err(format!( | ||||
|                 "The directory for validator data  (--datadir) does not exist: {:?}", | ||||
|                 config.data_dir | ||||
|                 "The directory for validator data does not exist: {:?}", | ||||
|                 config.validator_dir | ||||
|             )); | ||||
|         } | ||||
| 
 | ||||
| @ -79,10 +109,7 @@ impl Config { | ||||
|         config.allow_unsynced_beacon_node = cli_args.is_present("allow-unsynced"); | ||||
|         config.delete_lockfiles = cli_args.is_present("delete-lockfiles"); | ||||
|         config.disable_auto_discover = cli_args.is_present("disable-auto-discover"); | ||||
| 
 | ||||
|         if let Some(secrets_dir) = parse_optional(cli_args, "secrets-dir")? { | ||||
|             config.secrets_dir = secrets_dir; | ||||
|         } | ||||
|         config.strict_slashing_protection = cli_args.is_present("strict-slashing-protection"); | ||||
| 
 | ||||
|         if let Some(input_graffiti) = cli_args.value_of("graffiti") { | ||||
|             let graffiti_bytes = input_graffiti.as_bytes(); | ||||
|  | ||||
| @ -68,18 +68,18 @@ impl<T: EthSpec> ProductionValidatorClient<T> { | ||||
|             log, | ||||
|             "Starting validator client"; | ||||
|             "beacon_node" => &config.http_server, | ||||
|             "datadir" => format!("{:?}", config.data_dir), | ||||
|             "validator_dir" => format!("{:?}", config.validator_dir), | ||||
|         ); | ||||
| 
 | ||||
|         let mut validator_defs = ValidatorDefinitions::open_or_create(&config.data_dir) | ||||
|         let mut validator_defs = ValidatorDefinitions::open_or_create(&config.validator_dir) | ||||
|             .map_err(|e| format!("Unable to open or create validator definitions: {:?}", e))?; | ||||
| 
 | ||||
|         if !config.disable_auto_discover { | ||||
|             let new_validators = validator_defs | ||||
|                 .discover_local_keystores(&config.data_dir, &config.secrets_dir, &log) | ||||
|                 .discover_local_keystores(&config.validator_dir, &config.secrets_dir, &log) | ||||
|                 .map_err(|e| format!("Unable to discover local validator keystores: {:?}", e))?; | ||||
|             validator_defs | ||||
|                 .save(&config.data_dir) | ||||
|                 .save(&config.validator_dir) | ||||
|                 .map_err(|e| format!("Unable to update validator definitions: {:?}", e))?; | ||||
|             info!( | ||||
|                 log, | ||||
| @ -90,7 +90,7 @@ impl<T: EthSpec> ProductionValidatorClient<T> { | ||||
| 
 | ||||
|         let validators = InitializedValidators::from_definitions( | ||||
|             validator_defs, | ||||
|             config.data_dir.clone(), | ||||
|             config.validator_dir.clone(), | ||||
|             config.delete_lockfiles, | ||||
|             log.clone(), | ||||
|         ) | ||||
|  | ||||
| @ -62,14 +62,24 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore<T, E> { | ||||
|         fork_service: ForkService<T, E>, | ||||
|         log: Logger, | ||||
|     ) -> Result<Self, String> { | ||||
|         let slashing_db_path = config.data_dir.join(SLASHING_PROTECTION_FILENAME); | ||||
|         let slashing_protection = | ||||
|         let slashing_db_path = config.validator_dir.join(SLASHING_PROTECTION_FILENAME); | ||||
|         let slashing_protection = if config.strict_slashing_protection { | ||||
|             // Don't create a new slashing database if `strict_slashing_protection` is turned on.
 | ||||
|             SlashingDatabase::open(&slashing_db_path).map_err(|e| { | ||||
|                 format!( | ||||
|                     "Failed to open slashing protection database: {:?}.
 | ||||
|                     Ensure that `slashing_protection.sqlite` is in {:?} folder",
 | ||||
|                     e, config.validator_dir | ||||
|                 ) | ||||
|             })? | ||||
|         } else { | ||||
|             SlashingDatabase::open_or_create(&slashing_db_path).map_err(|e| { | ||||
|                 format!( | ||||
|                     "Failed to open or create slashing protection database: {:?}", | ||||
|                     e | ||||
|                 ) | ||||
|             })?; | ||||
|             })? | ||||
|         }; | ||||
| 
 | ||||
|         Ok(Self { | ||||
|             validators: Arc::new(RwLock::new(validators)), | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user