anza-xyz / anza-xyz/solana-rpc-client-extensions
Past epoch stake activation
- Dominant language
- TypeScript
- Stars
- 20
- Forks
- 18
- PR merge metrics
- No merged PRs in 30d
Description
Hi, I want to share something I built on top of this library and ask for feedback on why it worked at first but then broke.
This library is designed to get stake activation for the current epoch.
I extended it to query stake activation for a specific past epoch by adding a get_stake_activation_by_epoch function.
- I removed rpc_client.get_epoch_info()
- I pass the user-supplied epoch to stake_activating_and_deactivating instead of epoch_info.epoch
```
pub fn get_stake_activation_by_epoch(
rpc_client: &RpcClient,
stake: &Pubkey,
epoch: u64
) -> ClientResult {
let stake_account = rpc_client.get_account(stake)?;
let stake_history_account = rpc_client.get_account(&stake_history::id())?;
let stake_state = bincode::deserialize::(&stake_account.data).map_err(|_| {
Error::from(ErrorKind::Custom(
"Invalid param: stake account not initialized".to_string(),
))
})?;
let delegation = stake_state.delegation();
let rent_exempt_reserve = stake_state
.meta()
.ok_or_else(|| {
Error::from(ErrorKind::Custom(
"Invalid param: stake account not initialized".to_string(),
))
})?
.rent_exempt_reserve;
let delegation = match delegation {
None => {
return Ok(StakeActivation {
state: StakeActivationState::Inactive,
active: 0,
inactive: stake_account.lamports().saturating_sub(rent_exempt_reserve),
})
}
Some(delegation) => delegation,
};
let stake_history =
from_account::(&stake_history_account).ok_or(Error::from(
ErrorKind::Custom("Invalid param: stake history not deserializable".to_string()),
))?;
let StakeActivationStatus {
effective,
activating,
deactivating,
} = delegation.stake_activating_and_deactivating(epoch, &stake_history, Some(0));
let stake_activation_state = if deactivating > 0 {
StakeActivationState::Deactivating
} else if activating > 0 {
StakeActivationState::Activating
} else if effective > 0 {
StakeActivationState::Active
} else {
StakeActivationState::Inactive
};
let inactive_stake = stake_account
.lamports()
.saturating_sub(effective)
.saturating_sub(rent_exempt_reserve);
Ok(StakeActivation {
state: stake_activation_state,
active: effective,
inactive: inactive_stake,
})
}
```
- This worked correctly from approximately January 2025 to June 2025
- Around July 2025 it started returning current active stake value regardless of which past epoch I queried
**My questions**
1. Was my approach fundamentally wrong?
2. If it was wrong, why did it return seemingly correct results for the first 6 months?
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.