solana_rpc_get_stake_activation/
lib.rs1use {
2 serde::{Deserialize, Serialize},
3 solana_rpc_client::rpc_client::RpcClient,
4 solana_rpc_client_api::client_error::{Error, ErrorKind, Result as ClientResult},
5 solana_sdk::{
6 account::{from_account, ReadableAccount},
7 pubkey::Pubkey,
8 stake::state::{StakeActivationStatus, StakeStateV2},
9 stake_history::StakeHistory,
10 sysvar::stake_history,
11 },
12};
13
14#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
15#[serde(rename_all = "camelCase")]
16pub enum StakeActivationState {
17 Activating,
18 Active,
19 Deactivating,
20 Inactive,
21}
22
23#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
24#[serde(rename_all = "camelCase")]
25pub struct StakeActivation {
26 state: StakeActivationState,
27 active: u64,
28 inactive: u64,
29}
30
31pub fn get_stake_activation(
32 rpc_client: &RpcClient,
33 stake: &Pubkey,
34) -> ClientResult<StakeActivation> {
35 let stake_account = rpc_client.get_account(stake)?;
36 let stake_history_account = rpc_client.get_account(&stake_history::id())?;
37 let epoch_info = rpc_client.get_epoch_info()?;
38 let stake_state = bincode::deserialize::<StakeStateV2>(&stake_account.data).map_err(|_| {
39 Error::from(ErrorKind::Custom(
40 "Invalid param: stake account not initialized".to_string(),
41 ))
42 })?;
43 let delegation = stake_state.delegation();
44 let rent_exempt_reserve = stake_state
45 .meta()
46 .ok_or_else(|| {
47 Error::from(ErrorKind::Custom(
48 "Invalid param: stake account not initialized".to_string(),
49 ))
50 })?
51 .rent_exempt_reserve;
52
53 let delegation = match delegation {
54 None => {
55 return Ok(StakeActivation {
56 state: StakeActivationState::Inactive,
57 active: 0,
58 inactive: stake_account.lamports().saturating_sub(rent_exempt_reserve),
59 })
60 }
61 Some(delegation) => delegation,
62 };
63
64 let stake_history =
65 from_account::<StakeHistory, _>(&stake_history_account).ok_or(Error::from(
66 ErrorKind::Custom("Invalid param: stake history not deserializable".to_string()),
67 ))?;
68
69 let StakeActivationStatus {
70 effective,
71 activating,
72 deactivating,
73 } = delegation.stake_activating_and_deactivating(epoch_info.epoch, &stake_history, Some(0));
74 let stake_activation_state = if deactivating > 0 {
75 StakeActivationState::Deactivating
76 } else if activating > 0 {
77 StakeActivationState::Activating
78 } else if effective > 0 {
79 StakeActivationState::Active
80 } else {
81 StakeActivationState::Inactive
82 };
83 let inactive_stake = stake_account
84 .lamports()
85 .saturating_sub(effective)
86 .saturating_sub(rent_exempt_reserve);
87 Ok(StakeActivation {
88 state: stake_activation_state,
89 active: effective,
90 inactive: inactive_stake,
91 })
92}