From 97f6e8732207db0df7ab9c62c4fb44554fa3e693 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 28 Dec 2020 21:33:20 +0000 Subject: [PATCH] CLI: Support retrieving past leader schedules (bp #14304) (#14311) * clap-utils: Add epoch validator (cherry picked from commit a709850ee4ae56e2acf11457ede7ccae0e18abe0) * CLI: Support displaying past leader schedules (cherry picked from commit bd761e2a5215a72c2fd0f3acb34e53d3a29736fd) Co-authored-by: Trent Nelson --- clap-utils/src/input_validators.rs | 9 ++++++++- cli/src/cli.rs | 11 +++++------ cli/src/cluster_query.rs | 30 +++++++++++++++++++++++++++--- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/clap-utils/src/input_validators.rs b/clap-utils/src/input_validators.rs index fc98af446a..c3355ef038 100644 --- a/clap-utils/src/input_validators.rs +++ b/clap-utils/src/input_validators.rs @@ -1,7 +1,7 @@ use crate::keypair::{parse_keypair_path, KeypairUrl, ASK_KEYWORD}; use chrono::DateTime; use solana_sdk::{ - clock::Slot, + clock::{Epoch, Slot}, hash::Hash, pubkey::Pubkey, signature::{read_keypair_file, Signature}, @@ -148,6 +148,13 @@ where } } +pub fn is_epoch(epoch: T) -> Result<(), String> +where + T: AsRef + Display, +{ + is_parsable_generic::(epoch) +} + pub fn is_slot(slot: T) -> Result<(), String> where T: AsRef + Display, diff --git a/cli/src/cli.rs b/cli/src/cli.rs index a47c496c83..aaab1d2ecc 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -118,7 +118,9 @@ pub enum CliCommand { LargestAccounts { filter: Option, }, - LeaderSchedule, + LeaderSchedule { + epoch: Option, + }, LiveSlots, Logs { filter: RpcTransactionLogsFilter, @@ -582,10 +584,7 @@ pub fn parse_command( ("supply", Some(matches)) => parse_supply(matches), ("total-supply", Some(matches)) => parse_total_supply(matches), ("transaction-count", Some(matches)) => parse_get_transaction_count(matches), - ("leader-schedule", Some(_matches)) => Ok(CliCommandInfo { - command: CliCommand::LeaderSchedule, - signers: vec![], - }), + ("leader-schedule", Some(matches)) => parse_leader_schedule(matches), ("ping", Some(matches)) => parse_cluster_ping(matches, default_signer, wallet_manager), ("live-slots", Some(_matches)) => Ok(CliCommandInfo { command: CliCommand::LiveSlots, @@ -1562,7 +1561,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { CliCommand::Inflation(inflation_subcommand) => { process_inflation_subcommand(&rpc_client, config, inflation_subcommand) } - CliCommand::LeaderSchedule => process_leader_schedule(&rpc_client), + CliCommand::LeaderSchedule { epoch } => process_leader_schedule(&rpc_client, *epoch), CliCommand::LiveSlots => process_live_slots(&config), CliCommand::Logs { filter } => process_logs(&config, filter), CliCommand::Ping { diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index 226d132a5b..3ac5c8de1f 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -132,7 +132,17 @@ impl ClusterQuerySubCommands for App<'_, '_> { .help("Slot number of the block to query") ) ) - .subcommand(SubCommand::with_name("leader-schedule").about("Display leader schedule")) + .subcommand(SubCommand::with_name("leader-schedule") + .about("Display leader schedule") + .arg( + Arg::with_name("epoch") + .long("epoch") + .takes_value(true) + .value_name("EPOCH") + .validator(is_epoch) + .help("Epoch to show leader schedule for. (default: current)") + ) + ) .subcommand( SubCommand::with_name("epoch-info") .about("Get information about the current epoch") @@ -713,9 +723,23 @@ pub fn process_first_available_block(rpc_client: &RpcClient) -> ProcessResult { Ok(format!("{}", first_available_block)) } -pub fn process_leader_schedule(rpc_client: &RpcClient) -> ProcessResult { +pub fn parse_leader_schedule(matches: &ArgMatches<'_>) -> Result { + let epoch = value_of(matches, "epoch"); + Ok(CliCommandInfo { + command: CliCommand::LeaderSchedule { epoch }, + signers: vec![], + }) +} + +pub fn process_leader_schedule(rpc_client: &RpcClient, epoch: Option) -> ProcessResult { let epoch_info = rpc_client.get_epoch_info()?; - let first_slot_in_epoch = epoch_info.absolute_slot - epoch_info.slot_index; + let epoch = epoch.unwrap_or(epoch_info.epoch); + if epoch > epoch_info.epoch { + return Err(format!("Epoch {} is in the future", epoch).into()); + } + + let epoch_schedule = rpc_client.get_epoch_schedule()?; + let first_slot_in_epoch = epoch_schedule.get_first_slot_in_epoch(epoch); let leader_schedule = rpc_client.get_leader_schedule(Some(first_slot_in_epoch))?; if leader_schedule.is_none() {