Add --sort argument to `solana validators`
This commit is contained in:
parent
185bbf2db5
commit
b66faf7e80
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue