From 71ff2697804aa61ff0de412214f95b943a4e6fda Mon Sep 17 00:00:00 2001 From: Justin Starry Date: Fri, 25 Oct 2019 12:20:08 -0400 Subject: [PATCH] Add show-stake-history command to cli (#6541) --- cli/src/cli.rs | 35 ++++++++++++++++++----- cli/src/cluster_query.rs | 8 +++--- cli/src/stake.rs | 61 ++++++++++++++++++++++++++++++++++++++-- cli/src/vote.rs | 2 +- 4 files changed, 91 insertions(+), 15 deletions(-) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 88220993d..840d746b2 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -73,6 +73,9 @@ pub enum CliCommand { DeactivateStake(Pubkey), DelegateStake(Pubkey, Pubkey, bool), RedeemVoteCredits(Pubkey, Pubkey), + ShowStakeHistory { + use_lamports_unit: bool, + }, ShowStakeAccount { pubkey: Pubkey, use_lamports_unit: bool, @@ -252,6 +255,7 @@ pub fn parse_command(matches: &ArgMatches<'_>) -> Result parse_redeem_vote_credits(matches), ("show-stake-account", Some(matches)) => parse_show_stake_account(matches), + ("show-stake-history", Some(matches)) => parse_show_stake_history(matches), // Storage Commands ("create-archiver-storage-account", Some(matches)) => { parse_storage_create_archiver_account(matches) @@ -486,7 +490,7 @@ fn process_airdrop( ) -> ProcessResult { println!( "Requesting airdrop of {} from {}", - build_balance_message(lamports, use_lamports_unit), + build_balance_message(lamports, use_lamports_unit, true), drone_addr ); let previous_balance = match rpc_client.retry_get_balance(&config.keypair.pubkey(), 5)? { @@ -505,7 +509,11 @@ fn process_airdrop( .retry_get_balance(&config.keypair.pubkey(), 5)? .unwrap_or(previous_balance); - Ok(build_balance_message(current_balance, use_lamports_unit)) + Ok(build_balance_message( + current_balance, + use_lamports_unit, + true, + )) } fn process_balance( @@ -517,7 +525,7 @@ fn process_balance( let pubkey = pubkey.unwrap_or(config.keypair.pubkey()); let balance = rpc_client.retry_get_balance(&pubkey, 5)?; match balance { - Some(lamports) => Ok(build_balance_message(lamports, use_lamports_unit)), + Some(lamports) => Ok(build_balance_message(lamports, use_lamports_unit, true)), None => Err( CliError::RpcRequestError("Received result of an unexpected type".to_string()).into(), ), @@ -553,7 +561,7 @@ fn process_show_account( println_name_value("Public Key:", &account_pubkey.to_string()); println_name_value( "Balance:", - &build_balance_message(account.lamports, use_lamports_unit), + &build_balance_message(account.lamports, use_lamports_unit, true), ); println_name_value("Owner:", &account.owner.to_string()); println_name_value("Executable:", &account.executable.to_string()); @@ -877,6 +885,9 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { &stake_account_pubkey, *use_lamports_unit, ), + CliCommand::ShowStakeHistory { use_lamports_unit } => { + process_show_stake_history(&rpc_client, config, *use_lamports_unit) + } CliCommand::StakeAuthorize( stake_account_pubkey, new_authorized_pubkey, @@ -1151,15 +1162,25 @@ where } } -pub(crate) fn build_balance_message(lamports: u64, use_lamports_unit: bool) -> String { +pub(crate) fn build_balance_message( + lamports: u64, + use_lamports_unit: bool, + show_unit: bool, +) -> String { if use_lamports_unit { let ess = if lamports == 1 { "" } else { "s" }; - format!("{:?} lamport{}", lamports, ess) + let unit = if show_unit { + format!(" lamport{}", ess) + } else { + "".to_string() + }; + format!("{:?}{}", lamports, unit) } else { let sol = lamports_to_sol(lamports); let sol_str = format!("{:.8}", sol); let pretty_sol = sol_str.trim_end_matches('0').trim_end_matches('.'); - format!("{} SOL", pretty_sol) + let unit = if show_unit { " SOL" } else { "" }; + format!("{}{}", pretty_sol, unit) } } diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index 1c776dfaa..c3c4aad47 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -320,14 +320,14 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool) println_name_value( "Active Stake:", - &build_balance_message(total_active_stake as u64, use_lamports_unit), + &build_balance_message(total_active_stake as u64, use_lamports_unit, true), ); if total_deliquent_stake > 0. { println_name_value( "Current Stake:", &format!( "{} ({:0.2}%)", - &build_balance_message(total_current_stake as u64, use_lamports_unit), + &build_balance_message(total_current_stake as u64, use_lamports_unit, true), 100. * total_current_stake / total_active_stake ), ); @@ -335,7 +335,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool) "Delinquent Stake:", &format!( "{} ({:0.2}%)", - &build_balance_message(total_deliquent_stake as u64, use_lamports_unit), + &build_balance_message(total_deliquent_stake as u64, use_lamports_unit, true), 100. * total_deliquent_stake / total_active_stake ), ); @@ -385,7 +385,7 @@ pub fn process_show_validators(rpc_client: &RpcClient, use_lamports_unit: bool) if vote_account.activated_stake > 0 { format!( "{} ({:.2}%)", - build_balance_message(vote_account.activated_stake, use_lamports_unit), + build_balance_message(vote_account.activated_stake, use_lamports_unit, true), 100. * vote_account.activated_stake as f64 / total_active_stake ) } else { diff --git a/cli/src/stake.rs b/cli/src/stake.rs index 1007ad6d5..7506f11e5 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -8,9 +8,14 @@ use crate::{ input_validators::*, }; use clap::{App, Arg, ArgMatches, SubCommand}; +use console::style; use solana_client::rpc_client::RpcClient; use solana_sdk::{ - account_utils::State, pubkey::Pubkey, signature::KeypairUtil, system_instruction::SystemError, + account_utils::State, + pubkey::Pubkey, + signature::KeypairUtil, + system_instruction::SystemError, + sysvar::stake_history::{self, StakeHistory}, transaction::Transaction, }; use solana_stake_api::{ @@ -18,6 +23,7 @@ use solana_stake_api::{ stake_state::{Authorized, Lockup, StakeAuthorize, StakeState}, }; use solana_vote_api::vote_state::VoteState; +use std::ops::Deref; pub trait StakeSubCommands { fn stake_subcommands(self) -> Self; @@ -249,6 +255,16 @@ impl StakeSubCommands for App<'_, '_> { .help("Display balance in lamports instead of SOL") ) ) + .subcommand( + SubCommand::with_name("show-stake-history") + .about("Show the stake history") + .arg( + Arg::with_name("lamports") + .long("lamports") + .takes_value(false) + .help("Display balance in lamports instead of SOL") + ) + ) } } @@ -344,6 +360,14 @@ pub fn parse_show_stake_account(matches: &ArgMatches<'_>) -> Result) -> Result { + let use_lamports_unit = matches.is_present("lamports"); + Ok(CliCommandInfo { + command: CliCommand::ShowStakeHistory { use_lamports_unit }, + require_keypair: false, + }) +} + pub fn process_create_stake_account( rpc_client: &RpcClient, config: &CliConfig, @@ -527,12 +551,12 @@ pub fn process_show_stake_account( Ok(StakeState::Stake(authorized, lockup, stake)) => { println!( "total stake: {}", - build_balance_message(stake_account.lamports, use_lamports_unit) + build_balance_message(stake_account.lamports, use_lamports_unit, true) ); println!("credits observed: {}", stake.credits_observed); println!( "delegated stake: {}", - build_balance_message(stake.stake, use_lamports_unit) + build_balance_message(stake.stake, use_lamports_unit, true) ); if stake.voter_pubkey != Pubkey::default() { println!("delegated voter pubkey: {}", stake.voter_pubkey); @@ -567,6 +591,37 @@ pub fn process_show_stake_account( } } +pub fn process_show_stake_history( + rpc_client: &RpcClient, + _config: &CliConfig, + use_lamports_unit: bool, +) -> ProcessResult { + let stake_history_account = rpc_client.get_account(&stake_history::id())?; + let stake_history = StakeHistory::from_account(&stake_history_account).unwrap(); + + println!(); + println!( + "{}", + style(format!( + " {:<5} {:>15} {:>16} {:>18}", + "Epoch", "Effective Stake", "Activating Stake", "Deactivating Stake", + )) + .bold() + ); + + for (epoch, entry) in stake_history.deref() { + println!( + " {:>5} {:>15} {:>16} {:>18} {}", + epoch, + build_balance_message(entry.effective, use_lamports_unit, false), + build_balance_message(entry.activating, use_lamports_unit, false), + build_balance_message(entry.deactivating, use_lamports_unit, false), + if use_lamports_unit { "lamports" } else { "SOL" } + ); + } + Ok("".to_string()) +} + pub fn process_delegate_stake( rpc_client: &RpcClient, config: &CliConfig, diff --git a/cli/src/vote.rs b/cli/src/vote.rs index d1bf263a6..82a5230ca 100644 --- a/cli/src/vote.rs +++ b/cli/src/vote.rs @@ -334,7 +334,7 @@ pub fn process_show_vote_account( println!( "account balance: {}", - build_balance_message(vote_account.lamports, use_lamports_unit) + build_balance_message(vote_account.lamports, use_lamports_unit, true) ); println!("node id: {}", vote_state.node_pubkey); println!("authorized voter: {}", vote_state.authorized_voter);