Skip to content

Commit 2407965

Browse files
committed
Move check status to list_validator
1 parent b579d40 commit 2407965

File tree

3 files changed

+144
-75
lines changed

3 files changed

+144
-75
lines changed

validator_manager/src/exit_validators.rs

Lines changed: 1 addition & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ pub const VC_TOKEN_FLAG: &str = "vc-token";
1919
pub const VALIDATOR_FLAG: &str = "validators";
2020
pub const EXIT_EPOCH_FLAG: &str = "exit-epoch";
2121
pub const PRESIGN_FLAG: &str = "presign";
22-
pub const EXIT_STATUS_FLAG: &str = "status";
2322

2423
pub fn cli_app() -> Command {
2524
Command::new(CMD)
@@ -91,15 +90,6 @@ pub fn cli_app() -> Command {
9190
.display_order(0)
9291
.conflicts_with(BEACON_URL_FLAG),
9392
)
94-
.arg(
95-
Arg::new(EXIT_STATUS_FLAG)
96-
.long(EXIT_STATUS_FLAG)
97-
.help("Display the voluntary exit status.")
98-
.help_heading(FLAG_HEADER)
99-
.action(ArgAction::SetTrue)
100-
.requires(BEACON_URL_FLAG)
101-
.display_order(0),
102-
)
10393
}
10494

10595
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
@@ -110,7 +100,6 @@ pub struct ExitConfig {
110100
pub beacon_url: Option<SensitiveUrl>,
111101
pub exit_epoch: Option<Epoch>,
112102
pub presign: bool,
113-
pub exit_status: bool,
114103
}
115104

116105
impl ExitConfig {
@@ -134,7 +123,6 @@ impl ExitConfig {
134123
beacon_url: clap_utils::parse_optional(matches, BEACON_URL_FLAG)?,
135124
exit_epoch: clap_utils::parse_optional(matches, EXIT_EPOCH_FLAG)?,
136125
presign: matches.get_flag(PRESIGN_FLAG),
137-
exit_status: matches.get_flag(EXIT_STATUS_FLAG),
138126
})
139127
}
140128
}
@@ -160,7 +148,6 @@ async fn run<E: EthSpec>(config: ExitConfig) -> Result<(), String> {
160148
beacon_url,
161149
exit_epoch,
162150
presign,
163-
exit_status,
164151
} = config;
165152

166153
let (http_client, validators) = vc_http_client(vc_url.clone(), &vc_token_path).await?;
@@ -281,67 +268,13 @@ async fn run<E: EthSpec>(config: ExitConfig) -> Result<(), String> {
281268
validator_to_exit
282269
);
283270
}
284-
285-
// Check validator status after publishing voluntary exit
286-
if exit_status {
287-
let updated_validator_data = beacon_node
288-
.get_beacon_states_validator_id(
289-
StateId::Head,
290-
&ValidatorId::PublicKey(validator_to_exit),
291-
)
292-
.await
293-
.map_err(|e| format!("Failed to get updated validator details: {:?}", e))?
294-
.ok_or_else(|| {
295-
format!(
296-
"Validator {} is not present in the beacon state",
297-
validator_to_exit
298-
)
299-
})?
300-
.data;
301-
302-
if validator_data.status == ValidatorStatus::ActiveOngoing
303-
&& updated_validator_data.status == ValidatorStatus::ActiveOngoing
304-
{
305-
eprintln!("Voluntary exit for Validator {} is waiting to be accepted into the beacon chain.", validator_to_exit);
306-
} else if updated_validator_data.status == ValidatorStatus::ActiveExiting {
307-
let exit_epoch = updated_validator_data.validator.exit_epoch;
308-
let withdrawal_epoch = updated_validator_data.validator.withdrawable_epoch;
309-
310-
eprintln!("Voluntary exit for validator {} has been accepted into the beacon chain, but not yet finalized. \
311-
Finalization may take several minutes or longer. Before finalization there is a low \
312-
probability that the exit may be reverted.", validator_to_exit);
313-
eprintln!(
314-
"Current epoch: {}, Exit epoch: {}, Withdrawable epoch: {}",
315-
current_epoch, exit_epoch, withdrawal_epoch
316-
);
317-
eprintln!("Please keep your validator running till exit epoch");
318-
eprintln!(
319-
"Exit epoch in approximately {} secs",
320-
(exit_epoch - current_epoch) * spec.seconds_per_slot * E::slots_per_epoch()
321-
);
322-
} else if updated_validator_data.status == ValidatorStatus::ExitedSlashed
323-
|| updated_validator_data.status == ValidatorStatus::ExitedUnslashed
324-
{
325-
{
326-
eprintln!(
327-
"Validator {} has exited at epoch: {}",
328-
validator_to_exit, updated_validator_data.validator.exit_epoch
329-
);
330-
}
331-
} else {
332-
eprintln!(
333-
"Validator {} has not initiated voluntary exit. Validator status is: {}",
334-
validator_to_exit, updated_validator_data.status
335-
)
336-
}
337-
}
338271
}
339272
}
340273

