1
1
use crate :: { common:: vc_http_client, DumpConfig } ;
2
2
3
3
use clap:: { Arg , ArgAction , ArgMatches , Command } ;
4
- use eth2:: types:: Epoch ;
4
+ use eth2:: types:: { ConfigAndPreset , Epoch , StateId , ValidatorId , ValidatorStatus } ;
5
5
use eth2:: { BeaconNodeHttpClient , SensitiveUrl , Timeouts } ;
6
6
use serde:: { Deserialize , Serialize } ;
7
7
use serde_json;
8
+ use slot_clock:: { SlotClock , SystemTimeSlotClock } ;
8
9
use std:: path:: PathBuf ;
9
10
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;
11
13
12
14
pub const CMD : & str = "exit" ;
13
15
pub const BEACON_URL_FLAG : & str = "beacon-node" ;
@@ -96,17 +98,20 @@ impl ExitConfig {
96
98
}
97
99
}
98
100
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 > {
100
105
let config = ExitConfig :: from_cli ( matches) ?;
101
106
102
107
if dump_config. should_exit_early ( & config) ? {
103
108
Ok ( ( ) )
104
109
} else {
105
- run ( config) . await
110
+ run :: < E > ( config) . await
106
111
}
107
112
}
108
113
109
- async fn run ( config : ExitConfig ) -> Result < ( ) , String > {
114
+ async fn run < E : EthSpec > ( config : ExitConfig ) -> Result < ( ) , String > {
110
115
let ExitConfig {
111
116
vc_url,
112
117
vc_token_path,
@@ -130,9 +135,9 @@ async fn run(config: ExitConfig) -> Result<(), String> {
130
135
}
131
136
}
132
137
133
- for validator_to_exit in & validators_to_exit {
138
+ for validator_to_exit in validators_to_exit {
134
139
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)
136
141
. await
137
142
. map_err ( |e| format ! ( "Failed to generate voluntary exit message: {}" , e) ) ?;
138
143
@@ -143,6 +148,7 @@ async fn run(config: ExitConfig) -> Result<(), String> {
143
148
Err ( e) => eprintln ! ( "Failed to serialize voluntary exit message: {}" , e) ,
144
149
}
145
150
151
+ // only publish the voluntary exit if the --beacon-node flag is present
146
152
if beacon_url. is_some ( ) {
147
153
let beacon_node = if let Some ( ref beacon_url) = beacon_url {
148
154
BeaconNodeHttpClient :: new (
@@ -157,7 +163,7 @@ async fn run(config: ExitConfig) -> Result<(), String> {
157
163
if beacon_node
158
164
. get_node_syncing ( )
159
165
. 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) ) ?
161
167
. data
162
168
. is_syncing
163
169
{
@@ -176,6 +182,97 @@ async fn run(config: ExitConfig) -> Result<(), String> {
176
182
"Successfully validated and published voluntary exit for validator {}" ,
177
183
validator_to_exit
178
184
) ;
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
+ }
179
276
}
180
277
}
181
278
Ok ( ( ) )
0 commit comments