From dc2aadd258195c80f31170edbf8164955daf649b Mon Sep 17 00:00:00 2001 From: Stephen Akridge Date: Sun, 6 Oct 2024 10:22:02 +0200 Subject: [PATCH 1/2] refactor cli-output large functions --- cli-output/src/cli_output.rs | 153 ++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 73 deletions(-) diff --git a/cli-output/src/cli_output.rs b/cli-output/src/cli_output.rs index 1474c758fd8c8e..9f0f6542f1e1a4 100644 --- a/cli-output/src/cli_output.rs +++ b/cli-output/src/cli_output.rs @@ -1311,6 +1311,84 @@ impl VerboseDisplay for CliStakeState { } } +fn show_inactive_stake( + me: &CliStakeState, + f: &mut fmt::Formatter, + delegated_stake: u64, +) -> fmt::Result { + if let Some(deactivation_epoch) = me.deactivation_epoch { + if me.current_epoch > deactivation_epoch { + let deactivating_stake = me.deactivating_stake.or(me.active_stake); + if let Some(deactivating_stake) = deactivating_stake { + writeln!( + f, + "Inactive Stake: {}", + build_balance_message( + delegated_stake - deactivating_stake, + me.use_lamports_unit, + true + ), + )?; + writeln!( + f, + "Deactivating Stake: {}", + build_balance_message(deactivating_stake, me.use_lamports_unit, true), + )?; + } + } + writeln!( + f, + "Stake deactivates starting from epoch: {deactivation_epoch}" + )?; + } + if let Some(delegated_vote_account_address) = &me.delegated_vote_account_address { + writeln!( + f, + "Delegated Vote Account Address: {delegated_vote_account_address}" + )?; + } + Ok(()) +} + +fn show_active_stake( + me: &CliStakeState, + f: &mut fmt::Formatter, + delegated_stake: u64, +) -> fmt::Result { + if me + .deactivation_epoch + .map(|d| me.current_epoch <= d) + .unwrap_or(true) + { + let active_stake = me.active_stake.unwrap_or(0); + writeln!( + f, + "Active Stake: {}", + build_balance_message(active_stake, me.use_lamports_unit, true), + )?; + let activating_stake = me.activating_stake.or_else(|| { + if me.active_stake.is_none() { + Some(delegated_stake) + } else { + None + } + }); + if let Some(activating_stake) = activating_stake { + writeln!( + f, + "Activating Stake: {}", + build_balance_message(activating_stake, me.use_lamports_unit, true), + )?; + writeln!( + f, + "Stake activates starting from epoch: {}", + me.activation_epoch.unwrap() + )?; + } + } + Ok(()) +} + impl fmt::Display for CliStakeState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn show_authorized(f: &mut fmt::Formatter, authorized: &CliAuthorized) -> fmt::Result { @@ -1374,79 +1452,8 @@ impl fmt::Display for CliStakeState { "Delegated Stake: {}", build_balance_message(delegated_stake, self.use_lamports_unit, true) )?; - if self - .deactivation_epoch - .map(|d| self.current_epoch <= d) - .unwrap_or(true) - { - let active_stake = self.active_stake.unwrap_or(0); - writeln!( - f, - "Active Stake: {}", - build_balance_message(active_stake, self.use_lamports_unit, true), - )?; - let activating_stake = self.activating_stake.or_else(|| { - if self.active_stake.is_none() { - Some(delegated_stake) - } else { - None - } - }); - if let Some(activating_stake) = activating_stake { - writeln!( - f, - "Activating Stake: {}", - build_balance_message( - activating_stake, - self.use_lamports_unit, - true - ), - )?; - writeln!( - f, - "Stake activates starting from epoch: {}", - self.activation_epoch.unwrap() - )?; - } - } - - if let Some(deactivation_epoch) = self.deactivation_epoch { - if self.current_epoch > deactivation_epoch { - let deactivating_stake = self.deactivating_stake.or(self.active_stake); - if let Some(deactivating_stake) = deactivating_stake { - writeln!( - f, - "Inactive Stake: {}", - build_balance_message( - delegated_stake - deactivating_stake, - self.use_lamports_unit, - true - ), - )?; - writeln!( - f, - "Deactivating Stake: {}", - build_balance_message( - deactivating_stake, - self.use_lamports_unit, - true - ), - )?; - } - } - writeln!( - f, - "Stake deactivates starting from epoch: {deactivation_epoch}" - )?; - } - if let Some(delegated_vote_account_address) = - &self.delegated_vote_account_address - { - writeln!( - f, - "Delegated Vote Account Address: {delegated_vote_account_address}" - )?; - } + show_active_stake(self, f, delegated_stake)?; + show_inactive_stake(self, f, delegated_stake)?; } else { writeln!(f, "Stake account is undelegated")?; } From 6faf55ad9f9b5f5c32970f13ec22f2fc0e1d82e9 Mon Sep 17 00:00:00 2001 From: Stephen Akridge Date: Sun, 6 Oct 2024 10:28:34 +0200 Subject: [PATCH 2/2] solana CLI: Add starting reward epoch option --- cli/src/cli.rs | 6 ++++++ cli/src/stake.rs | 32 ++++++++++++++++++++++++++++---- cli/src/vote.rs | 18 +++++++++++++++++- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/cli/src/cli.rs b/cli/src/cli.rs index 643782e418b161..e846539f9e4216 100644 --- a/cli/src/cli.rs +++ b/cli/src/cli.rs @@ -269,6 +269,7 @@ pub enum CliCommand { use_lamports_unit: bool, with_rewards: Option, use_csv: bool, + starting_epoch: Option, }, StakeAuthorize { stake_account_pubkey: Pubkey, @@ -344,6 +345,7 @@ pub enum CliCommand { use_lamports_unit: bool, use_csv: bool, with_rewards: Option, + starting_epoch: Option, }, WithdrawFromVoteAccount { vote_account_pubkey: Pubkey, @@ -1325,6 +1327,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { use_lamports_unit, with_rewards, use_csv, + starting_epoch, } => process_show_stake_account( &rpc_client, config, @@ -1332,6 +1335,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { *use_lamports_unit, *with_rewards, *use_csv, + *starting_epoch, ), CliCommand::ShowStakeHistory { use_lamports_unit, @@ -1494,6 +1498,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { use_lamports_unit, use_csv, with_rewards, + starting_epoch, } => process_show_vote_account( &rpc_client, config, @@ -1501,6 +1506,7 @@ pub fn process_command(config: &CliConfig) -> ProcessResult { *use_lamports_unit, *use_csv, *with_rewards, + *starting_epoch, ), CliCommand::WithdrawFromVoteAccount { vote_account_pubkey, diff --git a/cli/src/stake.rs b/cli/src/stake.rs index a5434cd312d598..9fefb818aee3a9 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -741,6 +741,14 @@ impl StakeSubCommands for App<'_, '_> { .takes_value(false) .help("Format stake rewards data in csv"), ) + .arg( + Arg::with_name("starting_epoch") + .long("starting-epoch") + .takes_value(true) + .value_name("NUM") + .requires("with_rewards") + .help("Start displaying from epoch NUM"), + ) .arg( Arg::with_name("num_rewards_epochs") .long("num-rewards-epochs") @@ -1329,12 +1337,14 @@ pub fn parse_show_stake_account( } else { None }; + let starting_epoch = value_of(matches, "starting_epoch"); Ok(CliCommandInfo::without_signers( CliCommand::ShowStakeAccount { pubkey: stake_account_pubkey, use_lamports_unit, with_rewards, use_csv, + starting_epoch, }, )) } @@ -2541,10 +2551,18 @@ pub(crate) fn fetch_epoch_rewards( rpc_client: &RpcClient, address: &Pubkey, mut num_epochs: usize, + starting_epoch: Option, ) -> Result, Box> { let mut all_epoch_rewards = vec![]; let epoch_schedule = rpc_client.get_epoch_schedule()?; - let mut rewards_epoch = rpc_client.get_epoch_info()?.epoch; + let mut rewards_epoch = if let Some(epoch) = starting_epoch { + epoch + } else { + rpc_client + .get_epoch_info()? + .epoch + .saturating_sub(num_epochs as u64) + }; let mut process_reward = |reward: &Option| -> Result<(), Box> { @@ -2559,14 +2577,14 @@ pub(crate) fn fetch_epoch_rewards( Ok(()) }; - while num_epochs > 0 && rewards_epoch > 0 { - rewards_epoch = rewards_epoch.saturating_sub(1); + while num_epochs > 0 { if let Ok(rewards) = rpc_client.get_inflation_reward(&[*address], Some(rewards_epoch)) { process_reward(&rewards[0])?; } else { eprintln!("Rewards not available for epoch {rewards_epoch}"); } num_epochs = num_epochs.saturating_sub(1); + rewards_epoch = rewards_epoch.saturating_add(1); } Ok(all_epoch_rewards) @@ -2579,6 +2597,7 @@ pub fn process_show_stake_account( use_lamports_unit: bool, with_rewards: Option, use_csv: bool, + starting_epoch: Option, ) -> ProcessResult { let stake_account = rpc_client.get_account(stake_account_address)?; if stake_account.owner != stake::program::id() { @@ -2614,7 +2633,12 @@ pub fn process_show_stake_account( if state.stake_type == CliStakeType::Stake && state.activation_epoch.is_some() { let epoch_rewards = with_rewards.and_then(|num_epochs| { - match fetch_epoch_rewards(rpc_client, stake_account_address, num_epochs) { + match fetch_epoch_rewards( + rpc_client, + stake_account_address, + num_epochs, + starting_epoch, + ) { Ok(rewards) => Some(rewards), Err(error) => { eprintln!("Failed to fetch epoch rewards: {error:?}"); diff --git a/cli/src/vote.rs b/cli/src/vote.rs index 66b925d9b88418..ab9a4897342b24 100644 --- a/cli/src/vote.rs +++ b/cli/src/vote.rs @@ -350,6 +350,14 @@ impl VoteSubCommands for App<'_, '_> { .takes_value(false) .help("Format rewards in a CSV table"), ) + .arg( + Arg::with_name("starting_epoch") + .long("starting-epoch") + .takes_value(true) + .value_name("NUM") + .requires("with_rewards") + .help("Start displaying from epoch NUM"), + ) .arg( Arg::with_name("num_rewards_epochs") .long("num-rewards-epochs") @@ -675,12 +683,14 @@ pub fn parse_vote_get_account_command( } else { None }; + let starting_epoch = value_of(matches, "starting_epoch"); Ok(CliCommandInfo::without_signers( CliCommand::ShowVoteAccount { pubkey: vote_account_pubkey, use_lamports_unit, use_csv, with_rewards, + starting_epoch, }, )) } @@ -1261,6 +1271,7 @@ pub fn process_show_vote_account( use_lamports_unit: bool, use_csv: bool, with_rewards: Option, + starting_epoch: Option, ) -> ProcessResult { let (vote_account, vote_state) = get_vote_account(rpc_client, vote_account_address, config.commitment)?; @@ -1288,7 +1299,12 @@ pub fn process_show_vote_account( let epoch_rewards = with_rewards.and_then(|num_epochs| { - match crate::stake::fetch_epoch_rewards(rpc_client, vote_account_address, num_epochs) { + match crate::stake::fetch_epoch_rewards( + rpc_client, + vote_account_address, + num_epochs, + starting_epoch, + ) { Ok(rewards) => Some(rewards), Err(error) => { eprintln!("Failed to fetch epoch rewards: {error:?}");