Add an account command to enable/disable validators (#2386)
## Issue Addressed Resolves #2322 ## Proposed Changes Adds a `modify` command to `lighthouse account validator` with subcommands to enable and disable specific or all pubkeys.
This commit is contained in:
parent
3b600acdc5
commit
dffe31c312
@ -2,6 +2,7 @@ pub mod create;
|
|||||||
pub mod exit;
|
pub mod exit;
|
||||||
pub mod import;
|
pub mod import;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
|
pub mod modify;
|
||||||
pub mod recover;
|
pub mod recover;
|
||||||
pub mod slashing_protection;
|
pub mod slashing_protection;
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
|||||||
.conflicts_with("datadir"),
|
.conflicts_with("datadir"),
|
||||||
)
|
)
|
||||||
.subcommand(create::cli_app())
|
.subcommand(create::cli_app())
|
||||||
|
.subcommand(modify::cli_app())
|
||||||
.subcommand(import::cli_app())
|
.subcommand(import::cli_app())
|
||||||
.subcommand(list::cli_app())
|
.subcommand(list::cli_app())
|
||||||
.subcommand(recover::cli_app())
|
.subcommand(recover::cli_app())
|
||||||
@ -47,6 +49,7 @@ pub fn cli_run<T: EthSpec>(matches: &ArgMatches, env: Environment<T>) -> Result<
|
|||||||
|
|
||||||
match matches.subcommand() {
|
match matches.subcommand() {
|
||||||
(create::CMD, Some(matches)) => create::cli_run::<T>(matches, env, validator_base_dir),
|
(create::CMD, Some(matches)) => create::cli_run::<T>(matches, env, validator_base_dir),
|
||||||
|
(modify::CMD, Some(matches)) => modify::cli_run(matches, validator_base_dir),
|
||||||
(import::CMD, Some(matches)) => import::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),
|
(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, validator_base_dir),
|
||||||
|
100
account_manager/src/validator/modify.rs
Normal file
100
account_manager/src/validator/modify.rs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
use account_utils::validator_definitions::ValidatorDefinitions;
|
||||||
|
use bls::PublicKey;
|
||||||
|
use clap::{App, Arg, ArgMatches};
|
||||||
|
use std::{collections::HashSet, path::PathBuf};
|
||||||
|
|
||||||
|
pub const CMD: &str = "modify";
|
||||||
|
pub const ENABLE: &str = "enable";
|
||||||
|
pub const DISABLE: &str = "disable";
|
||||||
|
|
||||||
|
pub const PUBKEY_FLAG: &str = "pubkey";
|
||||||
|
pub const ALL: &str = "all";
|
||||||
|
|
||||||
|
pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||||
|
App::new(CMD)
|
||||||
|
.about("Modify validator status in validator_definitions.yml.")
|
||||||
|
.subcommand(
|
||||||
|
App::new(ENABLE)
|
||||||
|
.about("Enable validator(s) in validator_definitions.yml.")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(PUBKEY_FLAG)
|
||||||
|
.long(PUBKEY_FLAG)
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.help("Validator pubkey to enable")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(ALL)
|
||||||
|
.long(ALL)
|
||||||
|
.help("Enable all validators in the validator directory")
|
||||||
|
.takes_value(false)
|
||||||
|
.conflicts_with(PUBKEY_FLAG),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.subcommand(
|
||||||
|
App::new(DISABLE)
|
||||||
|
.about("Disable validator(s) in validator_definitions.yml.")
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(PUBKEY_FLAG)
|
||||||
|
.long(PUBKEY_FLAG)
|
||||||
|
.value_name("PUBKEY")
|
||||||
|
.help("Validator pubkey to disable")
|
||||||
|
.takes_value(true),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::with_name(ALL)
|
||||||
|
.long(ALL)
|
||||||
|
.help("Disable all validators in the validator directory")
|
||||||
|
.takes_value(false)
|
||||||
|
.conflicts_with(PUBKEY_FLAG),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cli_run(matches: &ArgMatches, validator_dir: PathBuf) -> Result<(), String> {
|
||||||
|
// `true` implies we are setting `validator_definition.enabled = true` and
|
||||||
|
// vice versa.
|
||||||
|
let (enabled, sub_matches) = match matches.subcommand() {
|
||||||
|
(ENABLE, Some(sub_matches)) => (true, sub_matches),
|
||||||
|
(DISABLE, Some(sub_matches)) => (false, sub_matches),
|
||||||
|
(unknown, _) => {
|
||||||
|
return Err(format!(
|
||||||
|
"{} does not have a {} command. See --help",
|
||||||
|
CMD, unknown
|
||||||
|
))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut defs = ValidatorDefinitions::open(&validator_dir).map_err(|e| {
|
||||||
|
format!(
|
||||||
|
"No validator definitions found in {:?}: {:?}",
|
||||||
|
validator_dir, e
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let pubkeys_to_modify = if sub_matches.is_present(ALL) {
|
||||||
|
defs.as_slice()
|
||||||
|
.iter()
|
||||||
|
.map(|def| def.voting_public_key.clone())
|
||||||
|
.collect::<HashSet<_>>()
|
||||||
|
} else {
|
||||||
|
let public_key: PublicKey = clap_utils::parse_required(sub_matches, PUBKEY_FLAG)?;
|
||||||
|
std::iter::once(public_key).collect::<HashSet<PublicKey>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Modify required entries from validator_definitions.
|
||||||
|
for def in defs.as_mut_slice() {
|
||||||
|
if pubkeys_to_modify.contains(&def.voting_public_key) {
|
||||||
|
def.enabled = enabled;
|
||||||
|
eprintln!(
|
||||||
|
"Validator {} {}",
|
||||||
|
def.voting_public_key,
|
||||||
|
if enabled { "enabled" } else { "disabled" }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defs.save(&validator_dir)
|
||||||
|
.map_err(|e| format!("Unable to modify validator definitions: {:?}", e))?;
|
||||||
|
|
||||||
|
eprintln!("\nSuccessfully modified validator_definitions.yml");
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -2,6 +2,7 @@ use account_manager::{
|
|||||||
validator::{
|
validator::{
|
||||||
create::*,
|
create::*,
|
||||||
import::{self, CMD as IMPORT_CMD},
|
import::{self, CMD as IMPORT_CMD},
|
||||||
|
modify::{ALL, CMD as MODIFY_CMD, DISABLE, ENABLE, PUBKEY_FLAG},
|
||||||
CMD as VALIDATOR_CMD,
|
CMD as VALIDATOR_CMD,
|
||||||
},
|
},
|
||||||
wallet::{
|
wallet::{
|
||||||
@ -475,10 +476,21 @@ fn validator_import_launchpad() {
|
|||||||
// Validator should be registered with slashing protection.
|
// Validator should be registered with slashing protection.
|
||||||
check_slashing_protection(&dst_dir, std::iter::once(keystore.public_key().unwrap()));
|
check_slashing_protection(&dst_dir, std::iter::once(keystore.public_key().unwrap()));
|
||||||
|
|
||||||
|
// Disable all the validators in validator_definition.
|
||||||
|
output_result(
|
||||||
|
validator_cmd()
|
||||||
|
.arg(format!("--{}", VALIDATOR_DIR_FLAG))
|
||||||
|
.arg(dst_dir.path().as_os_str())
|
||||||
|
.arg(MODIFY_CMD)
|
||||||
|
.arg(DISABLE)
|
||||||
|
.arg(format!("--{}", ALL)),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let defs = ValidatorDefinitions::open(&dst_dir).unwrap();
|
let defs = ValidatorDefinitions::open(&dst_dir).unwrap();
|
||||||
|
|
||||||
let expected_def = ValidatorDefinition {
|
let mut expected_def = ValidatorDefinition {
|
||||||
enabled: true,
|
enabled: false,
|
||||||
description: "".into(),
|
description: "".into(),
|
||||||
graffiti: None,
|
graffiti: None,
|
||||||
voting_public_key: keystore.public_key().unwrap(),
|
voting_public_key: keystore.public_key().unwrap(),
|
||||||
@ -490,7 +502,28 @@ fn validator_import_launchpad() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
defs.as_slice() == &[expected_def],
|
defs.as_slice() == &[expected_def.clone()],
|
||||||
|
"validator defs file should be accurate"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Enable keystore validator again
|
||||||
|
output_result(
|
||||||
|
validator_cmd()
|
||||||
|
.arg(format!("--{}", VALIDATOR_DIR_FLAG))
|
||||||
|
.arg(dst_dir.path().as_os_str())
|
||||||
|
.arg(MODIFY_CMD)
|
||||||
|
.arg(ENABLE)
|
||||||
|
.arg(format!("--{}", PUBKEY_FLAG))
|
||||||
|
.arg(format!("{}", keystore.public_key().unwrap())),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let defs = ValidatorDefinitions::open(&dst_dir).unwrap();
|
||||||
|
|
||||||
|
expected_def.enabled = true;
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
defs.as_slice() == &[expected_def.clone()],
|
||||||
"validator defs file should be accurate"
|
"validator defs file should be accurate"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user