Skip to content

Commit b2b6442

Browse files
committed
Add validator status after exit
1 parent 63b9a08 commit b2b6442

File tree

4 files changed

+111
-12
lines changed

4 files changed

+111
-12
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

validator_manager/Cargo.toml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ eth2_wallet = { workspace = true }
1515
account_utils = { workspace = true }
1616
serde = { workspace = true }
1717
serde_json = { workspace = true }
18+
slot_clock = { workspace = true }
1819
ethereum_serde_utils = { workspace = true }
1920
tree_hash = { workspace = true }
2021
eth2 = { workspace = true }
@@ -24,9 +25,9 @@ derivative = { workspace = true }
2425
logging = { workspace = true }
2526

2627
[dev-dependencies]
27-
tempfile = { workspace = true }
28+
beacon_chain = { workspace = true }
29+
http_api = { workspace = true }
2830
regex = { workspace = true }
31+
tempfile = { workspace = true }
2932
validator_http_api = { workspace = true }
30-
http_api = { workspace = true }
31-
beacon_chain = { workspace = true }
3233

validator_manager/src/exit_validators.rs

Lines changed: 105 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use crate::{common::vc_http_client, DumpConfig};
22

33
use clap::{Arg, ArgAction, ArgMatches, Command};
4-
use eth2::types::Epoch;
4+
use eth2::types::{ConfigAndPreset, Epoch, StateId, ValidatorId, ValidatorStatus};
55
use eth2::{BeaconNodeHttpClient, SensitiveUrl, Timeouts};
66
use serde::{Deserialize, Serialize};
77
use serde_json;
8+
use slot_clock::{SlotClock, SystemTimeSlotClock};
89
use std::path::PathBuf;
910
use std::time::Duration;
10-
use types::PublicKeyBytes;
11+
use types::{ChainSpec, EthSpec, PublicKeyBytes};
12+
// use validator_http_api::create_signed_voluntary_exit::get_current_epoch;
1113

1214
pub const CMD: &str = "exit";
1315
pub const BEACON_URL_FLAG: &str = "beacon-node";
@@ -96,17 +98,20 @@ impl ExitConfig {
9698
}
9799
}
98100

