Skip to main content

agave_validator/
admin_rpc_service.rs

1use {
2    agave_votor::{
3        event::VotorEvent, vote_history::VoteHistory, vote_history_storage::VoteHistoryStorage,
4    },
5    crossbeam_channel::Sender,
6    jsonrpc_core::{BoxFuture, ErrorCode, MetaIoHandler, Metadata, Result},
7    jsonrpc_core_client::{RpcError, transports::ipc},
8    jsonrpc_derive::rpc,
9    jsonrpc_ipc_server::{
10        RequestContext, ServerBuilder, tokio::sync::oneshot::channel as oneshot_channel,
11    },
12    log::*,
13    serde::{Deserialize, Serialize, de::Deserializer},
14    solana_clock::{Epoch, Slot},
15    solana_core::{
16        admin_rpc_post_init::AdminRpcRequestMetadataPostInit,
17        banking_stage::{
18            BankingControlMsg, BankingStage,
19            transaction_scheduler::scheduler_controller::SchedulerConfig,
20        },
21        consensus::{Tower, tower_storage::TowerStorage},
22        repair::repair_service,
23        validator::{
24            BlockProductionMethod, SchedulerPacing, TransactionStructure, ValidatorStartProgress,
25            should_require_vote_history_file,
26        },
27    },
28    solana_geyser_plugin_manager::GeyserPluginManagerRequest,
29    solana_gossip::contact_info::{ContactInfo, Protocol, SOCKET_ADDR_UNSPECIFIED},
30    solana_keypair::{Keypair, read_keypair_file},
31    solana_metrics::{datapoint_info, datapoint_warn},
32    solana_pubkey::Pubkey,
33    solana_runtime::{bank::VATHealthError, snapshot_controller::SnapshotController},
34    solana_signer::Signer,
35    solana_validator_exit::Exit,
36    std::{
37        collections::{HashMap, HashSet},
38        env, error,
39        fmt::{self, Display},
40        net::{IpAddr, SocketAddr},
41        num::NonZeroUsize,
42        path::{Path, PathBuf},
43        sync::{
44            Arc, RwLock,
45            atomic::{AtomicBool, Ordering},
46        },
47        thread::{self, Builder},
48        time::{Duration, Instant, SystemTime},
49    },
50    tokio::runtime::Runtime,
51};
52
53#[derive(Clone)]
54pub struct AdminRpcRequestMetadata {
55    pub rpc_addr: Option<SocketAddr>,
56    pub start_time: SystemTime,
57    pub start_progress: Arc<RwLock<ValidatorStartProgress>>,
58    pub validator_exit: Arc<RwLock<Exit>>,
59    pub validator_exit_backpressure: HashMap<String, Arc<AtomicBool>>,
60    pub authorized_voter_keypairs: Arc<RwLock<Vec<Arc<Keypair>>>>,
61    pub tower_storage: Arc<dyn TowerStorage>,
62    pub vote_history_storage: Arc<dyn VoteHistoryStorage>,
63    pub staked_nodes_overrides: Arc<RwLock<HashMap<Pubkey, u64>>>,
64    pub post_init: Arc<RwLock<Option<AdminRpcRequestMetadataPostInit>>>,
65    pub rpc_to_plugin_manager_sender: Option<Sender<GeyserPluginManagerRequest>>,
66}
67
68impl Metadata for AdminRpcRequestMetadata {}
69
70impl AdminRpcRequestMetadata {
71    fn with_post_init<F, R>(&self, func: F) -> Result<R>
72    where
73        F: FnOnce(&AdminRpcRequestMetadataPostInit) -> Result<R>,
74    {
75        if let Some(post_init) = self.post_init.read().unwrap().as_ref() {
76            func(post_init)
77        } else {
78            Err(jsonrpc_core::error::Error::invalid_params(
79                "Retry once validator start up is complete",
80            ))
81        }
82    }
83
84    fn snapshot_controller(&self) -> Option<Arc<SnapshotController>> {
85        self.with_post_init(|post_init| Ok(post_init.snapshot_controller.clone()))
86            .map_err(|_| {
87                // The error from with_post_init is not relevant, as it is meant for RPC callers
88                warn!("snapshot_controller unavailable, shutting down without taking snapshot");
89            })
90            .ok()
91    }
92}
93
94#[derive(Debug, Deserialize, Serialize)]
95pub struct AdminRpcContactInfo {
96    pub id: String,
97    pub gossip: SocketAddr,
98    pub tvu: SocketAddr,
99    pub serve_repair_quic: SocketAddr,
100    pub tpu: SocketAddr,
101    pub tpu_forwards: SocketAddr,
102    pub tpu_vote: SocketAddr,
103    pub rpc: SocketAddr,
104    pub rpc_pubsub: SocketAddr,
105    pub serve_repair: SocketAddr,
106    pub last_updated_timestamp: u64,
107    pub shred_version: u16,
108}
109
110#[derive(Debug, Deserialize, Serialize)]
111pub struct AdminRpcRepairWhitelist {
112    pub whitelist: Vec<Pubkey>,
113}
114
115#[derive(Debug, Deserialize, Serialize)]
116pub struct AdminRpcValidatorAdmissionTicketStatus {
117    pub vote_account: Pubkey,
118    pub voting_enabled: bool,
119    pub current_epoch: Epoch,
120    pub vat_active: bool,
121    pub in_current_epoch_vat: bool,
122    pub current_epoch_vote_account_stake: u64,
123    pub current_epoch_vote_accounts: usize,
124    pub next_epoch_vat_failure_reason: Option<VATHealthError>,
125}
126
127impl From<ContactInfo> for AdminRpcContactInfo {
128    fn from(node: ContactInfo) -> Self {
129        macro_rules! unwrap_socket {
130            ($name:ident) => {
131                node.$name().unwrap_or(SOCKET_ADDR_UNSPECIFIED)
132            };
133            ($name:ident, $protocol:expr) => {
134                node.$name($protocol).unwrap_or(SOCKET_ADDR_UNSPECIFIED)
135            };
136        }
137        Self {
138            id: node.pubkey().to_string(),
139            last_updated_timestamp: node.wallclock(),
140            gossip: unwrap_socket!(gossip),
141            tvu: unwrap_socket!(tvu, Protocol::UDP),
142            serve_repair_quic: unwrap_socket!(serve_repair, Protocol::QUIC),
143            tpu: unwrap_socket!(tpu, Protocol::UDP),
144            tpu_forwards: unwrap_socket!(tpu_forwards, Protocol::UDP),
145            tpu_vote: unwrap_socket!(tpu_vote, Protocol::UDP),
146            rpc: unwrap_socket!(rpc),
147            rpc_pubsub: unwrap_socket!(rpc_pubsub),
148            serve_repair: unwrap_socket!(serve_repair, Protocol::UDP),
149            shred_version: node.shred_version(),
150        }
151    }
152}
153
154impl Display for AdminRpcContactInfo {
155    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156        writeln!(f, "Identity: {}", self.id)?;
157        writeln!(f, "Gossip: {}", self.gossip)?;
158        writeln!(f, "TVU: {}", self.tvu)?;
159        writeln!(f, "TPU: {}", self.tpu)?;
160        writeln!(f, "TPU Forwards: {}", self.tpu_forwards)?;
161        writeln!(f, "TPU Votes: {}", self.tpu_vote)?;
162        writeln!(f, "RPC: {}", self.rpc)?;
163        writeln!(f, "RPC Pubsub: {}", self.rpc_pubsub)?;
164        writeln!(f, "Serve Repair: {}", self.serve_repair)?;
165        writeln!(f, "Last Updated Timestamp: {}", self.last_updated_timestamp)?;
166        writeln!(f, "Shred Version: {}", self.shred_version)
167    }
168}
169impl solana_cli_output::VerboseDisplay for AdminRpcContactInfo {}
170impl solana_cli_output::QuietDisplay for AdminRpcContactInfo {}
171
172impl Display for AdminRpcRepairWhitelist {
173    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174        writeln!(f, "Repair whitelist: {:?}", self.whitelist)
175    }
176}
177impl solana_cli_output::VerboseDisplay for AdminRpcRepairWhitelist {}
178impl solana_cli_output::QuietDisplay for AdminRpcRepairWhitelist {}
179
180#[rpc]
181pub trait AdminRpc {
182    type Metadata;
183
184    /// Initiates validator exit; exit is asynchronous so the validator
185    /// will almost certainly still be running when this method returns
186    #[rpc(meta, name = "exit")]
187    fn exit(&self, meta: Self::Metadata) -> Result<()>;
188
189    /// Return the process id (pid)
190    #[rpc(meta, name = "pid")]
191    fn pid(&self, meta: Self::Metadata) -> Result<u32>;
192
193    #[rpc(meta, name = "reloadPlugin")]
194    fn reload_plugin(
195        &self,
196        meta: Self::Metadata,
197        name: String,
198        config_file: String,
199    ) -> BoxFuture<Result<()>>;
200
201    #[rpc(meta, name = "unloadPlugin")]
202    fn unload_plugin(&self, meta: Self::Metadata, name: String) -> BoxFuture<Result<()>>;
203
204    #[rpc(meta, name = "loadPlugin")]
205    fn load_plugin(&self, meta: Self::Metadata, config_file: String) -> BoxFuture<Result<String>>;
206
207    #[rpc(meta, name = "listPlugins")]
208    fn list_plugins(&self, meta: Self::Metadata) -> BoxFuture<Result<Vec<String>>>;
209
210    #[rpc(meta, name = "rpcAddress")]
211    fn rpc_addr(&self, meta: Self::Metadata) -> Result<Option<SocketAddr>>;
212
213    #[rpc(name = "setLogFilter")]
214    fn set_log_filter(&self, filter: String) -> Result<()>;
215
216    #[rpc(meta, name = "startTime")]
217    fn start_time(&self, meta: Self::Metadata) -> Result<SystemTime>;
218
219    #[rpc(meta, name = "startProgress")]
220    fn start_progress(&self, meta: Self::Metadata) -> Result<ValidatorStartProgress>;
221
222    #[rpc(meta, name = "addAuthorizedVoter")]
223    fn add_authorized_voter(&self, meta: Self::Metadata, keypair_file: String) -> Result<()>;
224
225    #[rpc(meta, name = "addAuthorizedVoterFromBytes")]
226    fn add_authorized_voter_from_bytes(&self, meta: Self::Metadata, keypair: Vec<u8>)
227    -> Result<()>;
228
229    #[rpc(meta, name = "removeAllAuthorizedVoters")]
230    fn remove_all_authorized_voters(&self, meta: Self::Metadata) -> Result<()>;
231
232    #[rpc(meta, name = "setIdentity")]
233    fn set_identity(
234        &self,
235        meta: Self::Metadata,
236        keypair_file: String,
237        require_tower: bool,
238        require_vote_history: bool,
239    ) -> Result<()>;
240
241    #[rpc(meta, name = "setIdentityFromBytes")]
242    fn set_identity_from_bytes(
243        &self,
244        meta: Self::Metadata,
245        identity_keypair: Vec<u8>,
246        require_tower: bool,
247        require_vote_history: bool,
248    ) -> Result<()>;
249
250    #[rpc(meta, name = "setStakedNodesOverrides")]
251    fn set_staked_nodes_overrides(&self, meta: Self::Metadata, path: String) -> Result<()>;
252
253    #[rpc(meta, name = "contactInfo")]
254    fn contact_info(&self, meta: Self::Metadata) -> Result<AdminRpcContactInfo>;
255
256    #[rpc(meta, name = "validatorAdmissionTicketStatus")]
257    fn vat_status(&self, meta: Self::Metadata) -> Result<AdminRpcValidatorAdmissionTicketStatus>;
258
259    #[rpc(meta, name = "selectActiveInterface")]
260    fn select_active_interface(&self, meta: Self::Metadata, interface: IpAddr) -> Result<()>;
261
262    #[rpc(meta, name = "repairShredFromPeer")]
263    fn repair_shred_from_peer(
264        &self,
265        meta: Self::Metadata,
266        pubkey: Option<Pubkey>,
267        slot: u64,
268        shred_index: u64,
269    ) -> Result<()>;
270
271    #[rpc(meta, name = "repairWhitelist")]
272    fn repair_whitelist(&self, meta: Self::Metadata) -> Result<AdminRpcRepairWhitelist>;
273
274    #[rpc(meta, name = "setRepairWhitelist")]
275    fn set_repair_whitelist(&self, meta: Self::Metadata, whitelist: Vec<Pubkey>) -> Result<()>;
276
277    #[rpc(meta, name = "setPublicTpuAddress")]
278    fn set_public_tpu_address(
279        &self,
280        meta: Self::Metadata,
281        public_tpu_addr: SocketAddr,
282    ) -> Result<()>;
283
284    #[rpc(meta, name = "setPublicTpuForwardsAddress")]
285    fn set_public_tpu_forwards_address(
286        &self,
287        meta: Self::Metadata,
288        public_tpu_forwards_addr: SocketAddr,
289    ) -> Result<()>;
290
291    #[rpc(meta, name = "setPublicTvuAddress")]
292    fn set_public_tvu_address(
293        &self,
294        meta: Self::Metadata,
295        public_tvu_addr: SocketAddr,
296    ) -> Result<()>;
297
298    #[rpc(meta, name = "manageBlockProduction")]
299    fn manage_block_production(
300        &self,
301        meta: Self::Metadata,
302        block_production_method: BlockProductionMethod,
303        transaction_struct: TransactionStructure,
304        num_workers: NonZeroUsize,
305        scheduler_pacing: SchedulerPacing,
306    ) -> Result<()>;
307
308    #[rpc(meta, name = "isGeneratingSnapshots")]
309    fn is_generating_snapshots(&self, meta: Self::Metadata) -> Result<bool>;
310
311    #[rpc(meta, name = "blockstorePurge")]
312    fn blockstore_purge(&self, meta: Self::Metadata, maximum_purge_slot: Slot) -> Result<()>;
313}
314
315pub struct AdminRpcImpl;
316impl AdminRpc for AdminRpcImpl {
317    type Metadata = AdminRpcRequestMetadata;
318
319    fn exit(&self, meta: Self::Metadata) -> Result<()> {
320        debug!("exit admin rpc request received");
321
322        thread::Builder::new()
323            .name("solProcessExit".into())
324            .spawn(move || {
325                let start_time = Instant::now();
326
327                // Trigger a fastboot snapshot before exiting
328                if let Some(snapshot_controller) = meta.snapshot_controller() {
329                    let latest_snapshot_slot = snapshot_controller.latest_bank_snapshot_slot();
330
331                    info!("Requesting fastboot snapshot before exit");
332                    snapshot_controller.request_fastboot_snapshot();
333
334                    // Wait up to 5s for a snapshot to finish. This should allow time for the
335                    // fastboot snapshot to complete without stalling exit indefinitely.
336                    // The timeout will be hit in the event new roots are not being created.
337                    let timeout = Duration::from_secs(5);
338                    while snapshot_controller.latest_bank_snapshot_slot() == latest_snapshot_slot {
339                        if start_time.elapsed() > timeout {
340                            warn!("Timeout waiting for snapshot to complete");
341                            datapoint_warn!(
342                                "admin-rpc-snapshot-timeout",
343                                ("timeout_us", start_time.elapsed().as_micros(), i64)
344                            );
345                            break;
346                        }
347                        thread::sleep(Duration::from_millis(100));
348                    }
349                    info!(
350                        "Requesting fastboot snapshot before exit... Done in {:?}",
351                        start_time.elapsed()
352                    );
353                }
354
355                // Delay exit signal until this RPC request completes, otherwise the caller of `exit` might
356                // receive a confusing error as the validator shuts down before a response is sent back.
357                // If elapsed time has already taken 100ms, there is no need for further delay
358                if start_time.elapsed().as_millis() < 100 {
359                    thread::sleep(Duration::from_millis(100));
360                }
361
362                info!("validator exit requested");
363                meta.validator_exit.write().unwrap().exit();
364
365                if !meta.validator_exit_backpressure.is_empty() {
366                    let service_names = meta.validator_exit_backpressure.keys();
367                    info!("Wait for these services to complete: {service_names:?}");
368                    loop {
369                        // The initial sleep is a grace period to allow the services to raise their
370                        // backpressure flags.
371                        // Subsequent sleeps are to throttle how often we check and log.
372                        thread::sleep(Duration::from_secs(1));
373
374                        let mut any_flags_raised = false;
375                        for (name, flag) in meta.validator_exit_backpressure.iter() {
376                            let is_flag_raised = flag.load(Ordering::Relaxed);
377                            if is_flag_raised {
378                                info!("{name}'s exit backpressure flag is raised");
379                                any_flags_raised = true;
380                            }
381                        }
382                        if !any_flags_raised {
383                            break;
384                        }
385                    }
386                    info!("All services have completed");
387                }
388
389                // TODO: Debug why Exit doesn't always cause the validator to fully exit
390                // (rocksdb background processing or some other stuck thread perhaps?).
391                //
392                // If the process is still alive after five seconds, exit harder
393                thread::sleep(Duration::from_secs(
394                    env::var("SOLANA_VALIDATOR_EXIT_TIMEOUT")
395                        .ok()
396                        .and_then(|x| x.parse().ok())
397                        .unwrap_or(5),
398                ));
399                warn!("validator exit timeout");
400                std::process::exit(0);
401            })
402            .unwrap();
403
404        Ok(())
405    }
406
407    fn pid(&self, _meta: Self::Metadata) -> Result<u32> {
408        Ok(std::process::id())
409    }
410
411    fn reload_plugin(
412        &self,
413        meta: Self::Metadata,
414        name: String,
415        config_file: String,
416    ) -> BoxFuture<Result<()>> {
417        Box::pin(async move {
418            // Construct channel for plugin to respond to this particular rpc request instance
419            let (response_sender, response_receiver) = oneshot_channel();
420
421            // Send request to plugin manager if there is a geyser service
422            if let Some(ref rpc_to_manager_sender) = meta.rpc_to_plugin_manager_sender {
423                rpc_to_manager_sender
424                    .send(GeyserPluginManagerRequest::ReloadPlugin {
425                        name,
426                        config_file,
427                        response_sender,
428                    })
429                    .expect("GeyerPluginService should never drop request receiver");
430            } else {
431                return Err(jsonrpc_core::Error {
432                    code: ErrorCode::InvalidRequest,
433                    message: "No geyser plugin service".to_string(),
434                    data: None,
435                });
436            }
437
438            // Await response from plugin manager
439            response_receiver
440                .await
441                .expect("GeyerPluginService's oneshot sender shouldn't drop early")
442        })
443    }
444
445    fn load_plugin(&self, meta: Self::Metadata, config_file: String) -> BoxFuture<Result<String>> {
446        Box::pin(async move {
447            // Construct channel for plugin to respond to this particular rpc request instance
448            let (response_sender, response_receiver) = oneshot_channel();
449
450            // Send request to plugin manager if there is a geyser service
451            if let Some(ref rpc_to_manager_sender) = meta.rpc_to_plugin_manager_sender {
452                rpc_to_manager_sender
453                    .send(GeyserPluginManagerRequest::LoadPlugin {
454                        config_file,
455                        response_sender,
456                    })
457                    .expect("GeyerPluginService should never drop request receiver");
458            } else {
459                return Err(jsonrpc_core::Error {
460                    code: ErrorCode::InvalidRequest,
461                    message: "No geyser plugin service".to_string(),
462                    data: None,
463                });
464            }
465
466            // Await response from plugin manager
467            response_receiver
468                .await
469                .expect("GeyerPluginService's oneshot sender shouldn't drop early")
470        })
471    }
472
473    fn unload_plugin(&self, meta: Self::Metadata, name: String) -> BoxFuture<Result<()>> {
474        Box::pin(async move {
475            // Construct channel for plugin to respond to this particular rpc request instance
476            let (response_sender, response_receiver) = oneshot_channel();
477
478            // Send request to plugin manager if there is a geyser service
479            if let Some(ref rpc_to_manager_sender) = meta.rpc_to_plugin_manager_sender {
480                rpc_to_manager_sender
481                    .send(GeyserPluginManagerRequest::UnloadPlugin {
482                        name,
483                        response_sender,
484                    })
485                    .expect("GeyerPluginService should never drop request receiver");
486            } else {
487                return Err(jsonrpc_core::Error {
488                    code: ErrorCode::InvalidRequest,
489                    message: "No geyser plugin service".to_string(),
490                    data: None,
491                });
492            }
493
494            // Await response from plugin manager
495            response_receiver
496                .await
497                .expect("GeyerPluginService's oneshot sender shouldn't drop early")
498        })
499    }
500
501    fn list_plugins(&self, meta: Self::Metadata) -> BoxFuture<Result<Vec<String>>> {
502        Box::pin(async move {
503            // Construct channel for plugin to respond to this particular rpc request instance
504            let (response_sender, response_receiver) = oneshot_channel();
505
506            // Send request to plugin manager
507            if let Some(ref rpc_to_manager_sender) = meta.rpc_to_plugin_manager_sender {
508                rpc_to_manager_sender
509                    .send(GeyserPluginManagerRequest::ListPlugins { response_sender })
510                    .expect("GeyerPluginService should never drop request receiver");
511            } else {
512                return Err(jsonrpc_core::Error {
513                    code: ErrorCode::InvalidRequest,
514                    message: "No geyser plugin service".to_string(),
515                    data: None,
516                });
517            }
518
519            // Await response from plugin manager
520            response_receiver
521                .await
522                .expect("GeyerPluginService's oneshot sender shouldn't drop early")
523        })
524    }
525
526    fn rpc_addr(&self, meta: Self::Metadata) -> Result<Option<SocketAddr>> {
527        debug!("rpc_addr admin rpc request received");
528        Ok(meta.rpc_addr)
529    }
530
531    fn set_log_filter(&self, filter: String) -> Result<()> {
532        debug!("set_log_filter admin rpc request received");
533        agave_logger::setup_with(&filter);
534        Ok(())
535    }
536
537    fn start_time(&self, meta: Self::Metadata) -> Result<SystemTime> {
538        debug!("start_time admin rpc request received");
539        Ok(meta.start_time)
540    }
541
542    fn start_progress(&self, meta: Self::Metadata) -> Result<ValidatorStartProgress> {
543        debug!("start_progress admin rpc request received");
544        Ok(*meta.start_progress.read().unwrap())
545    }
546
547    fn add_authorized_voter(&self, meta: Self::Metadata, keypair_file: String) -> Result<()> {
548        debug!("add_authorized_voter request received");
549
550        let authorized_voter = read_keypair_file(keypair_file)
551            .map_err(|err| jsonrpc_core::error::Error::invalid_params(format!("{err}")))?;
552
553        AdminRpcImpl::add_authorized_voter_keypair(meta, authorized_voter)
554    }
555
556    fn add_authorized_voter_from_bytes(
557        &self,
558        meta: Self::Metadata,
559        keypair: Vec<u8>,
560    ) -> Result<()> {
561        debug!("add_authorized_voter_from_bytes request received");
562
563        let authorized_voter = Keypair::try_from(keypair.as_ref()).map_err(|err| {
564            jsonrpc_core::error::Error::invalid_params(format!(
565                "Failed to read authorized voter keypair from provided byte array: {err}"
566            ))
567        })?;
568
569        AdminRpcImpl::add_authorized_voter_keypair(meta, authorized_voter)
570    }
571
572    fn remove_all_authorized_voters(&self, meta: Self::Metadata) -> Result<()> {
573        debug!("remove_all_authorized_voters received");
574        meta.authorized_voter_keypairs.write().unwrap().clear();
575        Ok(())
576    }
577
578    fn set_identity(
579        &self,
580        meta: Self::Metadata,
581        keypair_file: String,
582        require_tower: bool,
583        require_vote_history: bool,
584    ) -> Result<()> {
585        debug!("set_identity request received");
586
587        let identity_keypair = read_keypair_file(&keypair_file).map_err(|err| {
588            jsonrpc_core::error::Error::invalid_params(format!(
589                "Failed to read identity keypair from {keypair_file}: {err}"
590            ))
591        })?;
592
593        AdminRpcImpl::set_identity_keypair(
594            meta,
595            identity_keypair,
596            require_tower,
597            require_vote_history,
598        )
599    }
600
601    fn set_identity_from_bytes(
602        &self,
603        meta: Self::Metadata,
604        identity_keypair: Vec<u8>,
605        require_tower: bool,
606        require_vote_history: bool,
607    ) -> Result<()> {
608        debug!("set_identity_from_bytes request received");
609
610        let identity_keypair = Keypair::try_from(identity_keypair.as_ref()).map_err(|err| {
611            jsonrpc_core::error::Error::invalid_params(format!(
612                "Failed to read identity keypair from provided byte array: {err}"
613            ))
614        })?;
615
616        AdminRpcImpl::set_identity_keypair(
617            meta,
618            identity_keypair,
619            require_tower,
620            require_vote_history,
621        )
622    }
623
624    fn set_staked_nodes_overrides(&self, meta: Self::Metadata, path: String) -> Result<()> {
625        let loaded_config = load_staked_nodes_overrides(&path)
626            .map_err(|err| {
627                error!("Failed to load staked nodes overrides from {path}: {err}");
628                jsonrpc_core::error::Error::internal_error()
629            })?
630            .staked_map_id;
631        let mut write_staked_nodes = meta.staked_nodes_overrides.write().unwrap();
632        write_staked_nodes.clear();
633        write_staked_nodes.extend(loaded_config);
634        info!("Staked nodes overrides loaded from {path}");
635        debug!("overrides map: {write_staked_nodes:?}");
636        Ok(())
637    }
638
639    fn contact_info(&self, meta: Self::Metadata) -> Result<AdminRpcContactInfo> {
640        meta.with_post_init(|post_init| Ok(post_init.cluster_info.my_contact_info().into()))
641    }
642
643    fn vat_status(&self, meta: Self::Metadata) -> Result<AdminRpcValidatorAdmissionTicketStatus> {
644        debug!("vat_status request received");
645        meta.with_post_init(|post_init| {
646            let bank = post_init.bank_forks.read().unwrap().root_bank();
647            let current_epoch = bank.epoch();
648            let vat_active = bank.feature_set.snapshot().validator_admission_ticket;
649            let epoch_vote_accounts = bank
650                .epoch_vote_accounts(current_epoch)
651                .ok_or_else(jsonrpc_core::Error::internal_error)?;
652            let current_epoch_vote_account_stake = epoch_vote_accounts
653                .get(&post_init.vote_account)
654                .map(|(stake, _vote_account)| *stake)
655                .unwrap_or_default();
656            let in_current_epoch_vote_accounts =
657                epoch_vote_accounts.contains_key(&post_init.vote_account);
658
659            let next_epoch_vat_failure_reason = bank
660                .get_vat_health_for_next_epoch(&post_init.vote_account)
661                .err();
662
663            let voting_enabled = !meta.authorized_voter_keypairs.read().unwrap().is_empty();
664            Ok(AdminRpcValidatorAdmissionTicketStatus {
665                vote_account: post_init.vote_account,
666                voting_enabled,
667                current_epoch,
668                vat_active,
669                in_current_epoch_vat: vat_active && in_current_epoch_vote_accounts,
670                current_epoch_vote_account_stake,
671                current_epoch_vote_accounts: epoch_vote_accounts.len(),
672                next_epoch_vat_failure_reason,
673            })
674        })
675    }
676
677    fn select_active_interface(&self, meta: Self::Metadata, interface: IpAddr) -> Result<()> {
678        debug!("select_active_interface received: {interface}");
679        meta.with_post_init(|post_init| {
680            let node = post_init.node.as_ref().ok_or_else(|| {
681                jsonrpc_core::Error::invalid_params("`Node` not initialized in post_init")
682            })?;
683
684            node.switch_active_interface(interface, &post_init.cluster_info)
685                .map_err(|e| {
686                    jsonrpc_core::Error::invalid_params(format!(
687                        "Switching failed due to error {e}"
688                    ))
689                })?;
690            info!("Switched primary interface to {interface}");
691            Ok(())
692        })
693    }
694
695    fn repair_shred_from_peer(
696        &self,
697        meta: Self::Metadata,
698        pubkey: Option<Pubkey>,
699        slot: u64,
700        shred_index: u64,
701    ) -> Result<()> {
702        debug!("repair_shred_from_peer request received");
703
704        meta.with_post_init(|post_init| {
705            repair_service::RepairService::request_repair_for_shred_from_peer(
706                post_init.cluster_info.clone(),
707                post_init.cluster_slots.clone(),
708                pubkey,
709                slot,
710                shred_index,
711                &post_init.repair_socket,
712                post_init.outstanding_repair_requests.clone(),
713            );
714            Ok(())
715        })
716    }
717
718    fn repair_whitelist(&self, meta: Self::Metadata) -> Result<AdminRpcRepairWhitelist> {
719        debug!("repair_whitelist request received");
720
721        meta.with_post_init(|post_init| {
722            let whitelist: Vec<_> = post_init
723                .repair_whitelist
724                .read()
725                .unwrap()
726                .iter()
727                .copied()
728                .collect();
729            Ok(AdminRpcRepairWhitelist { whitelist })
730        })
731    }
732
733    fn set_repair_whitelist(&self, meta: Self::Metadata, whitelist: Vec<Pubkey>) -> Result<()> {
734        debug!("set_repair_whitelist request received");
735
736        let whitelist: HashSet<Pubkey> = whitelist.into_iter().collect();
737        meta.with_post_init(|post_init| {
738            *post_init.repair_whitelist.write().unwrap() = whitelist;
739            warn!(
740                "Repair whitelist set to {:?}",
741                post_init.repair_whitelist.read().unwrap()
742            );
743            Ok(())
744        })
745    }
746
747    fn set_public_tpu_address(
748        &self,
749        meta: Self::Metadata,
750        public_tpu_addr: SocketAddr,
751    ) -> Result<()> {
752        debug!("set_public_tpu_address rpc request received: {public_tpu_addr}");
753
754        meta.with_post_init(|post_init| {
755            post_init
756                .cluster_info
757                .my_contact_info()
758                .tpu(Protocol::QUIC)
759                .ok_or_else(|| {
760                    error!(
761                        "The public TPU QUIC address isn't being published. The node is likely in \
762                         repair mode. See help for --restricted-repair-only-mode for more \
763                         information."
764                    );
765                    jsonrpc_core::error::Error::internal_error()
766                })?;
767            post_init
768                .cluster_info
769                .set_tpu_quic(public_tpu_addr)
770                .map_err(|err| {
771                    error!("Failed to set public TPU QUIC address to {public_tpu_addr}: {err}");
772                    jsonrpc_core::error::Error::internal_error()
773                })?;
774            let my_contact_info = post_init.cluster_info.my_contact_info();
775            warn!(
776                "Public TPU addresses set to {:?} (quic)",
777                my_contact_info.tpu(Protocol::QUIC),
778            );
779            Ok(())
780        })
781    }
782
783    fn set_public_tpu_forwards_address(
784        &self,
785        meta: Self::Metadata,
786        public_tpu_forwards_addr: SocketAddr,
787    ) -> Result<()> {
788        debug!("set_public_tpu_forwards_address rpc request received: {public_tpu_forwards_addr}");
789
790        meta.with_post_init(|post_init| {
791            post_init
792                .cluster_info
793                .my_contact_info()
794                .tpu_forwards(Protocol::QUIC)
795                .ok_or_else(|| {
796                    error!(
797                        "The public TPU Forwards address isn't being published. The node is \
798                         likely in repair mode. See help for --restricted-repair-only-mode for \
799                         more information."
800                    );
801                    jsonrpc_core::error::Error::internal_error()
802                })?;
803            post_init
804                .cluster_info
805                .set_tpu_forwards_quic(public_tpu_forwards_addr)
806                .map_err(|err| {
807                    error!(
808                        "Failed to set public TPU QUIC address to {public_tpu_forwards_addr}: \
809                         {err}"
810                    );
811                    jsonrpc_core::error::Error::internal_error()
812                })?;
813            let my_contact_info = post_init.cluster_info.my_contact_info();
814            warn!(
815                "Public TPU Forwards address set to {:?} (quic)",
816                my_contact_info.tpu_forwards(Protocol::QUIC),
817            );
818            Ok(())
819        })
820    }
821
822    fn set_public_tvu_address(
823        &self,
824        meta: Self::Metadata,
825        public_tvu_addr: SocketAddr,
826    ) -> Result<()> {
827        debug!("set_public_tvu_address rpc request received: {public_tvu_addr}");
828
829        meta.with_post_init(|post_init| {
830            post_init
831                .cluster_info
832                .my_contact_info()
833                .tvu(Protocol::UDP)
834                .ok_or_else(|| {
835                    error!(
836                        "The public TVU address isn't being published. The node is likely in \
837                         repair mode. See help for --restricted-repair-only-mode for more \
838                         information."
839                    );
840                    jsonrpc_core::error::Error::internal_error()
841                })?;
842            post_init
843                .cluster_info
844                .set_tvu_socket(public_tvu_addr)
845                .map_err(|err| {
846                    error!("Failed to set public TVU address to {public_tvu_addr}: {err}");
847                    jsonrpc_core::error::Error::internal_error()
848                })?;
849            let my_contact_info = post_init.cluster_info.my_contact_info();
850            warn!(
851                "Public TVU addresses set to {:?}",
852                my_contact_info.tvu(Protocol::UDP),
853            );
854            Ok(())
855        })
856    }
857
858    fn manage_block_production(
859        &self,
860        meta: Self::Metadata,
861        block_production_method: BlockProductionMethod,
862        transaction_struct: TransactionStructure,
863        num_workers: NonZeroUsize,
864        scheduler_pacing: SchedulerPacing,
865    ) -> Result<()> {
866        debug!("manage_block_production rpc request received");
867
868        if num_workers > BankingStage::max_num_workers() {
869            return Err(jsonrpc_core::error::Error::invalid_params(format!(
870                "Number of workers ({}) exceeds maximum allowed ({})",
871                num_workers,
872                BankingStage::max_num_workers()
873            )));
874        }
875
876        if transaction_struct != TransactionStructure::View {
877            warn!("TransactionStructure::Sdk has no effect on block production");
878        }
879
880        meta.with_post_init(|post_init| {
881            if post_init
882                .banking_control_sender
883                .try_send(BankingControlMsg::Internal {
884                    block_production_method,
885                    num_workers,
886                    config: SchedulerConfig { scheduler_pacing },
887                })
888                .is_err()
889            {
890                error!("Banking stage already switching schedulers");
891
892                return Err(jsonrpc_core::error::Error::internal_error());
893            }
894
895            Ok(())
896        })
897    }
898
899    fn is_generating_snapshots(&self, meta: Self::Metadata) -> Result<bool> {
900        if let Some(snapshot_controller) = meta.snapshot_controller() {
901            Ok(snapshot_controller.is_generating_snapshots())
902        } else {
903            Err(jsonrpc_core::error::Error::invalid_params(
904                "snapshot_controller unavailable",
905            ))
906        }
907    }
908
909    fn blockstore_purge(&self, meta: Self::Metadata, maximum_purge_slot: Slot) -> Result<()> {
910        meta.with_post_init(|post_init| {
911            post_init
912                .blockstore
913                .send_manual_purge_request(maximum_purge_slot)
914                .map_err(|err| jsonrpc_core::Error {
915                    code: ErrorCode::InvalidRequest,
916                    message: format!("{err}"),
917                    data: None,
918                })
919        })
920    }
921}
922
923impl AdminRpcImpl {
924    fn add_authorized_voter_keypair(
925        meta: AdminRpcRequestMetadata,
926        authorized_voter: Keypair,
927    ) -> Result<()> {
928        let mut authorized_voter_keypairs = meta.authorized_voter_keypairs.write().unwrap();
929
930        if authorized_voter_keypairs
931            .iter()
932            .any(|x| x.pubkey() == authorized_voter.pubkey())
933        {
934            Err(jsonrpc_core::error::Error::invalid_params(
935                "Authorized voter already present",
936            ))
937        } else {
938            authorized_voter_keypairs.push(Arc::new(authorized_voter));
939            Ok(())
940        }
941    }
942
943    fn set_identity_keypair(
944        meta: AdminRpcRequestMetadata,
945        identity_keypair: Keypair,
946        require_tower: bool,
947        require_vote_history: bool,
948    ) -> Result<()> {
949        meta.with_post_init(|post_init| {
950            if require_tower {
951                let _ = Tower::restore(meta.tower_storage.as_ref(), &identity_keypair.pubkey())
952                    .map_err(|err| {
953                        jsonrpc_core::error::Error::invalid_params(format!(
954                            "Unable to load tower file for identity {}: {}",
955                            identity_keypair.pubkey(),
956                            err
957                        ))
958                    })?;
959            }
960
961            if require_vote_history {
962                let should_require_vote_history = {
963                    let bank_forks = post_init.bank_forks.read().unwrap();
964                    should_require_vote_history_file(
965                        &bank_forks.working_bank(),
966                        &post_init.vote_account,
967                        &identity_keypair.pubkey(),
968                    )
969                };
970                if should_require_vote_history {
971                    let _ = VoteHistory::restore(
972                        meta.vote_history_storage.as_ref(),
973                        &identity_keypair.pubkey(),
974                    )
975                    .map_err(|err| {
976                        jsonrpc_core::error::Error::invalid_params(format!(
977                            "Unable to load vote history file for identity {}: {}. The vote \
978                             account {} has prior Alpenglow votes. Ensure the vote history file \
979                             is present or (dangerous) use --do-not-require-vote-history if you \
980                             know what you're doing",
981                            identity_keypair.pubkey(),
982                            err,
983                            post_init.vote_account
984                        ))
985                    })?;
986                }
987            }
988
989            for (key, notifier) in &*post_init.notifies.read().unwrap() {
990                if let Err(err) = notifier.update_key(&identity_keypair) {
991                    error!("Error updating network layer keypair: {err} on {key:?}");
992                }
993            }
994
995            let old_identity = post_init.cluster_info.id();
996            let new_identity = identity_keypair.pubkey();
997            solana_metrics::set_host_id(new_identity.to_string());
998            // Emit the datapoint after updating metrics to emit the new pubkey
999            datapoint_info!(
1000                "validator-set_identity",
1001                ("old_id", old_identity.to_string(), String),
1002                ("new_id", new_identity.to_string(), String),
1003                ("version", solana_version::version!(), String),
1004            );
1005            post_init
1006                .cluster_info
1007                .set_keypair(Arc::new(identity_keypair));
1008            post_init
1009                .votor_event_sender
1010                .send(VotorEvent::SetIdentity)
1011                .map_err(|err| jsonrpc_core::error::Error {
1012                    code: ErrorCode::InternalError,
1013                    message: format!("Failed to send SetIdentity event: {err}").to_string(),
1014                    data: None,
1015                })?;
1016
1017            warn!("Identity set to {new_identity}");
1018            Ok(())
1019        })
1020    }
1021}
1022
1023// Start the Admin RPC interface
1024pub fn run(ledger_path: &Path, metadata: AdminRpcRequestMetadata) {
1025    let admin_rpc_path = admin_rpc_path(ledger_path);
1026
1027    let event_loop = tokio::runtime::Builder::new_multi_thread()
1028        .thread_name("solAdminRpcEl")
1029        .worker_threads(3) // Three still seems like a lot, and better than the default of available core count
1030        .enable_all()
1031        .build()
1032        .unwrap();
1033
1034    Builder::new()
1035        .name("solAdminRpc".to_string())
1036        .spawn(move || {
1037            let mut io = MetaIoHandler::default();
1038            io.extend_with(AdminRpcImpl.to_delegate());
1039
1040            let validator_exit = metadata.validator_exit.clone();
1041            let server = ServerBuilder::with_meta_extractor(io, move |_req: &RequestContext| {
1042                metadata.clone()
1043            })
1044            .event_loop_executor(event_loop.handle().clone())
1045            .start(&format!("{}", admin_rpc_path.display()));
1046
1047            match server {
1048                Err(err) => {
1049                    warn!("Unable to start admin rpc service: {err:?}");
1050                }
1051                Ok(server) => {
1052                    info!("started admin rpc service!");
1053                    let close_handle = server.close_handle();
1054                    validator_exit
1055                        .write()
1056                        .unwrap()
1057                        .register_exit(Box::new(move || {
1058                            close_handle.close();
1059                        }));
1060
1061                    server.wait();
1062                }
1063            }
1064        })
1065        .unwrap();
1066}
1067
1068fn admin_rpc_path(ledger_path: &Path) -> PathBuf {
1069    #[cfg(target_family = "windows")]
1070    {
1071        // More information about the wackiness of pipe names over at
1072        // https://docs.microsoft.com/en-us/windows/win32/ipc/pipe-names
1073        if let Some(ledger_filename) = ledger_path.file_name() {
1074            PathBuf::from(format!(
1075                "\\\\.\\pipe\\{}-admin.rpc",
1076                ledger_filename.to_string_lossy()
1077            ))
1078        } else {
1079            PathBuf::from("\\\\.\\pipe\\admin.rpc")
1080        }
1081    }
1082    #[cfg(not(target_family = "windows"))]
1083    {
1084        ledger_path.join("admin.rpc")
1085    }
1086}
1087
1088// Connect to the Admin RPC interface
1089pub async fn connect(ledger_path: &Path) -> std::result::Result<gen_client::Client, RpcError> {
1090    let admin_rpc_path = admin_rpc_path(ledger_path);
1091    if !admin_rpc_path.exists() {
1092        Err(RpcError::Client(format!(
1093            "{} does not exist",
1094            admin_rpc_path.display()
1095        )))
1096    } else {
1097        ipc::connect::<_, gen_client::Client>(&format!("{}", admin_rpc_path.display())).await
1098    }
1099}
1100
1101// Create a runtime for use by client side admin RPC interface calls
1102pub fn runtime() -> Runtime {
1103    tokio::runtime::Builder::new_multi_thread()
1104        .thread_name("solAdminRpcRt")
1105        .enable_all()
1106        // The agave-validator subcommands make few admin RPC calls and block
1107        // on the results so two workers is plenty
1108        .worker_threads(2)
1109        .build()
1110        .expect("new tokio runtime")
1111}
1112
1113#[derive(Default, Deserialize, Clone)]
1114pub struct StakedNodesOverrides {
1115    #[serde(deserialize_with = "deserialize_pubkey_map")]
1116    pub staked_map_id: HashMap<Pubkey, u64>,
1117}
1118
1119pub fn deserialize_pubkey_map<'de, D>(des: D) -> std::result::Result<HashMap<Pubkey, u64>, D::Error>
1120where
1121    D: Deserializer<'de>,
1122{
1123    let container: HashMap<String, u64> = serde::Deserialize::deserialize(des)?;
1124    let mut container_typed: HashMap<Pubkey, u64> = HashMap::new();
1125    for (key, value) in container.iter() {
1126        let typed_key = Pubkey::try_from(key.as_str())
1127            .map_err(|_| serde::de::Error::invalid_type(serde::de::Unexpected::Map, &"PubKey"))?;
1128        container_typed.insert(typed_key, *value);
1129    }
1130    Ok(container_typed)
1131}
1132
1133pub fn load_staked_nodes_overrides(
1134    path: &String,
1135) -> std::result::Result<StakedNodesOverrides, Box<dyn error::Error>> {
1136    debug!("Loading staked nodes overrides configuration from {path}");
1137    if Path::new(&path).exists() {
1138        let file = std::fs::File::open(path)?;
1139        Ok(serde_yaml::from_reader(file)?)
1140    } else {
1141        Err(format!("Staked nodes overrides provided '{path}' a non-existing file path.").into())
1142    }
1143}
1144
1145#[cfg(test)]
1146mod tests {
1147    use {
1148        super::*,
1149        agave_snapshots::snapshot_config::SnapshotConfig,
1150        agave_votor::event::VotorEventSender,
1151        assert_matches::assert_matches,
1152        crossbeam_channel::bounded,
1153        serde_json::Value,
1154        solana_accounts_db::{
1155            accounts_db::{ACCOUNTS_DB_CONFIG_FOR_TESTING, AccountsDbConfig},
1156            accounts_index::AccountSecondaryIndexes,
1157        },
1158        solana_core::{
1159            admin_rpc_post_init::{KeyUpdaterType, KeyUpdaters},
1160            consensus::tower_storage::NullTowerStorage,
1161            validator::{Validator, ValidatorConfig, ValidatorTpuConfig},
1162        },
1163        solana_gossip::{cluster_info::ClusterInfo, node::Node},
1164        solana_ledger::{
1165            blockstore::Blockstore,
1166            create_new_tmp_ledger,
1167            genesis_utils::{
1168                GenesisConfigInfo, create_genesis_config, create_genesis_config_with_leader,
1169            },
1170            get_tmp_ledger_path_auto_delete,
1171        },
1172        solana_net_utils::{SocketAddrSpace, sockets::bind_to_localhost_unique},
1173        solana_rpc::rpc::create_validator_exit,
1174        solana_runtime::{
1175            bank::{Bank, BankTestConfig},
1176            bank_forks::BankForks,
1177        },
1178        std::{collections::HashSet, fs::remove_dir_all, sync::atomic::AtomicBool},
1179        tokio::sync::mpsc,
1180    };
1181
1182    #[derive(Default)]
1183    struct TestConfig {
1184        account_indexes: AccountSecondaryIndexes,
1185        votor_event_sender: Option<VotorEventSender>,
1186    }
1187
1188    struct RpcHandler {
1189        io: MetaIoHandler<AdminRpcRequestMetadata>,
1190        meta: AdminRpcRequestMetadata,
1191    }
1192
1193    impl RpcHandler {
1194        fn _start() -> Self {
1195            Self::start_with_config(TestConfig::default())
1196        }
1197
1198        fn start_with_config(config: TestConfig) -> Self {
1199            let keypair = Arc::new(Keypair::new());
1200            let cluster_info = Arc::new(ClusterInfo::new(
1201                ContactInfo::new(
1202                    keypair.pubkey(),
1203                    solana_time_utils::timestamp(), // wallclock
1204                    0u16,                           // shred_version
1205                ),
1206                keypair,
1207                SocketAddrSpace::Unspecified,
1208            ));
1209            let exit = Arc::new(AtomicBool::new(false));
1210            let validator_exit = create_validator_exit(exit);
1211            let (bank_forks, vote_keypair) = new_bank_forks_with_config(BankTestConfig {
1212                accounts_db_config: AccountsDbConfig {
1213                    account_indexes: Some(config.account_indexes),
1214                    ..ACCOUNTS_DB_CONFIG_FOR_TESTING
1215                },
1216            });
1217
1218            let (snapshot_request_sender, _) = bounded(1024);
1219            let snapshot_controller = Arc::new(SnapshotController::new(
1220                snapshot_request_sender.clone(),
1221                SnapshotConfig::default(),
1222                bank_forks.read().unwrap().root(),
1223            ));
1224
1225            let ledger_path = get_tmp_ledger_path_auto_delete!();
1226            let blockstore = Arc::new(Blockstore::open(ledger_path.path()).unwrap());
1227
1228            let vote_account = vote_keypair.pubkey();
1229            let start_progress = Arc::new(RwLock::new(ValidatorStartProgress::default()));
1230            let repair_whitelist = Arc::new(RwLock::new(HashSet::new()));
1231            let votor_event_sender = config.votor_event_sender.unwrap_or_else(|| {
1232                let (votor_event_sender, _) = bounded(1024);
1233                votor_event_sender
1234            });
1235            let meta = AdminRpcRequestMetadata {
1236                rpc_addr: None,
1237                start_time: SystemTime::now(),
1238                start_progress,
1239                validator_exit,
1240                validator_exit_backpressure: HashMap::default(),
1241                authorized_voter_keypairs: Arc::new(RwLock::new(vec![vote_keypair])),
1242                tower_storage: Arc::new(NullTowerStorage {}),
1243                vote_history_storage: Arc::new(
1244                    agave_votor::vote_history_storage::NullVoteHistoryStorage::default(),
1245                ),
1246                post_init: Arc::new(RwLock::new(Some(AdminRpcRequestMetadataPostInit {
1247                    cluster_info,
1248                    bank_forks,
1249                    vote_account,
1250                    repair_whitelist,
1251                    notifies: Arc::new(RwLock::new(KeyUpdaters::default())),
1252                    repair_socket: Arc::new(bind_to_localhost_unique().expect("should bind")),
1253                    outstanding_repair_requests: Arc::<
1254                        RwLock<repair_service::OutstandingShredRepairs>,
1255                    >::default(),
1256                    cluster_slots: Arc::new(
1257                        solana_core::cluster_slots_service::cluster_slots::ClusterSlots::default_for_tests(),
1258                    ),
1259                    node: None,
1260                    banking_control_sender: mpsc::channel(1).0,
1261                    snapshot_controller,
1262                    blockstore,
1263                    votor_event_sender,
1264                }))),
1265                staked_nodes_overrides: Arc::new(RwLock::new(HashMap::new())),
1266                rpc_to_plugin_manager_sender: None,
1267            };
1268            let mut io = MetaIoHandler::default();
1269            io.extend_with(AdminRpcImpl.to_delegate());
1270
1271            Self { io, meta }
1272        }
1273    }
1274
1275    fn new_bank_forks_with_config(
1276        config: BankTestConfig,
1277    ) -> (Arc<RwLock<BankForks>>, Arc<Keypair>) {
1278        let GenesisConfigInfo {
1279            genesis_config,
1280            voting_keypair,
1281            ..
1282        } = create_genesis_config(1_000_000_000);
1283
1284        let bank = Bank::new_with_paths_for_tests(&genesis_config, Some(config), vec![], None);
1285        (BankForks::new_rw_arc(bank), Arc::new(voting_keypair))
1286    }
1287
1288    // This test checks that the rpc call to `set_identity` works a expected with
1289    // Bank but without validator.
1290    #[test]
1291    fn test_set_identity() {
1292        let (votor_event_sender, votor_event_receiver) = bounded(1024);
1293        let rpc = RpcHandler::start_with_config(TestConfig {
1294            account_indexes: AccountSecondaryIndexes::default(),
1295            votor_event_sender: Some(votor_event_sender),
1296        });
1297
1298        let RpcHandler { io, meta, .. } = rpc;
1299
1300        let expected_validator_id = Keypair::new();
1301        let validator_id_bytes = format!("{:?}", expected_validator_id.to_bytes());
1302
1303        let set_id_request = format!(
1304            r#"{{"jsonrpc":"2.0","id":1,"method":"setIdentityFromBytes","params":[{validator_id_bytes}, false, false]}}"#,
1305        );
1306        let response = io.handle_request_sync(&set_id_request, meta.clone());
1307        let actual_parsed_response: Value =
1308            serde_json::from_str(&response.expect("actual response"))
1309                .expect("actual response deserialization");
1310
1311        let expected_parsed_response: Value = serde_json::from_str(
1312            r#"{
1313                "id": 1,
1314                "jsonrpc": "2.0",
1315                "result": null
1316            }"#,
1317        )
1318        .expect("Failed to parse expected response");
1319        assert_eq!(actual_parsed_response, expected_parsed_response);
1320
1321        let contact_info_request =
1322            r#"{"jsonrpc":"2.0","id":1,"method":"contactInfo","params":[]}"#.to_string();
1323        let response = io.handle_request_sync(&contact_info_request, meta.clone());
1324        let parsed_response: Value = serde_json::from_str(&response.expect("actual response"))
1325            .expect("actual response deserialization");
1326        let actual_validator_id = parsed_response["result"]["id"]
1327            .as_str()
1328            .expect("Expected a string");
1329        assert_eq!(
1330            actual_validator_id,
1331            expected_validator_id.pubkey().to_string()
1332        );
1333        let event = votor_event_receiver
1334            .recv()
1335            .expect("Failed to receive SetIdentity event");
1336        assert_matches!(event, VotorEvent::SetIdentity);
1337    }
1338
1339    #[test]
1340    fn test_vat_status() {
1341        let rpc = RpcHandler::_start();
1342        let RpcHandler { io, meta, .. } = rpc;
1343        let post_init = meta.post_init.read().unwrap().clone().unwrap();
1344        let bank = post_init.bank_forks.read().unwrap().root_bank();
1345        let current_epoch = bank.epoch();
1346        let epoch_vote_accounts = bank.epoch_vote_accounts(current_epoch).unwrap();
1347        let expected_vat_active = bank.feature_set.snapshot().validator_admission_ticket;
1348        let expected_in_vat =
1349            expected_vat_active && epoch_vote_accounts.contains_key(&post_init.vote_account);
1350        let expected_stake = epoch_vote_accounts
1351            .get(&post_init.vote_account)
1352            .map(|(stake, _vote_account)| *stake)
1353            .unwrap_or_default();
1354
1355        let request =
1356            r#"{"jsonrpc":"2.0","id":1,"method":"validatorAdmissionTicketStatus","params":[]}"#;
1357        let response = io.handle_request_sync(request, meta.clone());
1358        let result: Value = serde_json::from_str(&response.expect("actual response"))
1359            .expect("actual response deserialization");
1360        let status: AdminRpcValidatorAdmissionTicketStatus =
1361            serde_json::from_value(result["result"].clone()).unwrap();
1362
1363        assert_eq!(status.vote_account, post_init.vote_account);
1364        assert!(status.voting_enabled);
1365        assert_eq!(status.current_epoch, current_epoch);
1366        assert_eq!(status.vat_active, expected_vat_active);
1367        assert_eq!(status.in_current_epoch_vat, expected_in_vat);
1368        assert_eq!(status.current_epoch_vote_account_stake, expected_stake);
1369        assert_eq!(
1370            status.current_epoch_vote_accounts,
1371            epoch_vote_accounts.len()
1372        );
1373    }
1374
1375    struct TestValidatorWithAdminRpc {
1376        meta: AdminRpcRequestMetadata,
1377        io: MetaIoHandler<AdminRpcRequestMetadata>,
1378        validator_ledger_path: PathBuf,
1379    }
1380
1381    impl TestValidatorWithAdminRpc {
1382        fn new() -> Self {
1383            let leader_keypair = Keypair::new();
1384            let leader_node = Node::new_localhost_with_pubkey(&leader_keypair.pubkey());
1385
1386            let validator_keypair = Keypair::new();
1387            let validator_node = Node::new_localhost_with_pubkey(&validator_keypair.pubkey());
1388            let genesis_config =
1389                create_genesis_config_with_leader(10_000, &leader_keypair.pubkey(), 1000)
1390                    .genesis_config;
1391            let (validator_ledger_path, _blockhash) = create_new_tmp_ledger!(&genesis_config);
1392
1393            let voting_keypair = Arc::new(Keypair::new());
1394            let voting_pubkey = voting_keypair.pubkey();
1395            let authorized_voter_keypairs = Arc::new(RwLock::new(vec![voting_keypair]));
1396            let validator_config = ValidatorConfig {
1397                rpc_addrs: Some((
1398                    validator_node.info.rpc().unwrap(),
1399                    validator_node.info.rpc_pubsub().unwrap(),
1400                )),
1401                ..ValidatorConfig::default_for_test()
1402            };
1403            let start_progress = Arc::new(RwLock::new(ValidatorStartProgress::default()));
1404
1405            let post_init = Arc::new(RwLock::new(None));
1406            let meta = AdminRpcRequestMetadata {
1407                rpc_addr: validator_config.rpc_addrs.map(|(rpc_addr, _)| rpc_addr),
1408                start_time: SystemTime::now(),
1409                start_progress: start_progress.clone(),
1410                validator_exit: validator_config.validator_exit.clone(),
1411                validator_exit_backpressure: HashMap::default(),
1412                authorized_voter_keypairs: authorized_voter_keypairs.clone(),
1413                tower_storage: Arc::new(NullTowerStorage {}),
1414                vote_history_storage: Arc::new(
1415                    agave_votor::vote_history_storage::NullVoteHistoryStorage::default(),
1416                ),
1417                post_init: post_init.clone(),
1418                staked_nodes_overrides: Arc::new(RwLock::new(HashMap::new())),
1419                rpc_to_plugin_manager_sender: None,
1420            };
1421
1422            let _validator = Validator::new(
1423                validator_node,
1424                Arc::new(validator_keypair),
1425                &validator_ledger_path,
1426                &voting_pubkey,
1427                authorized_voter_keypairs,
1428                vec![leader_node.info],
1429                &validator_config,
1430                None, // rpc_to_plugin_manager_receiver
1431                start_progress.clone(),
1432                SocketAddrSpace::Unspecified,
1433                ValidatorTpuConfig::new_for_tests(),
1434                post_init.clone(),
1435                None,
1436            )
1437            .expect("assume successful validator start");
1438            assert_eq!(
1439                *start_progress.read().unwrap(),
1440                ValidatorStartProgress::Running
1441            );
1442            let post_init = post_init.read().unwrap();
1443
1444            assert!(post_init.is_some());
1445            let post_init = post_init.as_ref().unwrap();
1446            let notifies = post_init.notifies.read().unwrap();
1447            let updater_keys: HashSet<KeyUpdaterType> =
1448                notifies.into_iter().map(|(key, _)| key.clone()).collect();
1449            assert_eq!(
1450                updater_keys,
1451                HashSet::from_iter(vec![
1452                    KeyUpdaterType::Tpu,
1453                    KeyUpdaterType::TpuForwards,
1454                    KeyUpdaterType::TpuVote,
1455                    KeyUpdaterType::Forward,
1456                    KeyUpdaterType::RpcService,
1457                    KeyUpdaterType::Bls,
1458                    KeyUpdaterType::BlsConnectionCache,
1459                ])
1460            );
1461            let mut io = MetaIoHandler::default();
1462            io.extend_with(AdminRpcImpl.to_delegate());
1463            Self {
1464                meta,
1465                io,
1466                validator_ledger_path,
1467            }
1468        }
1469
1470        fn handle_request(&self, request: &str) -> Option<String> {
1471            self.io.handle_request_sync(request, self.meta.clone())
1472        }
1473    }
1474
1475    impl Drop for TestValidatorWithAdminRpc {
1476        fn drop(&mut self) {
1477            remove_dir_all(self.validator_ledger_path.clone()).unwrap();
1478        }
1479    }
1480
1481    #[test]
1482    fn test_no_post_init_no_snapshot_controller() {
1483        let validator_exit = create_validator_exit(Arc::new(AtomicBool::new(false)));
1484        let voting_keypair = Arc::new(Keypair::new());
1485        let authorized_voter_keypairs = Arc::new(RwLock::new(vec![voting_keypair]));
1486        let start_progress = Arc::new(RwLock::new(ValidatorStartProgress::default()));
1487
1488        let post_init = Arc::new(RwLock::new(None));
1489        let meta = AdminRpcRequestMetadata {
1490            rpc_addr: None,
1491            start_time: SystemTime::now(),
1492            start_progress: start_progress.clone(),
1493            validator_exit,
1494            validator_exit_backpressure: HashMap::default(),
1495            authorized_voter_keypairs: authorized_voter_keypairs.clone(),
1496            tower_storage: Arc::new(NullTowerStorage {}),
1497            vote_history_storage: Arc::new(
1498                agave_votor::vote_history_storage::NullVoteHistoryStorage::default(),
1499            ),
1500            post_init: post_init.clone(),
1501            staked_nodes_overrides: Arc::new(RwLock::new(HashMap::new())),
1502            rpc_to_plugin_manager_sender: None,
1503        };
1504
1505        let snapshot_controller = meta.snapshot_controller();
1506        assert!(snapshot_controller.is_none());
1507    }
1508
1509    // This test checks that `set_identity` call works with working validator and client.
1510    #[test]
1511    fn test_set_identity_with_validator() {
1512        let test_validator = TestValidatorWithAdminRpc::new();
1513        let expected_validator_id = Keypair::new();
1514        let validator_id_bytes = format!("{:?}", expected_validator_id.to_bytes());
1515
1516        let set_id_request = format!(
1517            r#"{{"jsonrpc":"2.0","id":1,"method":"setIdentityFromBytes","params":[{validator_id_bytes}, false, false]}}"#,
1518        );
1519        let response = test_validator.handle_request(&set_id_request);
1520        let actual_parsed_response: Value =
1521            serde_json::from_str(&response.expect("actual response"))
1522                .expect("actual response deserialization");
1523
1524        let expected_parsed_response: Value = serde_json::from_str(
1525            r#"{
1526                "id": 1,
1527                "jsonrpc": "2.0",
1528                "result": null
1529            }"#,
1530        )
1531        .expect("Failed to parse expected response");
1532        assert_eq!(actual_parsed_response, expected_parsed_response);
1533
1534        let contact_info_request =
1535            r#"{"jsonrpc":"2.0","id":1,"method":"contactInfo","params":[]}"#.to_string();
1536        let response = test_validator.handle_request(&contact_info_request);
1537        let parsed_response: Value = serde_json::from_str(&response.expect("actual response"))
1538            .expect("actual response deserialization");
1539        let actual_validator_id = parsed_response["result"]["id"]
1540            .as_str()
1541            .expect("Expected a string");
1542        assert_eq!(
1543            actual_validator_id,
1544            expected_validator_id.pubkey().to_string()
1545        );
1546
1547        let contact_info_request =
1548            r#"{"jsonrpc":"2.0","id":1,"method":"exit","params":[]}"#.to_string();
1549        let exit_response = test_validator.handle_request(&contact_info_request);
1550        let actual_parsed_response: Value =
1551            serde_json::from_str(&exit_response.expect("actual response"))
1552                .expect("actual response deserialization");
1553        assert_eq!(actual_parsed_response, expected_parsed_response);
1554    }
1555
1556    #[test]
1557    fn test_is_generating_snapshots() {
1558        // Test with snapshots enabled
1559        let rpc = RpcHandler::start_with_config(TestConfig::default());
1560        let RpcHandler { io, meta, .. } = rpc;
1561
1562        let request = r#"{"jsonrpc":"2.0","id":1,"method":"isGeneratingSnapshots","params":[]}"#;
1563        let response = io.handle_request_sync(request, meta.clone());
1564        let result: Value = serde_json::from_str(&response.expect("actual response"))
1565            .expect("actual response deserialization");
1566
1567        // Should return a boolean result indicating if snapshots are being generated
1568        assert!(result["result"].is_boolean());
1569        // Verify that snapshots are being generated since the test setup includes a snapshot controller
1570        assert!(result["result"].as_bool().unwrap());
1571    }
1572
1573    #[test]
1574    fn test_is_generating_snapshots_no_controller() {
1575        // Test with snapshots enabled
1576        let rpc = RpcHandler::start_with_config(TestConfig::default());
1577        let RpcHandler { io, .. } = rpc;
1578
1579        // Test with no post_init (snapshot_controller unavailable)
1580        let request = r#"{"jsonrpc":"2.0","id":1,"method":"isGeneratingSnapshots","params":[]}"#;
1581        let validator_exit = create_validator_exit(Arc::new(AtomicBool::new(false)));
1582        let authorized_voter_keypairs = Arc::new(RwLock::new(vec![Arc::new(Keypair::new())]));
1583        let start_progress = Arc::new(RwLock::new(ValidatorStartProgress::default()));
1584
1585        let meta_no_post_init = AdminRpcRequestMetadata {
1586            rpc_addr: None,
1587            start_time: SystemTime::now(),
1588            start_progress,
1589            validator_exit,
1590            validator_exit_backpressure: HashMap::default(),
1591            authorized_voter_keypairs,
1592            tower_storage: Arc::new(NullTowerStorage {}),
1593            vote_history_storage: Arc::new(
1594                agave_votor::vote_history_storage::NullVoteHistoryStorage::default(),
1595            ),
1596            post_init: Arc::new(RwLock::new(None)),
1597            staked_nodes_overrides: Arc::new(RwLock::new(HashMap::new())),
1598            rpc_to_plugin_manager_sender: None,
1599        };
1600
1601        let response = io.handle_request_sync(request, meta_no_post_init);
1602        let result: Value = serde_json::from_str(&response.expect("actual response"))
1603            .expect("actual response deserialization");
1604
1605        // Should return an error when snapshot_controller is unavailable
1606        assert!(result["error"].is_object());
1607        assert_eq!(
1608            result["error"]["message"].as_str().unwrap(),
1609            "snapshot_controller unavailable"
1610        );
1611    }
1612}