CLI: Improve stake (de)activation display
This commit is contained in:
parent
34507e8a5b
commit
f9ee97d6f5
|
@ -482,7 +482,7 @@ impl fmt::Display for CliKeyedStakeState {
|
|||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CliStakeState {
|
||||
pub stake_type: CliStakeType,
|
||||
pub total_stake: u64,
|
||||
pub account_balance: u64,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub delegated_stake: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
|
@ -497,6 +497,16 @@ pub struct CliStakeState {
|
|||
pub lockup: Option<CliLockup>,
|
||||
#[serde(skip_serializing)]
|
||||
pub use_lamports_unit: bool,
|
||||
#[serde(skip_serializing)]
|
||||
pub current_epoch: Epoch,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rent_exempt_reserve: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub active_stake: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub activating_stake: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub deactivating_stake: Option<u64>,
|
||||
}
|
||||
|
||||
impl fmt::Display for CliStakeState {
|
||||
|
@ -522,52 +532,122 @@ impl fmt::Display for CliStakeState {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
writeln!(
|
||||
f,
|
||||
"Balance: {}",
|
||||
build_balance_message(self.account_balance, self.use_lamports_unit, true)
|
||||
)?;
|
||||
|
||||
if let Some(rent_exempt_reserve) = self.rent_exempt_reserve {
|
||||
writeln!(
|
||||
f,
|
||||
"Rent Exempt Reserve: {}",
|
||||
build_balance_message(rent_exempt_reserve, self.use_lamports_unit, true)
|
||||
)?;
|
||||
}
|
||||
|
||||
match self.stake_type {
|
||||
CliStakeType::RewardsPool => writeln!(f, "Stake account is a rewards pool")?,
|
||||
CliStakeType::Uninitialized => writeln!(f, "Stake account is uninitialized")?,
|
||||
CliStakeType::Initialized => {
|
||||
writeln!(
|
||||
f,
|
||||
"Total Stake: {}",
|
||||
build_balance_message(self.total_stake, self.use_lamports_unit, true)
|
||||
)?;
|
||||
writeln!(f, "Stake account is undelegated")?;
|
||||
show_authorized(f, self.authorized.as_ref().unwrap())?;
|
||||
show_lockup(f, self.lockup.as_ref().unwrap())?;
|
||||
}
|
||||
CliStakeType::Stake => {
|
||||
writeln!(
|
||||
f,
|
||||
"Total Stake: {}",
|
||||
build_balance_message(self.total_stake, self.use_lamports_unit, true)
|
||||
)?;
|
||||
let show_delegation = {
|
||||
self.active_stake.is_some()
|
||||
|| self.activating_stake.is_some()
|
||||
|| self.deactivating_stake.is_some()
|
||||
|| self
|
||||
.deactivation_epoch
|
||||
.map(|de| de > self.current_epoch)
|
||||
.unwrap_or(true)
|
||||
};
|
||||
if show_delegation {
|
||||
let delegated_stake = self.delegated_stake.unwrap();
|
||||
writeln!(
|
||||
f,
|
||||
"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(
|
||||
self.delegated_stake.unwrap(),
|
||||
activating_stake,
|
||||
self.use_lamports_unit,
|
||||
true
|
||||
)
|
||||
),
|
||||
)?;
|
||||
if let Some(delegated_vote_account_address) = &self.delegated_vote_account_address {
|
||||
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
|
||||
)?;
|
||||
}
|
||||
writeln!(
|
||||
f,
|
||||
"Stake activates starting from epoch: {}",
|
||||
self.activation_epoch.unwrap()
|
||||
)?;
|
||||
if let Some(deactivation_epoch) = self.deactivation_epoch {
|
||||
writeln!(
|
||||
f,
|
||||
"Stake deactivates starting from epoch: {}",
|
||||
deactivation_epoch
|
||||
)?;
|
||||
} else {
|
||||
writeln!(f, "Stake account is undelegated")?;
|
||||
}
|
||||
show_authorized(f, self.authorized.as_ref().unwrap())?;
|
||||
show_lockup(f, self.lockup.as_ref().unwrap())?;
|
||||
|
|
|
@ -29,7 +29,11 @@ use solana_sdk::{
|
|||
native_token::lamports_to_sol,
|
||||
pubkey::{self, Pubkey},
|
||||
system_instruction, system_program,
|
||||
sysvar::{self, Sysvar},
|
||||
sysvar::{
|
||||
self,
|
||||
stake_history::{self, StakeHistory},
|
||||
Sysvar,
|
||||
},
|
||||
transaction::Transaction,
|
||||
};
|
||||
use std::{
|
||||
|
@ -1184,8 +1188,13 @@ pub fn process_show_stakes(
|
|||
let progress_bar = new_spinner_progress_bar();
|
||||
progress_bar.set_message("Fetching stake accounts...");
|
||||
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 stake_history = StakeHistory::from_account(&stake_history_account).ok_or_else(|| {
|
||||
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
|
||||
})?;
|
||||
|
||||
let mut stake_accounts: Vec<CliKeyedStakeState> = vec![];
|
||||
for (stake_pubkey, stake_account) in all_stake_accounts {
|
||||
if let Ok(stake_state) = stake_account.state() {
|
||||
|
@ -1198,6 +1207,7 @@ pub fn process_show_stakes(
|
|||
stake_account.lamports,
|
||||
&stake_state,
|
||||
use_lamports_unit,
|
||||
&stake_history,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
@ -1214,6 +1224,7 @@ pub fn process_show_stakes(
|
|||
stake_account.lamports,
|
||||
&stake_state,
|
||||
use_lamports_unit,
|
||||
&stake_history,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1256,22 +1256,41 @@ pub fn process_stake_set_lockup(
|
|||
}
|
||||
}
|
||||
|
||||
fn u64_some_if_not_zero(n: u64) -> Option<u64> {
|
||||
if n > 0 {
|
||||
Some(n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_stake_state(
|
||||
stake_lamports: u64,
|
||||
account_balance: u64,
|
||||
stake_state: &StakeState,
|
||||
use_lamports_unit: bool,
|
||||
stake_history: &StakeHistory,
|
||||
) -> CliStakeState {
|
||||
match stake_state {
|
||||
StakeState::Stake(
|
||||
Meta {
|
||||
authorized, lockup, ..
|
||||
rent_exempt_reserve,
|
||||
authorized,
|
||||
lockup,
|
||||
},
|
||||
stake,
|
||||
) => CliStakeState {
|
||||
) => {
|
||||
// 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 (active_stake, activating_stake, deactivating_stake) = stake
|
||||
.delegation
|
||||
.stake_activating_and_deactivating(current_epoch, Some(stake_history));
|
||||
CliStakeState {
|
||||
stake_type: CliStakeType::Stake,
|
||||
total_stake: stake_lamports,
|
||||
account_balance,
|
||||
delegated_stake: Some(stake.delegation.stake),
|
||||
delegated_vote_account_address: if stake.delegation.voter_pubkey != Pubkey::default() {
|
||||
delegated_vote_account_address: if stake.delegation.voter_pubkey
|
||||
!= Pubkey::default()
|
||||
{
|
||||
Some(stake.delegation.voter_pubkey.to_string())
|
||||
} else {
|
||||
None
|
||||
|
@ -1289,20 +1308,33 @@ pub fn build_stake_state(
|
|||
authorized: Some(authorized.into()),
|
||||
lockup: Some(lockup.into()),
|
||||
use_lamports_unit,
|
||||
},
|
||||
current_epoch,
|
||||
rent_exempt_reserve: Some(*rent_exempt_reserve),
|
||||
active_stake: u64_some_if_not_zero(active_stake),
|
||||
activating_stake: u64_some_if_not_zero(activating_stake),
|
||||
deactivating_stake: u64_some_if_not_zero(deactivating_stake),
|
||||
}
|
||||
}
|
||||
StakeState::RewardsPool => CliStakeState {
|
||||
stake_type: CliStakeType::RewardsPool,
|
||||
account_balance,
|
||||
..CliStakeState::default()
|
||||
},
|
||||
StakeState::Uninitialized => CliStakeState {
|
||||
account_balance,
|
||||
..CliStakeState::default()
|
||||
},
|
||||
StakeState::Uninitialized => CliStakeState::default(),
|
||||
StakeState::Initialized(Meta {
|
||||
authorized, lockup, ..
|
||||
rent_exempt_reserve,
|
||||
authorized,
|
||||
lockup,
|
||||
}) => CliStakeState {
|
||||
stake_type: CliStakeType::Initialized,
|
||||
total_stake: stake_lamports,
|
||||
account_balance,
|
||||
authorized: Some(authorized.into()),
|
||||
lockup: Some(lockup.into()),
|
||||
use_lamports_unit,
|
||||
rent_exempt_reserve: Some(*rent_exempt_reserve),
|
||||
..CliStakeState::default()
|
||||
},
|
||||
}
|
||||
|
@ -1324,7 +1356,18 @@ pub fn process_show_stake_account(
|
|||
}
|
||||
match stake_account.state() {
|
||||
Ok(stake_state) => {
|
||||
let state = build_stake_state(stake_account.lamports, &stake_state, use_lamports_unit);
|
||||
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
|
||||
let stake_history =
|
||||
StakeHistory::from_account(&stake_history_account).ok_or_else(|| {
|
||||
CliError::RpcRequestError("Failed to deserialize stake history".to_string())
|
||||
})?;
|
||||
|
||||
let state = build_stake_state(
|
||||
stake_account.lamports,
|
||||
&stake_state,
|
||||
use_lamports_unit,
|
||||
&stake_history,
|
||||
);
|
||||
Ok(config.output_format.formatted_string(&state))
|
||||
}
|
||||
Err(err) => Err(CliError::RpcRequestError(format!(
|
||||
|
|
|
@ -202,7 +202,7 @@ impl Delegation {
|
|||
}
|
||||
|
||||
#[allow(clippy::comparison_chain)]
|
||||
fn stake_activating_and_deactivating(
|
||||
pub fn stake_activating_and_deactivating(
|
||||
&self,
|
||||
epoch: Epoch,
|
||||
history: Option<&StakeHistory>,
|
||||
|
|
Loading…
Reference in New Issue