diff --git a/validator_manager/src/validators/common.rs b/validator_manager/src/validators/common.rs index d433ec8089..d3f3d3f231 100644 --- a/validator_manager/src/validators/common.rs +++ b/validator_manager/src/validators/common.rs @@ -3,7 +3,7 @@ use eth2::lighthouse_vc::std_types::{InterchangeJsonStr, KeystoreJsonStr}; use eth2::{ lighthouse_vc::{ http_client::ValidatorClientHttpClient, - std_types::{ImportKeystoresRequest, SingleKeystoreResponse}, + std_types::{ImportKeystoreStatus, ImportKeystoresRequest, SingleKeystoreResponse, Status}, types::UpdateFeeRecipientRequest, }, SensitiveUrl, @@ -31,6 +31,7 @@ pub enum UploadError { DuplicateValidator(PublicKeyBytes), FailedToListKeys(eth2::Error), KeyUploadFailed(eth2::Error), + IncorrectStatusCount(usize), FeeRecipientUpdateFailed(eth2::Error), PatchValidatorFailed(eth2::Error), } @@ -52,7 +53,7 @@ impl ValidatorSpecification { self, http_client: &ValidatorClientHttpClient, ignore_duplicates: bool, - ) -> Result<(), UploadError> { + ) -> Result, UploadError> { let ValidatorSpecification { voting_keystore, voting_keystore_password, @@ -98,14 +99,15 @@ impl ValidatorSpecification { } }; - if let Err(e) = http_client.post_keystores(&request).await { - // Return here *without* writing the deposit JSON file. This might help prevent - // users from submitting duplicate deposits or deposits for validators that weren't - // initialized on a VC. - // - // Next the the user runs with the --ignore-duplicates flag there should be a new, - // complete deposit JSON file created. - return Err(UploadError::KeyUploadFailed(e)); + let mut statuses = http_client + .post_keystores(&request) + .await + .map_err(UploadError::KeyUploadFailed)? + .data; + + let status = statuses.pop().ok_or(UploadError::IncorrectStatusCount(0))?; + if !statuses.is_empty() { + return Err(UploadError::IncorrectStatusCount(statuses.len() + 1)); } if let Some(fee_recipient) = fee_recipient { @@ -132,7 +134,7 @@ impl ValidatorSpecification { .map_err(UploadError::PatchValidatorFailed)?; } - Ok(()) + Ok(status) } } diff --git a/validator_manager/src/validators/import_validators.rs b/validator_manager/src/validators/import_validators.rs index f1ad622502..74228b1e1e 100644 --- a/validator_manager/src/validators/import_validators.rs +++ b/validator_manager/src/validators/import_validators.rs @@ -1,7 +1,7 @@ use super::common::*; use crate::DumpConfig; use clap::{App, Arg, ArgMatches}; -use eth2::SensitiveUrl; +use eth2::{lighthouse_vc::std_types::ImportKeystoreStatus, SensitiveUrl}; use serde::{Deserialize, Serialize}; use std::fs; use std::path::PathBuf; @@ -134,7 +134,38 @@ async fn run<'a>(config: ImportConfig) -> Result<(), String> { for (i, validator) in validators.into_iter().enumerate() { match validator.upload(&http_client, ignore_duplicates).await { - Ok(()) => eprintln!("Uploaded keystore {} of {} to the VC", i + 1, count), + Ok(status) => { + match status.status { + ImportKeystoreStatus::Imported => { + eprintln!("Uploaded keystore {} of {} to the VC", i + 1, count) + } + ImportKeystoreStatus::Duplicate => { + if ignore_duplicates { + eprintln!("Re-uploaded keystore {} of {} to the VC", i + 1, count) + } else { + eprintln!( + "Keystore {} of {} was uploaded to the VC, but it was a duplicate. \ + Exiting now, use --{} to allow duplicates.", + i + 1, count, IGNORE_DUPLICATES_FLAG + ); + return Err(DETECTED_DUPLICATE_MESSAGE.to_string()); + } + } + ImportKeystoreStatus::Error => { + eprintln!( + "Upload of keystore {} of {} failed with message: {:?}. \ + A potential solution is run this command again \ + using the --{} flag, however care should be taken to ensure \ + that there are no duplicate deposits submitted.", + i + 1, + count, + status.message, + IGNORE_DUPLICATES_FLAG + ); + return Err(format!("Upload failed with {:?}", status.message)); + } + } + } e @ Err(UploadError::InvalidPublicKey) => { eprintln!("Validator {} has an invalid public key", i); return Err(format!("{:?}", e)); @@ -168,6 +199,18 @@ async fn run<'a>(config: ImportConfig) -> Result<(), String> { ); return Err(format!("{:?}", e)); } + Err(UploadError::IncorrectStatusCount(count)) => { + eprintln!( + "Keystore was uploaded, however the validator client returned an invalid response. \ + A potential solution is run this command again using the --{} flag, however care \ + should be taken to ensure that there are no duplicate deposits submitted.", + IGNORE_DUPLICATES_FLAG + ); + return Err(format!( + "Invalid status count in import response: {}", + count + )); + } Err(UploadError::FeeRecipientUpdateFailed(e)) => { eprintln!( "Failed to set fee recipient for validator {}. This value may need \ diff --git a/validator_manager/src/validators/move_validators.rs b/validator_manager/src/validators/move_validators.rs index 64225db6e4..f9576260dd 100644 --- a/validator_manager/src/validators/move_validators.rs +++ b/validator_manager/src/validators/move_validators.rs @@ -3,7 +3,10 @@ use crate::DumpConfig; use clap::{App, Arg, ArgMatches}; use eth2::{ lighthouse_vc::{ - std_types::{DeleteKeystoreStatus, DeleteKeystoresRequest, InterchangeJsonStr, Status}, + std_types::{ + DeleteKeystoreStatus, DeleteKeystoresRequest, ImportKeystoreStatus, InterchangeJsonStr, + Status, + }, types::{ExportKeystoresResponse, SingleExportKeystoresResponse}, }, SensitiveUrl, @@ -399,7 +402,37 @@ async fn run<'a>(config: MoveConfig) -> Result<(), String> { .upload(&dest_http_client, ignore_duplicates) .await { - Ok(()) => break, + Ok(status) => { + match status.status { + ImportKeystoreStatus::Imported => { + eprintln!("Moved keystore {} of {}", i + 1, count); + break; + } + ImportKeystoreStatus::Duplicate => { + eprintln!("Moved duplicate keystore {} of {} to the VC", i + 1, count); + break; + } + ImportKeystoreStatus::Error => { + eprintln!( + "Upload of keystore {} of {} failed with message: {:?}. \ + A potential solution is run this command again \ + using the --{} flag, however care should be taken to ensure \ + that there are no duplicate deposits submitted.", + i + 1, + count, + status.message, + IGNORE_DUPLICATES_FLAG + ); + // Retry uploading this validator. + sleep_with_retry_message( + &pubkey_to_move, + keystore_derivation_path.as_deref(), + ) + .await; + return Err(format!("Upload failed with {:?}", status.message)); + } + } + } e @ Err(UploadError::InvalidPublicKey) => { eprintln!("Validator {} has an invalid public key", i); return Err(format!("{:?}", e)); @@ -429,6 +462,18 @@ async fn run<'a>(config: MoveConfig) -> Result<(), String> { sleep_with_retry_message(&pubkey_to_move, keystore_derivation_path.as_deref()) .await; } + Err(UploadError::IncorrectStatusCount(count)) => { + eprintln!( + "Keystore was uploaded, however the validator client returned an invalid response. \ + A potential solution is run this command again using the --{} flag, however care \ + should be taken to ensure that there are no duplicate deposits submitted.", + IGNORE_DUPLICATES_FLAG + ); + return Err(format!( + "Invalid status count in import response: {}", + count + )); + } Err(UploadError::FeeRecipientUpdateFailed(e)) => { eprintln!( "Failed to set fee recipient for validator {}. This value may need \