11use crate :: { common:: vc_http_client, DumpConfig } ;
22
33use clap:: { Arg , ArgAction , ArgMatches , Command } ;
4- use eth2:: types:: Epoch ;
4+ use eth2:: types:: { ConfigAndPreset , Epoch , StateId , ValidatorId , ValidatorStatus } ;
55use eth2:: { BeaconNodeHttpClient , SensitiveUrl , Timeouts } ;
66use serde:: { Deserialize , Serialize } ;
77use serde_json;
8+ use slot_clock:: { SlotClock , SystemTimeSlotClock } ;
89use std:: path:: PathBuf ;
910use 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
1214pub const CMD : & str = "exit" ;
1315pub 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 ( ( ) )
0 commit comments