Add --sort argument to `solana validators`

This commit is contained in:
Michael Vines 2021-04-19 10:24:07 -07:00
parent 185bbf2db5
commit b66faf7e80
3 changed files with 143 additions and 30 deletions

View File

@ -303,14 +303,29 @@ pub struct CliValidatorsStakeByVersion {
pub delinquent_active_stake: u64, 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)] #[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct CliValidators { pub struct CliValidators {
pub total_active_stake: u64, pub total_active_stake: u64,
pub total_current_stake: u64, pub total_current_stake: u64,
pub total_delinquent_stake: u64, pub total_delinquent_stake: u64,
pub current_validators: Vec<CliValidator>, pub validators: Vec<CliValidator>,
pub delinquent_validators: Vec<CliValidator>, #[serde(skip_serializing)]
pub validators_sort_order: CliValidatorsSortOrder,
#[serde(skip_serializing)]
pub validators_reverse_sort: bool,
pub stake_by_version: BTreeMap<String, CliValidatorsStakeByVersion>, pub stake_by_version: BTreeMap<String, CliValidatorsStakeByVersion>,
#[serde(skip_serializing)] #[serde(skip_serializing)]
pub use_lamports_unit: bool, pub use_lamports_unit: bool,
@ -326,7 +341,6 @@ impl fmt::Display for CliValidators {
validator: &CliValidator, validator: &CliValidator,
total_active_stake: u64, total_active_stake: u64,
use_lamports_unit: bool, use_lamports_unit: bool,
delinquent: bool,
) -> fmt::Result { ) -> fmt::Result {
fn non_zero_or_dash(v: u64) -> String { fn non_zero_or_dash(v: u64) -> String {
if v == 0 { if v == 0 {
@ -339,7 +353,7 @@ impl fmt::Display for CliValidators {
writeln!( writeln!(
f, f,
"{} {:<44} {:<44} {:>3}% {:>8} {:>10} {:>13} {:>7} {}", "{} {:<44} {:<44} {:>3}% {:>8} {:>10} {:>13} {:>7} {}",
if delinquent { if validator.delinquent {
WARNING.to_string() WARNING.to_string()
} else { } else {
" ".to_string() " ".to_string()
@ -378,22 +392,45 @@ impl fmt::Display for CliValidators {
)) ))
.bold() .bold()
)?; )?;
for validator in &self.current_validators {
write_vote_account( let mut sorted_validators = self.validators.clone();
f, match self.validators_sort_order {
validator, CliValidatorsSortOrder::Delinquent => {
self.total_active_stake, sorted_validators.sort_by_key(|a| a.delinquent);
self.use_lamports_unit, }
false, 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( write_vote_account(
f, f,
validator, validator,
self.total_active_stake, self.total_active_stake,
self.use_lamports_unit, 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")] #[serde(rename_all = "camelCase")]
pub struct CliValidator { pub struct CliValidator {
pub identity_pubkey: String, pub identity_pubkey: String,
@ -465,6 +502,7 @@ pub struct CliValidator {
pub epoch_credits: u64, // credits earned in the current epoch pub epoch_credits: u64, // credits earned in the current epoch
pub activated_stake: u64, pub activated_stake: u64,
pub version: String, pub version: String,
pub delinquent: bool,
} }
impl CliValidator { impl CliValidator {
@ -473,6 +511,25 @@ impl CliValidator {
current_epoch: Epoch, current_epoch: Epoch,
version: String, version: String,
address_labels: &HashMap<String, String>, address_labels: &HashMap<String, String>,
) -> 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<String, String>,
) -> Self {
Self::_new(vote_account, current_epoch, version, address_labels, true)
}
fn _new(
vote_account: &RpcVoteAccountInfo,
current_epoch: Epoch,
version: String,
address_labels: &HashMap<String, String>,
delinquent: bool,
) -> Self { ) -> Self {
let (credits, epoch_credits) = vote_account let (credits, epoch_credits) = vote_account
.epoch_credits .epoch_credits
@ -485,7 +542,6 @@ impl CliValidator {
} }
}) })
.unwrap_or((0, 0)); .unwrap_or((0, 0));
Self { Self {
identity_pubkey: format_labeled_address(&vote_account.node_pubkey, address_labels), identity_pubkey: format_labeled_address(&vote_account.node_pubkey, address_labels),
vote_account_pubkey: format_labeled_address(&vote_account.vote_pubkey, address_labels), vote_account_pubkey: format_labeled_address(&vote_account.vote_pubkey, address_labels),
@ -496,6 +552,7 @@ impl CliValidator {
epoch_credits, epoch_credits,
activated_stake: vote_account.activated_stake, activated_stake: vote_account.activated_stake,
version, version,
delinquent,
} }
} }
} }

View File

@ -20,7 +20,8 @@ use solana_clap_utils::{
use solana_cli_output::{ use solana_cli_output::{
display::{build_balance_message, println_name_value}, display::{build_balance_message, println_name_value},
return_signers_with_config, CliAccount, CliSignature, CliSignatureVerificationStatus, return_signers_with_config, CliAccount, CliSignature, CliSignatureVerificationStatus,
CliTransaction, CliTransactionConfirmation, OutputFormat, ReturnSignersConfig, CliTransaction, CliTransactionConfirmation, CliValidatorsSortOrder, OutputFormat,
ReturnSignersConfig,
}; };
use solana_client::{ use solana_client::{
blockhash_query::BlockhashQuery, blockhash_query::BlockhashQuery,
@ -130,6 +131,8 @@ pub enum CliCommand {
}, },
ShowValidators { ShowValidators {
use_lamports_unit: bool, use_lamports_unit: bool,
sort_order: CliValidatorsSortOrder,
reverse_sort: bool,
}, },
Supply { Supply {
print_accounts: bool, print_accounts: bool,
@ -1378,9 +1381,17 @@ pub fn process_command(config: &CliConfig) -> ProcessResult {
CliCommand::WaitForMaxStake { max_stake_percent } => { CliCommand::WaitForMaxStake { max_stake_percent } => {
process_wait_for_max_stake(&rpc_client, config, *max_stake_percent) process_wait_for_max_stake(&rpc_client, config, *max_stake_percent)
} }
CliCommand::ShowValidators { use_lamports_unit } => { CliCommand::ShowValidators {
process_show_validators(&rpc_client, config, *use_lamports_unit) use_lamports_unit,
} sort_order,
reverse_sort,
} => process_show_validators(
&rpc_client,
config,
*use_lamports_unit,
*sort_order,
*reverse_sort,
),
CliCommand::Supply { print_accounts } => { CliCommand::Supply { print_accounts } => {
process_supply(&rpc_client, config, *print_accounts) process_supply(&rpc_client, config, *print_accounts)
} }

View File

@ -349,6 +349,30 @@ impl ClusterQuerySubCommands for App<'_, '_> {
.long("lamports") .long("lamports")
.takes_value(false) .takes_value(false)
.help("Display balance in lamports instead of SOL"), .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( .subcommand(
@ -582,9 +606,26 @@ pub fn parse_show_stakes(
pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> { pub fn parse_show_validators(matches: &ArgMatches<'_>) -> Result<CliCommandInfo, CliError> {
let use_lamports_unit = matches.is_present("lamports"); 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 { Ok(CliCommandInfo {
command: CliCommand::ShowValidators { use_lamports_unit }, command: CliCommand::ShowValidators {
use_lamports_unit,
sort_order,
reverse_sort,
},
signers: vec![], signers: vec![],
}) })
} }
@ -1730,6 +1771,8 @@ pub fn process_show_validators(
rpc_client: &RpcClient, rpc_client: &RpcClient,
config: &CliConfig, config: &CliConfig,
use_lamports_unit: bool, use_lamports_unit: bool,
validators_sort_order: CliValidatorsSortOrder,
validators_reverse_sort: bool,
) -> ProcessResult { ) -> ProcessResult {
let epoch_info = rpc_client.get_epoch_info()?; let epoch_info = rpc_client.get_epoch_info()?;
let vote_accounts = rpc_client.get_vote_accounts()?; let vote_accounts = rpc_client.get_vote_accounts()?;
@ -1759,9 +1802,8 @@ pub fn process_show_validators(
.sum(); .sum();
let total_current_stake = total_active_stake - total_delinquent_stake; let total_current_stake = total_active_stake - total_delinquent_stake;
let mut current = vote_accounts.current; let current_validators: Vec<CliValidator> = vote_accounts
current.sort_by(|a, b| b.activated_stake.cmp(&a.activated_stake)); .current
let current_validators: Vec<CliValidator> = current
.iter() .iter()
.map(|vote_account| { .map(|vote_account| {
CliValidator::new( CliValidator::new(
@ -1775,12 +1817,11 @@ pub fn process_show_validators(
) )
}) })
.collect(); .collect();
let mut delinquent = vote_accounts.delinquent; let delinquent_validators: Vec<CliValidator> = vote_accounts
delinquent.sort_by(|a, b| b.activated_stake.cmp(&a.activated_stake)); .delinquent
let delinquent_validators: Vec<CliValidator> = delinquent
.iter() .iter()
.map(|vote_account| { .map(|vote_account| {
CliValidator::new( CliValidator::new_delinquent(
vote_account, vote_account,
epoch_info.epoch, epoch_info.epoch,
node_version node_version
@ -1812,8 +1853,12 @@ pub fn process_show_validators(
total_active_stake, total_active_stake,
total_current_stake, total_current_stake,
total_delinquent_stake, total_delinquent_stake,
current_validators, validators: current_validators
delinquent_validators, .into_iter()
.chain(delinquent_validators.into_iter())
.collect(),
validators_sort_order,
validators_reverse_sort,
stake_by_version, stake_by_version,
use_lamports_unit, use_lamports_unit,
}; };