99-
pub async fn cli_run(matches: &ArgMatches, dump_config: DumpConfig) -> Result<(), String> {
101+
pub async fn cli_run<E: EthSpec>(
102+
matches: &ArgMatches,
103+
dump_config: DumpConfig,
104+
) -> Result<(), String> {
100105
let config = ExitConfig::from_cli(matches)?;
101106

102107
if dump_config.should_exit_early(&config)? {
103108
Ok(())
104109
} else {
105-
run(config).await
110+
run::<E>(config).await
106111
}
107112
}
108113

109-
async fn run(config: ExitConfig) -> Result<(), String> {
114+
async fn run<E: EthSpec>(config: ExitConfig) -> Result<(), String> {
110115
let ExitConfig {
111116
vc_url,
112117
vc_token_path,
@@ -130,9 +135,9 @@ async fn run(config: ExitConfig) -> Result<(), String> {
130135
}
131136
}
132137

133-
for validator_to_exit in &validators_to_exit {
138+
for validator_to_exit in validators_to_exit {
134139
let exit_message = http_client
135-
.post_validator_voluntary_exit(validator_to_exit, exit_epoch)
140+
.post_validator_voluntary_exit(&validator_to_exit, exit_epoch)
136141
.await
137142
.map_err(|e| format!("Failed to generate voluntary exit message: {}", e))?;
138143

@@ -143,6 +148,7 @@ async fn run(config: ExitConfig) -> Result<(), String> {
143148
Err(e) => eprintln!("Failed to serialize voluntary exit message: {}", e),
144149
}
145150

151+
// only publish the voluntary exit if the --beacon-node flag is present
146152
if beacon_url.is_some() {
147153
let beacon_node = if let Some(ref beacon_url) = beacon_url {
148154
BeaconNodeHttpClient::new(
@@ -157,7 +163,7 @@ async fn run(config: ExitConfig) -> Result<(), String> {
157163
if beacon_node
158164
.get_node_syncing()
159165
.await
160-
.map_err(|e| format!("Failed to get sync status: {:?}", e))?
166+
.map_err(|e| format!("Failed to get beacon node sync status: {:?}", e))?
161167
.data
162168
.is_syncing
163169
{
@@ -176,6 +182,97 @@ async fn run(config: ExitConfig) -> Result<(), String> {
176182
"Successfully validated and published voluntary exit for validator {}",
177183
validator_to_exit
178184
);
185+
186+
// check validator status
187+
let validator_data = beacon_node
188+
.get_beacon_states_validator_id(
189+
StateId::Head,
190+
&ValidatorId::PublicKey(validator_to_exit),
191+
)
192+
.await
193+
.map_err(|e| format!("Failed to get validator details: {:?}", e))?
194+
.ok_or_else(|| {
195+
format!(
196+
"Validator {} is not present in the beacon state. \
197+
Please ensure that your beacon node is synced and the validator has been deposited.",
198+
validator_to_exit)})?
199+
.data;
200+
201+
match validator_data.status {
202+
ValidatorStatus::ActiveExiting => {
203+
let exit_epoch = validator_data.validator.exit_epoch;
204+
let withdrawal_epoch = validator_data.validator.withdrawable_epoch;
205+
206+
let genesis_data = beacon_node
207+
.get_beacon_genesis()
208+
.await
209+
.map_err(|e| format!("Failed to get genesis data: {}", e))?
210+
.data;
211+
212+
let spec = beacon_node
213+
.get_config_spec::<ConfigAndPreset>()
214+
.await
215+
.map_err(|e| format!("Failed to get config spec: {}", e))?
216+
.data;
217+
218+
let chain_spec = ChainSpec::from_config::<E>(spec.config())
219+
.ok_or_else(|| "Failed to create chain spec".to_string())?;
220+
221+
// let slot_clock = SystemTimeSlotClock::new(
222+
// spec.genesis_slot,
223+
// Duration::from_secs(genesis_data.genesis_time),
224+
// Duration::from_secs(spec.config().seconds_per_slot),
225+
// );
226+
227+
// let current_epoch = get_current_epoch::<SystemTimeSlotClock, E>(slot_clock)
228+
// .ok_or_else(|| "Unable to determine current epoch".to_string())?;
229+
230+
fn get_current_epoch<E: EthSpec>(
231+
genesis_time: u64,
232+
spec: &ChainSpec,
233+
) -> Option<Epoch> {
234+
let slot_clock = SystemTimeSlotClock::new(
235+
spec.genesis_slot,
236+
Duration::from_secs(genesis_time),
237+
Duration::from_secs(spec.seconds_per_slot),
238+
);
239+
slot_clock.now().map(|s| s.epoch(E::slots_per_epoch()))
240+
}
241+
242+
let current_epoch =
243+
get_current_epoch::<E>(genesis_data.genesis_time, &chain_spec)
244+
.ok_or("Failed to get current epoch. Please check your system time")?;
245+
eprintln!("Voluntary exit has been accepted into the beacon chain, but not yet finalized. \
246+
Finalization may take several minutes or longer. Before finalization there is a low \
247+
probability that the exit may be reverted.");
248+
eprintln!(
249+
"Current epoch: {}, Exit epoch: {}, Withdrawable epoch: {}",
250+
current_epoch, exit_epoch, withdrawal_epoch
251+
);
252+
eprintln!("Please keep your validator running till exit epoch");
253+
eprintln!(
254+
"Exit epoch in approximately {} secs",
255+
(exit_epoch - current_epoch)
256+
* chain_spec.seconds_per_slot
257+
* E::slots_per_epoch()
258+
);
259+
}
260+
261+
_ => {
262+
eprintln!("Waiting for voluntary exit to be accepted into the beacon chain...")
263+
}
264+
// fn get_current_epoch<T: 'static + SlotClock + Clone, E: EthSpec>(
265+
// slot_clock: T,
266+
// ) -> Option<Epoch> {
267+
// slot_clock.now().map(|s| s.epoch(E::slots_per_epoch()))
268+
// }
269+
270+
// let spec = ChainSpec::mainnet();
271+
272+
// let current_epoch =
273+
// get_current_epoch::<E>(genesis_time, &spec).ok_or("Failed to get current epoch")?;
274+
//let current_epoch = get_current_epoch::<E>(genesis_data.genesis_time, spec);
275+
}
179276
}
180277
}
181278
Ok(())

validator_manager/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ pub fn run<E: EthSpec>(matches: &ArgMatches, env: Environment<E>) -> Result<(),
9797
delete_validators::cli_run(matches, dump_config).await
9898
}
9999
Some((exit_validators::CMD, matches)) => {
100-
exit_validators::cli_run(matches, dump_config).await
100+
exit_validators::cli_run::<E>(matches, dump_config).await
101101
}
102102
Some(("", _)) => Err("No command supplied. See --help.".to_string()),
103103
Some((unknown, _)) => Err(format!(

0 commit comments

Comments
 (0)