From 5af83be8b830805a35118c10211e19ec5aa2b60b Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 15 Aug 2022 15:11:42 +1000 Subject: [PATCH] Add deposit data to recover function --- account_manager/src/validator/mod.rs | 2 +- account_manager/src/validator/recover.rs | 53 +++++++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/account_manager/src/validator/mod.rs b/account_manager/src/validator/mod.rs index 4f1bde0795..dccddf866f 100644 --- a/account_manager/src/validator/mod.rs +++ b/account_manager/src/validator/mod.rs @@ -53,7 +53,7 @@ pub fn cli_run(matches: &ArgMatches, env: Environment) -> Result< (modify::CMD, Some(matches)) => modify::cli_run(matches, validator_base_dir), (import::CMD, Some(matches)) => import::cli_run(matches, validator_base_dir), (list::CMD, Some(_)) => list::cli_run(validator_base_dir), - (recover::CMD, Some(matches)) => recover::cli_run(matches, validator_base_dir), + (recover::CMD, Some(matches)) => recover::cli_run::(matches, env, validator_base_dir), (slashing_protection::CMD, Some(matches)) => { slashing_protection::cli_run(matches, env, validator_base_dir) } diff --git a/account_manager/src/validator/recover.rs b/account_manager/src/validator/recover.rs index d9b05e7756..881d7b7dde 100644 --- a/account_manager/src/validator/recover.rs +++ b/account_manager/src/validator/recover.rs @@ -8,13 +8,18 @@ use account_utils::random_password; use clap::{App, Arg, ArgMatches}; use directory::ensure_dir_exists; use directory::{parse_path_or_default_with_flag, DEFAULT_SECRET_DIR}; +use environment::Environment; use eth2_wallet::bip39::Seed; use eth2_wallet::{recover_validator_secret_from_mnemonic, KeyType, ValidatorKeystores}; +use std::fs; use std::path::PathBuf; +use types::*; use validator_dir::Builder as ValidatorDirBuilder; + pub const CMD: &str = "recover"; pub const FIRST_INDEX_FLAG: &str = "first-index"; pub const MNEMONIC_FLAG: &str = "mnemonic-path"; +pub const JSON_DEPOSIT_DATA_PATH: &str = "json-deposit-data-path"; pub fn cli_app<'a, 'b>() -> App<'a, 'b> { App::new(CMD) @@ -76,9 +81,26 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> { .long(STDIN_INPUTS_FLAG) .help("If present, read all user inputs from stdin instead of tty."), ) + .arg( + Arg::with_name(JSON_DEPOSIT_DATA_PATH) + .long(JSON_DEPOSIT_DATA_PATH) + .value_name("PATH") + .help( + "When provided, outputs a JSON file containing deposit data which \ + is equivalent to the 'deposit-data-*.json' file used by the \ + staking-deposit-cli tool.", + ) + .takes_value(true), + ) } -pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), String> { +pub fn cli_run( + matches: &ArgMatches, + mut env: Environment, + validator_dir: PathBuf, +) -> Result<(), String> { + let spec = env.core_context().eth2_config.spec; + let secrets_dir = if matches.value_of("datadir").is_some() { let path: PathBuf = clap_utils::parse_required(matches, "datadir")?; path.join(DEFAULT_SECRET_DIR) @@ -89,6 +111,8 @@ pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), Strin let count: u32 = clap_utils::parse_required(matches, COUNT_FLAG)?; let mnemonic_path: Option = clap_utils::parse_optional(matches, MNEMONIC_FLAG)?; let stdin_inputs = cfg!(windows) || matches.is_present(STDIN_INPUTS_FLAG); + let json_deposit_data_path: Option = + clap_utils::parse_optional(matches, JSON_DEPOSIT_DATA_PATH)?; eprintln!("secrets-dir path: {:?}", secrets_dir); @@ -103,6 +127,8 @@ pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), Strin let seed = Seed::new(&mnemonic, ""); + let mut json_deposit_data = Some(vec![]).filter(|_| json_deposit_data_path.is_some()); + for index in first_index..first_index + count { let voting_password = random_password(); let withdrawal_password = random_password(); @@ -128,7 +154,7 @@ pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), Strin let voting_pubkey = keystores.voting.pubkey().to_string(); - ValidatorDirBuilder::new(validator_dir.clone()) + let validator_dir = ValidatorDirBuilder::new(validator_dir.clone()) .password_dir(secrets_dir.clone()) .voting_keystore(keystores.voting, voting_password.as_bytes()) .withdrawal_keystore(keystores.withdrawal, withdrawal_password.as_bytes()) @@ -136,6 +162,13 @@ pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), Strin .build() .map_err(|e| format!("Unable to build validator directory: {:?}", e))?; + if let Some(json_deposit_data) = &mut json_deposit_data { + let standard_deposit_data_json = validator_dir + .standard_deposit_data_json(&spec) + .map_err(|e| format!("Unable to create standard JSON deposit data: {:?}", e))?; + json_deposit_data.push(standard_deposit_data_json); + } + println!( "{}/{}\tIndex: {}\t0x{}", index - first_index, @@ -145,5 +178,21 @@ pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), Strin ); } + // If configured, create a single JSON file which contains deposit data information for all + // validators. + if let Some(json_deposit_data_path) = json_deposit_data_path { + let json_deposit_data = + json_deposit_data.ok_or("Internal error: JSON deposit data is None")?; + + let mut file = fs::OpenOptions::new() + .write(true) + .create_new(true) + .open(&json_deposit_data_path) + .map_err(|e| format!("Unable to create {:?}: {:?}", json_deposit_data_path, e))?; + + serde_json::to_writer(&mut file, &json_deposit_data) + .map_err(|e| format!("Unable write JSON to {:?}: {:?}", json_deposit_data_path, e))?; + } + Ok(()) }