341274
Ok(())
342275
}
343276

344-
fn get_current_epoch<E: EthSpec>(genesis_time: u64, spec: &ChainSpec) -> Option<Epoch> {
277+
pub fn get_current_epoch<E: EthSpec>(genesis_time: u64, spec: &ChainSpec) -> Option<Epoch> {
345278
let slot_clock = SystemTimeSlotClock::new(
346279
spec.genesis_slot,
347280
Duration::from_secs(genesis_time),

validator_manager/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ pub fn run<E: EthSpec>(matches: &ArgMatches, env: Environment<E>) -> Result<(),
9191
move_validators::cli_run(matches, dump_config).await
9292
}
9393
Some((list_validators::CMD, matches)) => {
94-
list_validators::cli_run(matches, dump_config).await
94+
list_validators::cli_run::<E>(matches, dump_config).await
9595
}
9696
Some((delete_validators::CMD, matches)) => {
9797
delete_validators::cli_run(matches, dump_config).await

validator_manager/src/list_validators.rs

Lines changed: 142 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
use clap::{Arg, ArgAction, ArgMatches, Command};
22
use eth2::lighthouse_vc::types::SingleKeystoreResponse;
3-
use eth2::SensitiveUrl;
3+
use eth2::types::{ConfigAndPreset, StateId, ValidatorId, ValidatorStatus};
4+
use eth2::{BeaconNodeHttpClient, SensitiveUrl, Timeouts};
45
use serde::{Deserialize, Serialize};
56
use std::path::PathBuf;
7+
use std::time::Duration;
8+
use types::{ChainSpec, EthSpec, PublicKeyBytes};
69

10+
use crate::exit_validators::get_current_epoch;
711
use crate::{common::vc_http_client, DumpConfig};
812

913
pub const CMD: &str = "list";
1014
pub const VC_URL_FLAG: &str = "vc-url";
1115
pub const VC_TOKEN_FLAG: &str = "vc-token";
16+
pub const BEACON_URL_FLAG: &str = "beacon-node";
17+
pub const VALIDATOR_FLAG: &str = "validators";
1218

1319
pub fn cli_app() -> Command {
1420
Command::new(CMD)
@@ -31,47 +37,177 @@ pub fn cli_app() -> Command {
3137
.action(ArgAction::Set)
3238
.display_order(0),
3339
)
40+
.arg(
41+
Arg::new(BEACON_URL_FLAG)
42+
.long(BEACON_URL_FLAG)
43+
.value_name("NETWORK_ADDRESS")
44+
.help(
45+
"Address to a beacon node HTTP API. When supplied, \
46+
the status of validators (with regard to voluntary exit) \
47+
will be displayed. This flag is to be used together with \
48+
the --validators flag.",
49+
)
50+
.action(ArgAction::Set)
51+
.display_order(0)
52+
.requires(VALIDATOR_FLAG),
53+
)
54+
.arg(
55+
Arg::new(VALIDATOR_FLAG)
56+
.long(VALIDATOR_FLAG)
57+
.value_name("STRING")
58+
.help(
59+
"Comma-separated list of validators (pubkey) to display status for. \
60+
To display the status for all validators, use the keyword \"all\". \
61+
This flag is to be used together with the --beacon-node flag.",
62+
)
63+
.action(ArgAction::Set)
64+
.display_order(0)
65+
.requires(BEACON_URL_FLAG),
66+
)
3467
}
3568

3669
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
3770
pub struct ListConfig {
3871
pub vc_url: SensitiveUrl,
3972
pub vc_token_path: PathBuf,
73+
pub beacon_url: Option<SensitiveUrl>,
74+
pub validators_to_display: Vec<PublicKeyBytes>,
4075
}
4176

4277
impl ListConfig {
4378
fn from_cli(matches: &ArgMatches) -> Result<Self, String> {
79+
let validators_to_display_str =
80+
clap_utils::parse_optional::<String>(matches, VALIDATOR_FLAG)?;
81+
82+
// Keyword "all" to exit all validators, vector to be created later
83+
let validators_to_display = match validators_to_display_str {
84+
Some(str) => {
85+
if str.trim() == "all" {
86+
Vec::new()
87+
} else {
88+
str.split(',')
89+
.map(|s| s.trim().parse())
90+
.collect::<Result<Vec<PublicKeyBytes>, _>>()?
91+
}
92+
}
93+
None => Vec::new(),
94+
};
95+
4496
Ok(Self {
4597
vc_token_path: clap_utils::parse_required(matches, VC_TOKEN_FLAG)?,
4698
vc_url: clap_utils::parse_required(matches, VC_URL_FLAG)?,
99+
beacon_url: clap_utils::parse_optional(matches, BEACON_URL_FLAG)?,
100+
validators_to_display,
47101
})
48102
}
49103
}
50104

51-
pub async fn cli_run(matches: &ArgMatches, dump_config: DumpConfig) -> Result<(), String> {
105+
pub async fn cli_run<E: EthSpec>(
106+
matches: &ArgMatches,
107+
dump_config: DumpConfig,
108+
) -> Result<(), String> {
52109
let config = ListConfig::from_cli(matches)?;
53110
if dump_config.should_exit_early(&config)? {
54111
Ok(())
55112
} else {
56-
run(config).await?;
113+
run::<E>(config).await?;
57114
Ok(())
58115
}
59116
}
60117

61-
async fn run(config: ListConfig) -> Result<Vec<SingleKeystoreResponse>, String> {
118+
async fn run<E: EthSpec>(config: ListConfig) -> Result<Vec<SingleKeystoreResponse>, String> {
62119
let ListConfig {
63120
vc_url,
64121
vc_token_path,
122+
beacon_url,
123+
mut validators_to_display,
65124
} = config;
66125

67126
let (_, validators) = vc_http_client(vc_url.clone(), &vc_token_path).await?;
68127

69128
println!("List of validators ({}):", validators.len());
70129

71-
for validator in &validators {
72-
println!("{}", validator.validating_pubkey);
130+
if validators_to_display.is_empty() {
131+
validators_to_display = validators.iter().map(|v| v.validating_pubkey).collect();
73132
}
74133

134+
if let Some(ref beacon_url) = beacon_url {
135+
for validator in &validators_to_display {
136+
let beacon_node = BeaconNodeHttpClient::new(
137+
SensitiveUrl::parse(beacon_url.as_ref())
138+
.map_err(|e| format!("Failed to parse beacon http server: {:?}", e))?,
139+
Timeouts::set_all(Duration::from_secs(12)),
140+
);
141+
142+
let validator_data = beacon_node
143+
.get_beacon_states_validator_id(StateId::Head, &ValidatorId::PublicKey(*validator))
144+
.await
145+
.map_err(|e| format!("Failed to get updated validator details: {:?}", e))?
146+
.ok_or_else(|| {
147+
format!("Validator {} is not present in the beacon state", validator)
148+
})?
149+
.data;
150+
151+
match validator_data.status {
152+
ValidatorStatus::ActiveExiting => {
153+
let exit_epoch = validator_data.validator.exit_epoch;
154+
let withdrawal_epoch = validator_data.validator.withdrawable_epoch;
155+
156+
let genesis_data = beacon_node
157+
.get_beacon_genesis()
158+
.await
159+
.map_err(|e| format!("Failed to get genesis data: {}", e))?
160+
.data;
161+
162+
let config_and_preset = beacon_node
163+
.get_config_spec::<ConfigAndPreset>()
164+
.await
165+
.map_err(|e| format!("Failed to get config spec: {}", e))?
166+
.data;
167+
168+
let spec = ChainSpec::from_config::<E>(config_and_preset.config())
169+
.ok_or("Failed to create chain spec")?;
170+
171+
let current_epoch = get_current_epoch::<E>(genesis_data.genesis_time, &spec)
172+
.ok_or("Failed to get current epoch. Please check your system time")?;
173+
174+
eprintln!(
175+
"Voluntary exit for validator {} has been accepted into the beacon chain. \
176+
Note that the voluntary exit is subject chain finalization. \
177+
Before the chain has finalized, there is a low \
178+
probability that the exit may be reverted.",
179+
validator
180+
);
181+
eprintln!(
182+
"Current epoch: {}, Exit epoch: {}, Withdrawable epoch: {}",
183+
current_epoch, exit_epoch, withdrawal_epoch
184+
);
185+
eprintln!("Please keep your validator running till exit epoch");
186+
eprintln!(
187+
"Exit epoch in approximately {} secs",
188+
(exit_epoch - current_epoch) * spec.seconds_per_slot * E::slots_per_epoch()
189+
);
190+
}
191+
ValidatorStatus::ExitedSlashed | ValidatorStatus::ExitedUnslashed => {
192+
eprintln!(
193+
"Validator {} has exited at epoch: {}",
194+
validator, validator_data.validator.exit_epoch
195+
);
196+
}
197+
_ => {
198+
eprintln!(
199+
"Validator {} has not initiated voluntary exit or the voluntary exit \
200+
is yet to be accepted into the beacon chain. Validator status is: {}",
201+
validator, validator_data.status
202+
)
203+
}
204+
}
205+
}
206+
} else {
207+
for validator in &validators {
208+
println!("{}", validator.validating_pubkey);
209+
}
210+
}
75211
Ok(validators)
76212
}
77213

0 commit comments

Comments
 (0)