diff --git a/cli/src/cli_output.rs b/cli/src/cli_output.rs index 9372246dbf12f1..574c7fa9c74251 100644 --- a/cli/src/cli_output.rs +++ b/cli/src/cli_output.rs @@ -516,19 +516,25 @@ impl fmt::Display for CliStakeState { writeln!(f, "Withdraw Authority: {}", authorized.withdrawer)?; Ok(()) } - fn show_lockup(f: &mut fmt::Formatter, lockup: &CliLockup) -> fmt::Result { - writeln!( - f, - "Lockup Timestamp: {} (UnixTimestamp: {})", - DateTime::::from_utc( - NaiveDateTime::from_timestamp(lockup.unix_timestamp, 0), - Utc - ) - .to_rfc3339_opts(SecondsFormat::Secs, true), - lockup.unix_timestamp - )?; - writeln!(f, "Lockup Epoch: {}", lockup.epoch)?; - writeln!(f, "Lockup Custodian: {}", lockup.custodian)?; + fn show_lockup(f: &mut fmt::Formatter, lockup: Option<&CliLockup>) -> fmt::Result { + if let Some(lockup) = lockup { + if lockup.unix_timestamp != UnixTimestamp::default() { + writeln!( + f, + "Lockup Timestamp: {} (UnixTimestamp: {})", + DateTime::::from_utc( + NaiveDateTime::from_timestamp(lockup.unix_timestamp, 0), + Utc + ) + .to_rfc3339_opts(SecondsFormat::Secs, true), + lockup.unix_timestamp + )?; + } + if lockup.epoch != Epoch::default() { + writeln!(f, "Lockup Epoch: {}", lockup.epoch)?; + } + writeln!(f, "Lockup Custodian: {}", lockup.custodian)?; + } Ok(()) } @@ -552,7 +558,7 @@ impl fmt::Display for CliStakeState { CliStakeType::Initialized => { writeln!(f, "Stake account is undelegated")?; show_authorized(f, self.authorized.as_ref().unwrap())?; - show_lockup(f, self.lockup.as_ref().unwrap())?; + show_lockup(f, self.lockup.as_ref())?; } CliStakeType::Stake => { let show_delegation = { @@ -650,7 +656,7 @@ impl fmt::Display for CliStakeState { writeln!(f, "Stake account is undelegated")?; } show_authorized(f, self.authorized.as_ref().unwrap())?; - show_lockup(f, self.lockup.as_ref().unwrap())?; + show_lockup(f, self.lockup.as_ref())?; } } Ok(()) diff --git a/cli/src/cluster_query.rs b/cli/src/cluster_query.rs index c6545453e53ead..867189a90556f4 100644 --- a/cli/src/cluster_query.rs +++ b/cli/src/cluster_query.rs @@ -1190,10 +1190,14 @@ pub fn process_show_stakes( let all_stake_accounts = rpc_client.get_program_accounts(&solana_stake_program::id())?; let stake_history_account = rpc_client.get_account(&stake_history::id())?; progress_bar.finish_and_clear(); + let clock_account = rpc_client.get_account(&sysvar::clock::id())?; let stake_history = StakeHistory::from_account(&stake_history_account).ok_or_else(|| { CliError::RpcRequestError("Failed to deserialize stake history".to_string()) })?; + let clock: Clock = Sysvar::from_account(&clock_account).ok_or_else(|| { + CliError::RpcRequestError("Failed to deserialize clock sysvar".to_string()) + })?; let mut stake_accounts: Vec = vec![]; for (stake_pubkey, stake_account) in all_stake_accounts { @@ -1208,6 +1212,7 @@ pub fn process_show_stakes( &stake_state, use_lamports_unit, &stake_history, + &clock, ), }); } @@ -1225,6 +1230,7 @@ pub fn process_show_stakes( &stake_state, use_lamports_unit, &stake_history, + &clock, ), }); } diff --git a/cli/src/stake.rs b/cli/src/stake.rs index e048eea6681d9b..7c5308228d39ab 100644 --- a/cli/src/stake.rs +++ b/cli/src/stake.rs @@ -16,10 +16,12 @@ use solana_client::rpc_client::RpcClient; use solana_remote_wallet::remote_wallet::RemoteWalletManager; use solana_sdk::{ account_utils::StateMut, + clock::Clock, message::Message, pubkey::Pubkey, system_instruction::SystemError, sysvar::{ + clock, stake_history::{self, StakeHistory}, Sysvar, }, @@ -30,7 +32,7 @@ use solana_stake_program::{ stake_state::{Authorized, Lockup, Meta, StakeAuthorize, StakeState}, }; use solana_vote_program::vote_state::VoteState; -use std::{ops::Deref, sync::Arc}; +use std::{collections::HashSet, ops::Deref, sync::Arc}; pub const STAKE_AUTHORITY_ARG: ArgConstant<'static> = ArgConstant { name: "stake_authority", @@ -1269,6 +1271,7 @@ pub fn build_stake_state( stake_state: &StakeState, use_lamports_unit: bool, stake_history: &StakeHistory, + clock: &Clock, ) -> CliStakeState { match stake_state { StakeState::Stake( @@ -1279,11 +1282,15 @@ pub fn build_stake_state( }, stake, ) => { - // The first entry in stake history is the previous epoch, so +1 for current - let current_epoch = stake_history.iter().next().unwrap().0 + 1; + let current_epoch = clock.epoch; let (active_stake, activating_stake, deactivating_stake) = stake .delegation .stake_activating_and_deactivating(current_epoch, Some(stake_history)); + let lockup = if lockup.is_in_force(clock, &HashSet::new()) { + Some(lockup.into()) + } else { + None + }; CliStakeState { stake_type: CliStakeType::Stake, account_balance, @@ -1306,7 +1313,7 @@ pub fn build_stake_state( None }, authorized: Some(authorized.into()), - lockup: Some(lockup.into()), + lockup, use_lamports_unit, current_epoch, rent_exempt_reserve: Some(*rent_exempt_reserve), @@ -1328,15 +1335,22 @@ pub fn build_stake_state( rent_exempt_reserve, authorized, lockup, - }) => CliStakeState { - stake_type: CliStakeType::Initialized, - account_balance, - authorized: Some(authorized.into()), - lockup: Some(lockup.into()), - use_lamports_unit, - rent_exempt_reserve: Some(*rent_exempt_reserve), - ..CliStakeState::default() - }, + }) => { + let lockup = if lockup.is_in_force(clock, &HashSet::new()) { + Some(lockup.into()) + } else { + None + }; + CliStakeState { + stake_type: CliStakeType::Initialized, + account_balance, + authorized: Some(authorized.into()), + lockup, + use_lamports_unit, + rent_exempt_reserve: Some(*rent_exempt_reserve), + ..CliStakeState::default() + } + } } } @@ -1361,12 +1375,17 @@ pub fn process_show_stake_account( StakeHistory::from_account(&stake_history_account).ok_or_else(|| { CliError::RpcRequestError("Failed to deserialize stake history".to_string()) })?; + let clock_account = rpc_client.get_account(&clock::id())?; + let clock: Clock = Sysvar::from_account(&clock_account).ok_or_else(|| { + CliError::RpcRequestError("Failed to deserialize clock sysvar".to_string()) + })?; let state = build_stake_state( stake_account.lamports, &stake_state, use_lamports_unit, &stake_history, + &clock, ); Ok(config.output_format.formatted_string(&state)) }