From b66faf7e805179e010add572beb377e91b6dd384 Mon Sep 17 00:00:00 2001 From: Michael Vines Date: Mon, 19 Apr 2021 10:24:07 -0700 Subject: [PATCH] Add --sort argument to `solana validators` --- cli-output/src/cli_output.rs | 89 +++++++++++++++++++++++++++++------- cli/src/cli.rs | 19 ++++++-- cli/src/cluster_query.rs | 65 ++++++++++++++++++++++---- 3 files changed, 143 insertions(+), 30 deletions(-) diff --git a/cli-output/src/cli_output.rs b/cli-output/src/cli_output.rs index 235a8dde0d..c6c2e6f9bd 100644 --- a/cli-output/src/cli_output.rs +++ b/cli-output/src/cli_output.rs @@ -303,14 +303,29 @@ pub struct CliValidatorsStakeByVersion { pub delinquent_active_stake: u64, } +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)] +pub enum CliValidatorsSortOrder { + Delinquent, + Commission, + EpochCredits, + Identity, + LastVote, + Root, + Stake, + VoteAccount, +} + #[derive(Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct CliValidators { pub total_active_stake: u64, pub total_current_stake: u64, pub total_delinquent_stake: u64, - pub current_validators: Vec, - pub delinquent_validators: Vec, + pub validators: Vec, + #[serde(skip_serializing)] + pub validators_sort_order: CliValidatorsSortOrder, + #[serde(skip_serializing)] + pub validators_reverse_sort: bool, pub stake_by_version: BTreeMap, #[serde(skip_serializing)] pub use_lamports_unit: bool, @@ -326,7 +341,6 @@ impl fmt::Display for CliValidators { validator: &CliValidator, total_active_stake: u64, use_lamports_unit: bool, - delinquent: bool, ) -> fmt::Result { fn non_zero_or_dash(v: u64) -> String { if v == 0 { @@ -339,7 +353,7 @@ impl fmt::Display for CliValidators { writeln!( f, "{} {:<44} {:<44} {:>3}% {:>8} {:>10} {:>13} {:>7} {}", - if delinquent { + if validator.delinquent { WARNING.to_string() } else { " ".to_string() @@ -378,22 +392,45 @@ impl fmt::Display for CliValidators { )) .bold() )?; - for validator in &self.current_validators { - write_vote_account( - f, - validator, - self.total_active_stake, - self.use_lamports_unit, - false, - )?; + + let mut sorted_validators = self.validators.clone(); + match self.validators_sort_order { + CliValidatorsSortOrder::Delinquent => { + sorted_validators.sort_by_key(|a| a.delinquent); + } + CliValidatorsSortOrder::Commission => { + sorted_validators.sort_by_key(|a| a.commission); + } + CliValidatorsSortOrder::EpochCredits => { + sorted_validators.sort_by_key(|a| a.epoch_credits); + } + CliValidatorsSortOrder::Identity => { + sorted_validators.sort_by(|a, b| a.identity_pubkey.cmp(&b.identity_pubkey)); + } + CliValidatorsSortOrder::LastVote => { + sorted_validators.sort_by_key(|a| a.last_vote); + } + CliValidatorsSortOrder::Root => { + sorted_validators.sort_by_key(|a| a.root_slot); + } + CliValidatorsSortOrder::VoteAccount => { + sorted_validators.sort_by(|a, b| a.vote_account_pubkey.cmp(&b.vote_account_pubkey)); + } + CliValidatorsSortOrder::Stake => { + sorted_validators.sort_by_key(|a| a.activated_stake); + } } - for validator in &self.delinquent_validators { + + if self.validators_reverse_sort { + sorted_validators.reverse(); + } + + for validator in &sorted_validators { write_vote_account( f, validator, self.total_active_stake, self.use_lamports_unit, - true, )?; } @@ -453,7 +490,7 @@ impl fmt::Display for CliValidators { } } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] pub struct CliValidator { pub identity_pubkey: String, @@ -465,6 +502,7 @@ pub struct CliValidator { pub epoch_credits: u64, // credits earned in the current epoch pub activated_stake: u64, pub version: String, + pub delinquent: bool, } impl CliValidator { @@ -473,6 +511,25 @@ impl CliValidator { current_epoch: Epoch, version: String, address_labels: &HashMap, + ) -> Self { + Self::_new(vote_account, current_epoch, version, address_labels, false) + } + + pub fn new_delinquent( + vote_account: &RpcVoteAccountInfo, + current_epoch: Epoch, + version: String, + address_labels: &HashMap, + ) -> Self { + Self::_new(vote_account, current_epoch, version, address_labels, true) + } + + fn _new( + vote_account: &RpcVoteAccountInfo, + current_epoch: Epoch, + version: String, + address_labels: &HashMap, + delinquent: bool, ) -> Self { let (credits, epoch_credits) = vote_account .epoch_credits @@ -485,7 +542,6 @@ impl CliValidator { } }) .unwrap_or((0, 0)); - Self { identity_pubkey: format_labeled_address(&vote_account.node_pubkey, address_labels), vote_account_pubkey: format_labeled_address(&vote_account.vote_pubkey, address_labels), @@ -496,6 +552,7 @@ impl CliValidator { epoch_credits, activated_stake: vote_account.activated_stake, version, + delinquent, } } } diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 93dfc4fd6a..7a4cc41515 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -20,7 +20,8 @@ use solana_clap_utils::{ use solana_cli_output::{ display::{build_balance_message, println_name_value}, return_signers_with_config, CliAccount, CliSignature, CliSignatureVerificationStatus, - CliTransaction, CliTransactionConfirmation, OutputFormat, ReturnSignersConfig, + CliTransaction, CliTransactionConfirmation, CliValidatorsSortOrder, OutputFormat, + ReturnSignersConfig, }; use solana_client::{ blockhash_query::BlockhashQuery, @@ -130,6 +131,8 @@ pub enum CliCommand { }, ShowValidators { use_lamports_unit: bool, + sort_order: CliValidatorsSortOrder, + reverse_sort: bool, }, Supply { print_accounts: bool, @@ -1378,9 +1381,17 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { CliCommand::WaitForMaxStake { max_stake_percent } => { process_wait_for_max_stake(&rpc_client, config, *max_stake_percent) } - CliCommand::ShowValidators { use_lamports_unit } => { - process_show_validators(&rpc_client, config, *use_lamports_unit) - } + CliCommand::ShowValidators { + use_lamports_unit, + sort_order, + reverse_sort, + } => process_show_validators( + &rpc_client, + config, + *use_lamports_unit, + *sort_order, + *reverse_sort, + ), CliCommand::Supply { print_accounts } => { process_supply(&rpc_client, config, *print_accounts) } diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index 4892e22e14..e108485cb6 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -349,6 +349,30 @@ impl ClusterQuerySubCommands for App<'_, '_> { .long("lamports") .takes_value(false) .help("Display balance in lamports instead of SOL"), + ) + .arg( + Arg::with_name("reverse") + .long("reverse") + .short("r") + .takes_value(false) + .help("Reverse order while sorting"), + ) + .arg( + Arg::with_name("sort") + .long("sort") + .takes_value(true) + .possible_values(&[ + "delinquent", + "commission", + "credits", + "identity", + "last-vote", + "root", + "stake", + "vote-account", + ]) + .default_value("stake") + .help("Sort order (does not affect JSON output)"), ), ) .subcommand( @@ -582,9 +606,26 @@ pub fn parse_show_stakes( pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result { let use_lamports_unit = matches.is_present("lamports"); + let reverse_sort = matches.is_present("reverse"); + + let sort_order = match value_t_or_exit!(matches, "sort", String).as_str() { + "delinquent" => CliValidatorsSortOrder::Delinquent, + "commission" => CliValidatorsSortOrder::Commission, + "credits" => CliValidatorsSortOrder::EpochCredits, + "identity" => CliValidatorsSortOrder::Identity, + "last-vote" => CliValidatorsSortOrder::LastVote, + "root" => CliValidatorsSortOrder::Root, + "stake" => CliValidatorsSortOrder::Stake, + "vote-account" => CliValidatorsSortOrder::VoteAccount, + _ => unreachable!(), + }; Ok(CliCommandInfo { - command: CliCommand::ShowValidators { use_lamports_unit }, + command: CliCommand::ShowValidators { + use_lamports_unit, + sort_order, + reverse_sort, + }, signers: vec![], }) } @@ -1730,6 +1771,8 @@ pub fn process_show_validators( rpc_client: &RpcClient, config: &CliConfig, use_lamports_unit: bool, + validators_sort_order: CliValidatorsSortOrder, + validators_reverse_sort: bool, ) -> ProcessResult { let epoch_info = rpc_client.get_epoch_info()?; let vote_accounts = rpc_client.get_vote_accounts()?; @@ -1759,9 +1802,8 @@ pub fn process_show_validators( .sum(); let total_current_stake = total_active_stake - total_delinquent_stake; - let mut current = vote_accounts.current; - current.sort_by(|a, b| b.activated_stake.cmp(&a.activated_stake)); - let current_validators: Vec = current + let current_validators: Vec = vote_accounts + .current .iter() .map(|vote_account| { CliValidator::new( @@ -1775,12 +1817,11 @@ pub fn process_show_validators( ) }) .collect(); - let mut delinquent = vote_accounts.delinquent; - delinquent.sort_by(|a, b| b.activated_stake.cmp(&a.activated_stake)); - let delinquent_validators: Vec = delinquent + let delinquent_validators: Vec = vote_accounts + .delinquent .iter() .map(|vote_account| { - CliValidator::new( + CliValidator::new_delinquent( vote_account, epoch_info.epoch, node_version @@ -1812,8 +1853,12 @@ pub fn process_show_validators( total_active_stake, total_current_stake, total_delinquent_stake, - current_validators, - delinquent_validators, + validators: current_validators + .into_iter() + .chain(delinquent_validators.into_iter()) + .collect(), + validators_sort_order, + validators_reverse_sort, stake_by_version, use_lamports_unit, };