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")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct CliStakeState {
|
pub struct CliStakeState {
|
||||||
pub stake_type: CliStakeType,
|
pub stake_type: CliStakeType,
|
||||||
pub total_stake: u64,
|
pub account_balance: u64,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub delegated_stake: Option<u64>,
|
pub delegated_stake: Option<u64>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
@ -497,6 +497,16 @@ pub struct CliStakeState {
|
||||||
pub lockup: Option<CliLockup>,
|
pub lockup: Option<CliLockup>,
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
pub use_lamports_unit: bool,
|
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 {
|
impl fmt::Display for CliStakeState {
|
||||||
|
@ -522,52 +532,122 @@ impl fmt::Display for CliStakeState {
|
||||||
Ok(())
|
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 {
|
match self.stake_type {
|
||||||
CliStakeType::RewardsPool => writeln!(f, "Stake account is a rewards pool")?,
|
CliStakeType::RewardsPool => writeln!(f, "Stake account is a rewards pool")?,
|
||||||
CliStakeType::Uninitialized => writeln!(f, "Stake account is uninitialized")?,
|
CliStakeType::Uninitialized => writeln!(f, "Stake account is uninitialized")?,
|
||||||
CliStakeType::Initialized => {
|
CliStakeType::Initialized => {
|
||||||
writeln!(
|
|
||||||
f,
|
|
||||||
"Total Stake: {}",
|
|
||||||
build_balance_message(self.total_stake, self.use_lamports_unit, true)
|
|
||||||
)?;
|
|
||||||
writeln!(f, "Stake account is undelegated")?;
|
writeln!(f, "Stake account is undelegated")?;
|
||||||
show_authorized(f, self.authorized.as_ref().unwrap())?;
|
show_authorized(f, self.authorized.as_ref().unwrap())?;
|
||||||
show_lockup(f, self.lockup.as_ref().unwrap())?;
|
show_lockup(f, self.lockup.as_ref().unwrap())?;
|
||||||
}
|
}
|
||||||
CliStakeType::Stake => {
|
CliStakeType::Stake => {
|
||||||
writeln!(
|
let show_delegation = {
|
||||||
f,
|
self.active_stake.is_some()
|
||||||
"Total Stake: {}",
|
|| self.activating_stake.is_some()
|
||||||
build_balance_message(self.total_stake, self.use_lamports_unit, true)
|
|| self.deactivating_stake.is_some()
|
||||||
)?;
|
|| self
|
||||||
writeln!(
|
.deactivation_epoch
|
||||||
f,
|
.map(|de| de > self.current_epoch)
|
||||||
"Delegated Stake: {}",
|
.unwrap_or(true)
|
||||||
build_balance_message(
|
};
|
||||||
self.delegated_stake.unwrap(),
|
if show_delegation {
|
||||||
self.use_lamports_unit,
|
let delegated_stake = self.delegated_stake.unwrap();
|
||||||
true
|
|
||||||
)
|
|
||||||
)?;
|
|
||||||
if let Some(delegated_vote_account_address) = &self.delegated_vote_account_address {
|
|
||||||
writeln!(
|
writeln!(
|
||||||
f,
|
f,
|
||||||
"Delegated Vote Account Address: {}",
|
"Delegated Stake: {}",
|
||||||
delegated_vote_account_address
|
build_balance_message(delegated_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 {
|
|
||||||
writeln!(
|
|
||||||
f,
|
|
||||||
"Stake deactivates starting from epoch: {}",
|
|
||||||
deactivation_epoch
|
|
||||||
)?;
|
)?;
|
||||||
|
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
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
writeln!(f, "Stake account is undelegated")?;
|
||||||
}
|
}
|
||||||
show_authorized(f, self.authorized.as_ref().unwrap())?;
|
show_authorized(f, self.authorized.as_ref().unwrap())?;
|
||||||
show_lockup(f, self.lockup.as_ref().unwrap())?;
|
show_lockup(f, self.lockup.as_ref().unwrap())?;
|
||||||
|
|
|
@ -29,7 +29,11 @@ use solana_sdk::{
|
||||||
native_token::lamports_to_sol,
|
native_token::lamports_to_sol,
|
||||||
pubkey::{self, Pubkey},
|
pubkey::{self, Pubkey},
|
||||||
system_instruction, system_program,
|
system_instruction, system_program,
|
||||||
sysvar::{self, Sysvar},
|
sysvar::{
|
||||||
|
self,
|
||||||
|
stake_history::{self, StakeHistory},
|
||||||
|
Sysvar,
|
||||||
|
},
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -1184,8 +1188,13 @@ pub fn process_show_stakes(
|
||||||
let progress_bar = new_spinner_progress_bar();
|
let progress_bar = new_spinner_progress_bar();
|
||||||
progress_bar.set_message("Fetching stake accounts...");
|
progress_bar.set_message("Fetching stake accounts...");
|
||||||
let all_stake_accounts = rpc_client.get_program_accounts(&solana_stake_program::id())?;
|
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();
|
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![];
|
let mut stake_accounts: Vec<CliKeyedStakeState> = vec![];
|
||||||
for (stake_pubkey, stake_account) in all_stake_accounts {
|
for (stake_pubkey, stake_account) in all_stake_accounts {
|
||||||
if let Ok(stake_state) = stake_account.state() {
|
if let Ok(stake_state) = stake_account.state() {
|
||||||
|
@ -1198,6 +1207,7 @@ pub fn process_show_stakes(
|
||||||
stake_account.lamports,
|
stake_account.lamports,
|
||||||
&stake_state,
|
&stake_state,
|
||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
|
&stake_history,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1214,6 +1224,7 @@ pub fn process_show_stakes(
|
||||||
stake_account.lamports,
|
stake_account.lamports,
|
||||||
&stake_state,
|
&stake_state,
|
||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
|
&stake_history,
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
101
cli/src/stake.rs
101
cli/src/stake.rs
|
@ -1256,53 +1256,85 @@ 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(
|
pub fn build_stake_state(
|
||||||
stake_lamports: u64,
|
account_balance: u64,
|
||||||
stake_state: &StakeState,
|
stake_state: &StakeState,
|
||||||
use_lamports_unit: bool,
|
use_lamports_unit: bool,
|
||||||
|
stake_history: &StakeHistory,
|
||||||
) -> CliStakeState {
|
) -> CliStakeState {
|
||||||
match stake_state {
|
match stake_state {
|
||||||
StakeState::Stake(
|
StakeState::Stake(
|
||||||
Meta {
|
Meta {
|
||||||
authorized, lockup, ..
|
rent_exempt_reserve,
|
||||||
|
authorized,
|
||||||
|
lockup,
|
||||||
},
|
},
|
||||||
stake,
|
stake,
|
||||||
) => CliStakeState {
|
) => {
|
||||||
stake_type: CliStakeType::Stake,
|
// The first entry in stake history is the previous epoch, so +1 for current
|
||||||
total_stake: stake_lamports,
|
let current_epoch = stake_history.iter().next().unwrap().0 + 1;
|
||||||
delegated_stake: Some(stake.delegation.stake),
|
let (active_stake, activating_stake, deactivating_stake) = stake
|
||||||
delegated_vote_account_address: if stake.delegation.voter_pubkey != Pubkey::default() {
|
.delegation
|
||||||
Some(stake.delegation.voter_pubkey.to_string())
|
.stake_activating_and_deactivating(current_epoch, Some(stake_history));
|
||||||
} else {
|
CliStakeState {
|
||||||
None
|
stake_type: CliStakeType::Stake,
|
||||||
},
|
account_balance,
|
||||||
activation_epoch: Some(if stake.delegation.activation_epoch < std::u64::MAX {
|
delegated_stake: Some(stake.delegation.stake),
|
||||||
stake.delegation.activation_epoch
|
delegated_vote_account_address: if stake.delegation.voter_pubkey
|
||||||
} else {
|
!= Pubkey::default()
|
||||||
0
|
{
|
||||||
}),
|
Some(stake.delegation.voter_pubkey.to_string())
|
||||||
deactivation_epoch: if stake.delegation.deactivation_epoch < std::u64::MAX {
|
} else {
|
||||||
Some(stake.delegation.deactivation_epoch)
|
None
|
||||||
} else {
|
},
|
||||||
None
|
activation_epoch: Some(if stake.delegation.activation_epoch < std::u64::MAX {
|
||||||
},
|
stake.delegation.activation_epoch
|
||||||
authorized: Some(authorized.into()),
|
} else {
|
||||||
lockup: Some(lockup.into()),
|
0
|
||||||
use_lamports_unit,
|
}),
|
||||||
},
|
deactivation_epoch: if stake.delegation.deactivation_epoch < std::u64::MAX {
|
||||||
|
Some(stake.delegation.deactivation_epoch)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
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 {
|
StakeState::RewardsPool => CliStakeState {
|
||||||
stake_type: CliStakeType::RewardsPool,
|
stake_type: CliStakeType::RewardsPool,
|
||||||
|
account_balance,
|
||||||
|
..CliStakeState::default()
|
||||||
|
},
|
||||||
|
StakeState::Uninitialized => CliStakeState {
|
||||||
|
account_balance,
|
||||||
..CliStakeState::default()
|
..CliStakeState::default()
|
||||||
},
|
},
|
||||||
StakeState::Uninitialized => CliStakeState::default(),
|
|
||||||
StakeState::Initialized(Meta {
|
StakeState::Initialized(Meta {
|
||||||
authorized, lockup, ..
|
rent_exempt_reserve,
|
||||||
|
authorized,
|
||||||
|
lockup,
|
||||||
}) => CliStakeState {
|
}) => CliStakeState {
|
||||||
stake_type: CliStakeType::Initialized,
|
stake_type: CliStakeType::Initialized,
|
||||||
total_stake: stake_lamports,
|
account_balance,
|
||||||
authorized: Some(authorized.into()),
|
authorized: Some(authorized.into()),
|
||||||
lockup: Some(lockup.into()),
|
lockup: Some(lockup.into()),
|
||||||
use_lamports_unit,
|
use_lamports_unit,
|
||||||
|
rent_exempt_reserve: Some(*rent_exempt_reserve),
|
||||||
..CliStakeState::default()
|
..CliStakeState::default()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -1324,7 +1356,18 @@ pub fn process_show_stake_account(
|
||||||
}
|
}
|
||||||
match stake_account.state() {
|
match stake_account.state() {
|
||||||
Ok(stake_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))
|
Ok(config.output_format.formatted_string(&state))
|
||||||
}
|
}
|
||||||
Err(err) => Err(CliError::RpcRequestError(format!(
|
Err(err) => Err(CliError::RpcRequestError(format!(
|
||||||
|
|
|
@ -202,7 +202,7 @@ impl Delegation {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::comparison_chain)]
|
#[allow(clippy::comparison_chain)]
|
||||||
fn stake_activating_and_deactivating(
|
pub fn stake_activating_and_deactivating(
|
||||||
&self,
|
&self,
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
history: Option<&StakeHistory>,
|
history: Option<&StakeHistory>,
|
||||||
|
|
Loading…
Reference in New Issue