feat: implementation of live-slots command (#8129)

This commit is contained in:
Sunny Gleason
2020-02-06 14:16:30 -05:00
committed by GitHub
parent a25e57c397
commit a7fa92b372
7 changed files with 496 additions and 10 deletions

View File

@ -199,6 +199,9 @@ pub enum CliCommand {
commitment_config: CommitmentConfig,
},
LeaderSchedule,
LiveSlots {
url: String,
},
Ping {
lamports: u64,
interval: Duration,
@ -474,6 +477,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
require_keypair: false,
}),
("ping", Some(matches)) => parse_cluster_ping(matches),
("live-slots", Some(matches)) => parse_live_slots(matches),
("block-production", Some(matches)) => parse_show_block_production(matches),
("gossip", Some(_matches)) => Ok(CliCommandInfo {
command: CliCommand::ShowGossip,
@ -1274,6 +1278,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
process_get_transaction_count(&rpc_client, commitment_config)
}
CliCommand::LeaderSchedule => process_leader_schedule(&rpc_client),
CliCommand::LiveSlots { url } => process_live_slots(&url),
CliCommand::Ping {
lamports,
interval,

View File

@ -9,7 +9,11 @@ use clap::{value_t, value_t_or_exit, App, Arg, ArgMatches, SubCommand};
use console::{style, Emoji};
use indicatif::{ProgressBar, ProgressStyle};
use solana_clap_utils::{input_parsers::*, input_validators::*};
use solana_client::{rpc_client::RpcClient, rpc_response::RpcVoteAccountInfo};
use solana_client::{
pubsub_client::{PubsubClient, SlotInfoMessage},
rpc_client::RpcClient,
rpc_response::RpcVoteAccountInfo,
};
use solana_sdk::{
account_utils::StateMut,
clock::{self, Slot},
@ -23,6 +27,10 @@ use solana_sdk::{
use std::{
collections::{HashMap, VecDeque},
net::SocketAddr,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread::sleep,
time::{Duration, Instant},
};
@ -157,6 +165,19 @@ impl ClusterQuerySubCommands for App<'_, '_> {
),
),
)
.subcommand(
SubCommand::with_name("live-slots")
.about("Show information about the current slot progression")
.arg(
Arg::with_name("websocket_url")
.short("w")
.long("ws")
.value_name("URL")
.takes_value(true)
.default_value("ws://127.0.0.1:8900")
.help("WebSocket URL for PubSub RPC connection"),
),
)
.subcommand(
SubCommand::with_name("block-production")
.about("Show information about block production")
@ -246,6 +267,14 @@ pub fn parse_cluster_ping(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Cl
})
}
pub fn parse_live_slots(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let url: String = value_t_or_exit!(matches, "websocket_url", String);
Ok(CliCommandInfo {
command: CliCommand::LiveSlots { url },
require_keypair: false,
})
}
pub fn parse_get_block_time(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let slot = value_t_or_exit!(matches, "slot", u64);
Ok(CliCommandInfo {
@ -810,6 +839,63 @@ pub fn process_ping(
Ok("".to_string())
}
pub fn process_live_slots(url: &str) -> ProcessResult {
let exit = Arc::new(AtomicBool::new(false));
let exit_clone = exit.clone();
ctrlc::set_handler(move || {
exit_clone.store(true, Ordering::Relaxed);
})?;
let mut current: Option<SlotInfoMessage> = None;
let mut message = "".to_string();
let slot_progress = new_spinner_progress_bar();
slot_progress.set_message("Connecting...");
let (mut client, receiver) = PubsubClient::slot_subscribe(url)?;
slot_progress.set_message("Connected.");
loop {
if exit.load(Ordering::Relaxed) {
eprintln!("{}", message);
client.shutdown().unwrap();
break;
}
match receiver.recv() {
Ok(new_info) => {
message = format!("{:?}", new_info).to_owned();
slot_progress.set_message(&message);
if let Some(previous) = current {
let slot_delta: i64 = new_info.slot as i64 - previous.slot as i64;
let root_delta: i64 = new_info.root as i64 - previous.root as i64;
//
// if slot has advanced out of step with the root, we detect
// a mismatch and output the slot information
//
if slot_delta != root_delta {
let prev_root = format!(
"|<- {} <- … <- {} <- {}",
previous.root, previous.parent, previous.slot
)
.to_owned();
slot_progress.println(&prev_root);
}
}
current = Some(new_info);
}
Err(err) => {
eprintln!("disconnected: {:?}", err);
break;
}
}
}
Ok("".to_string())
}
pub fn process_show_gossip(rpc_client: &RpcClient) -> ProcessResult {
let cluster_nodes = rpc_client.get_cluster_nodes()?;