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