Add show-block-production command
This commit is contained in:
parent
05664d150b
commit
ff171baa67
|
@ -405,7 +405,7 @@ Returns the leader schedule for an epoch
|
|||
|
||||
#### Parameters:
|
||||
|
||||
* `slot` - (optional) Fetch the leader schedule for the epoch that corresponds to the provided slot. If unspecified, the leader schedule for the current epoch is fetch
|
||||
* `slot` - (optional) Fetch the leader schedule for the epoch that corresponds to the provided slot. If unspecified, the leader schedule for the current epoch is fetched
|
||||
* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||
|
||||
#### Results:
|
||||
|
|
|
@ -21,7 +21,7 @@ use solana_faucet::faucet::request_airdrop_transaction;
|
|||
use solana_faucet::faucet_mock::request_airdrop_transaction;
|
||||
use solana_sdk::{
|
||||
bpf_loader,
|
||||
clock::Slot,
|
||||
clock::{Epoch, Slot},
|
||||
commitment_config::CommitmentConfig,
|
||||
fee_calculator::FeeCalculator,
|
||||
hash::Hash,
|
||||
|
@ -106,6 +106,10 @@ pub enum CliCommand {
|
|||
timeout: Duration,
|
||||
commitment_config: CommitmentConfig,
|
||||
},
|
||||
ShowBlockProduction {
|
||||
epoch: Option<Epoch>,
|
||||
slot_limit: Option<u64>,
|
||||
},
|
||||
ShowGossip,
|
||||
ShowValidators {
|
||||
use_lamports_unit: bool,
|
||||
|
@ -336,6 +340,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, Box<dyn
|
|||
("get-slot", Some(matches)) => parse_get_slot(matches),
|
||||
("get-transaction-count", Some(matches)) => parse_get_transaction_count(matches),
|
||||
("ping", Some(matches)) => parse_cluster_ping(matches),
|
||||
("show-block-production", Some(matches)) => parse_show_block_production(matches),
|
||||
("show-gossip", Some(_matches)) => Ok(CliCommandInfo {
|
||||
command: CliCommand::ShowGossip,
|
||||
require_keypair: false,
|
||||
|
@ -1126,6 +1131,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
|
|||
timeout,
|
||||
commitment_config,
|
||||
),
|
||||
CliCommand::ShowBlockProduction { epoch, slot_limit } => {
|
||||
process_show_block_production(&rpc_client, *epoch, *slot_limit)
|
||||
}
|
||||
CliCommand::ShowGossip => process_show_gossip(&rpc_client),
|
||||
CliCommand::ShowValidators { use_lamports_unit } => {
|
||||
process_show_validators(&rpc_client, *use_lamports_unit)
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
|||
},
|
||||
display::println_name_value,
|
||||
};
|
||||
use clap::{value_t_or_exit, App, Arg, ArgMatches, SubCommand};
|
||||
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::*};
|
||||
|
@ -20,7 +20,7 @@ use solana_sdk::{
|
|||
system_transaction,
|
||||
};
|
||||
use std::{
|
||||
collections::VecDeque,
|
||||
collections::{HashMap, VecDeque},
|
||||
net::SocketAddr,
|
||||
thread::sleep,
|
||||
time::{Duration, Instant},
|
||||
|
@ -149,6 +149,22 @@ impl ClusterQuerySubCommands for App<'_, '_> {
|
|||
),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("show-block-production")
|
||||
.about("Show information about block production")
|
||||
.arg(
|
||||
Arg::with_name("epoch")
|
||||
.long("epoch")
|
||||
.takes_value(true)
|
||||
.help("Epoch to show block production for [default: current epoch]"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("slot_limit")
|
||||
.long("slot-limit")
|
||||
.takes_value(true)
|
||||
.help("Limit results to this many slots from the end of the epoch [default: full epoch]"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
SubCommand::with_name("show-gossip")
|
||||
.about("Show the current gossip network nodes"),
|
||||
|
@ -394,6 +410,138 @@ pub fn process_get_slot(
|
|||
Ok(slot.to_string())
|
||||
}
|
||||
|
||||
pub fn parse_show_block_production(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
|
||||
let epoch = value_t!(matches, "epoch", Epoch).ok();
|
||||
let slot_limit = value_t!(matches, "slot_limit", u64).ok();
|
||||
|
||||
Ok(CliCommandInfo {
|
||||
command: CliCommand::ShowBlockProduction { epoch, slot_limit },
|
||||
require_keypair: false,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process_show_block_production(
|
||||
rpc_client: &RpcClient,
|
||||
epoch: Option<Epoch>,
|
||||
slot_limit: Option<u64>,
|
||||
) -> ProcessResult {
|
||||
let epoch_schedule = rpc_client.get_epoch_schedule()?;
|
||||
let epoch_info = rpc_client.get_epoch_info_with_commitment(CommitmentConfig::max())?;
|
||||
|
||||
let epoch = epoch.unwrap_or(epoch_info.epoch);
|
||||
|
||||
if epoch > epoch_info.epoch {
|
||||
return Err(format!("Epoch {} is in the future", epoch).into());
|
||||
}
|
||||
|
||||
let end_slot = std::cmp::min(
|
||||
epoch_info.absolute_slot,
|
||||
epoch_schedule.get_last_slot_in_epoch(epoch),
|
||||
);
|
||||
let start_slot = {
|
||||
let start_slot = epoch_schedule.get_first_slot_in_epoch(epoch);
|
||||
std::cmp::max(
|
||||
end_slot.saturating_sub(slot_limit.unwrap_or(start_slot)),
|
||||
start_slot,
|
||||
)
|
||||
};
|
||||
|
||||
let progress_bar = new_spinner_progress_bar();
|
||||
progress_bar.set_message("Connecting...");
|
||||
progress_bar.set_message(&format!("Fetching leader schedule for epoch {}...", epoch));
|
||||
|
||||
let leader_schedule = rpc_client
|
||||
.get_leader_schedule_with_commitment(Some(start_slot), CommitmentConfig::max())?;
|
||||
|
||||
if leader_schedule.is_none() {
|
||||
return Err(format!("Unable to fetch leader schedule for slot {}", start_slot).into());
|
||||
}
|
||||
let leader_schedule = leader_schedule.unwrap();
|
||||
|
||||
progress_bar.set_message(&format!(
|
||||
"Fetching confirmed blocks between slots {} and {}...",
|
||||
start_slot, end_slot
|
||||
));
|
||||
let confirmed_blocks = rpc_client.get_confirmed_blocks(start_slot, Some(end_slot))?;
|
||||
|
||||
let total_slots = (end_slot - start_slot + 1) as usize;
|
||||
let total_blocks = confirmed_blocks.len();
|
||||
let total_slots_missed = total_slots - total_blocks;
|
||||
let mut leader_slot_count = HashMap::new();
|
||||
let mut leader_missed_slots = HashMap::new();
|
||||
|
||||
for slot_index in 0..total_slots {
|
||||
let leader = {
|
||||
let mut leader = None;
|
||||
for (pubkey, leader_slots) in leader_schedule.iter() {
|
||||
if leader_slots.contains(&slot_index) {
|
||||
leader = Some(pubkey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
leader.unwrap()
|
||||
};
|
||||
|
||||
let slot = start_slot + slot_index as u64;
|
||||
let remaining_slots = total_slots - slot_index;
|
||||
progress_bar.set_message(&format!(
|
||||
"Checking slot {} ({:.}% done, {} slots remaining)...",
|
||||
slot,
|
||||
100 * slot_index / total_slots,
|
||||
remaining_slots,
|
||||
));
|
||||
let slot_count = leader_slot_count.entry(leader).or_insert(0);
|
||||
*slot_count += 1;
|
||||
|
||||
let missed_slots = leader_missed_slots.entry(leader).or_insert(0);
|
||||
|
||||
if !confirmed_blocks.contains(&slot) {
|
||||
*missed_slots += 1;
|
||||
}
|
||||
}
|
||||
|
||||
progress_bar.finish_and_clear();
|
||||
println!(
|
||||
"\n{}",
|
||||
style(format!(
|
||||
" {:<44} {:>15} {:>15} {:>15} {:>23}",
|
||||
"Identity Pubkey",
|
||||
"Leader Slots",
|
||||
"Blocks Produced",
|
||||
"Missed Slots",
|
||||
"Missed Block Percentage",
|
||||
))
|
||||
.bold()
|
||||
);
|
||||
|
||||
for (leader, leader_slots) in leader_slot_count.iter() {
|
||||
let missed_slots = leader_missed_slots.get(leader).unwrap();
|
||||
let blocks_produced = leader_slots - missed_slots;
|
||||
println!(
|
||||
" {:<44} {:>15} {:>15} {:>15} {:>22.2}%",
|
||||
leader,
|
||||
leader_slots,
|
||||
blocks_produced,
|
||||
missed_slots,
|
||||
*missed_slots as f64 / *leader_slots as f64 * 100.
|
||||
);
|
||||
}
|
||||
|
||||
println!(
|
||||
"\n {:<44} {:>15} {:>15} {:>15} {:>22.2}%",
|
||||
format!("Epoch {} total:", epoch),
|
||||
total_slots,
|
||||
total_blocks,
|
||||
total_slots_missed,
|
||||
total_slots_missed as f64 / total_slots as f64 * 100.
|
||||
);
|
||||
println!(
|
||||
" (using data from {} slots: {} to {})",
|
||||
total_slots, start_slot, end_slot
|
||||
);
|
||||
Ok("".to_string())
|
||||
}
|
||||
|
||||
pub fn process_get_transaction_count(
|
||||
rpc_client: &RpcClient,
|
||||
commitment_config: &CommitmentConfig,
|
||||
|
|
|
@ -19,6 +19,12 @@ impl CommitmentConfig {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn max() -> Self {
|
||||
Self {
|
||||
commitment: CommitmentLevel::Max,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ok(&self) -> Option<Self> {
|
||||
if self == &Self::default() {
|
||||
None
|
||||
|
|
Loading…
Reference in New Issue