Rpc: Add getStakeActivation endpoint (#10902)
* Add getStakeActivation endpoint * Add docs * Update docs/src/apps/jsonrpc-api.md Co-authored-by: Michael Vines <mvines@gmail.com> * Rework return type * Update docs * Rebase Co-authored-by: Michael Vines <mvines@gmail.com>
This commit is contained in:
parent
39b3ac6a8d
commit
4de0713aa3
|
@ -37,7 +37,7 @@ pub struct RpcLargestAccountsConfig {
|
|||
|
||||
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcInflationConfig {
|
||||
pub struct RpcStakeConfig {
|
||||
pub epoch: Option<Epoch>,
|
||||
#[serde(flatten)]
|
||||
pub commitment: Option<CommitmentConfig>,
|
||||
|
|
|
@ -202,3 +202,20 @@ pub struct RpcSupply {
|
|||
pub non_circulating: u64,
|
||||
pub non_circulating_accounts: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum StakeActivationState {
|
||||
Activating,
|
||||
Active,
|
||||
Deactivating,
|
||||
Inactive,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RpcStakeActivation {
|
||||
pub state: StakeActivationState,
|
||||
pub active: u64,
|
||||
pub inactive: u64,
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ use solana_runtime::{
|
|||
log_collector::LogCollector,
|
||||
};
|
||||
use solana_sdk::{
|
||||
account_utils::StateMut,
|
||||
clock::{Slot, UnixTimestamp},
|
||||
commitment_config::{CommitmentConfig, CommitmentLevel},
|
||||
epoch_info::EpochInfo,
|
||||
|
@ -37,9 +38,12 @@ use solana_sdk::{
|
|||
hash::Hash,
|
||||
pubkey::Pubkey,
|
||||
signature::Signature,
|
||||
stake_history::StakeHistory,
|
||||
sysvar::{stake_history, Sysvar},
|
||||
timing::slot_duration_from_slots_per_year,
|
||||
transaction::{self, Transaction},
|
||||
};
|
||||
use solana_stake_program::stake_state::StakeState;
|
||||
use solana_transaction_status::{
|
||||
ConfirmedBlock, ConfirmedTransaction, TransactionStatus, UiTransactionEncoding,
|
||||
};
|
||||
|
@ -755,6 +759,67 @@ impl JsonRpcRequestProcessor {
|
|||
.get_first_available_block()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn get_stake_activation(
|
||||
&self,
|
||||
pubkey: &Pubkey,
|
||||
config: Option<RpcStakeConfig>,
|
||||
) -> Result<RpcStakeActivation> {
|
||||
let config = config.unwrap_or_default();
|
||||
let bank = self.bank(config.commitment);
|
||||
let epoch = config.epoch.unwrap_or_else(|| bank.epoch());
|
||||
if bank.epoch().saturating_sub(epoch) > solana_sdk::stake_history::MAX_ENTRIES as u64 {
|
||||
return Err(Error::invalid_params(format!(
|
||||
"Invalid param: epoch {:?} is too far in the past",
|
||||
epoch
|
||||
)));
|
||||
}
|
||||
if epoch > bank.epoch() {
|
||||
return Err(Error::invalid_params(format!(
|
||||
"Invalid param: epoch {:?} has not yet started",
|
||||
epoch
|
||||
)));
|
||||
}
|
||||
|
||||
let stake_account = bank
|
||||
.get_account(pubkey)
|
||||
.ok_or_else(|| Error::invalid_params("Invalid param: account not found".to_string()))?;
|
||||
let stake_state: StakeState = stake_account
|
||||
.state()
|
||||
.map_err(|_| Error::invalid_params("Invalid param: not a stake account".to_string()))?;
|
||||
let delegation = stake_state.delegation().ok_or_else(|| {
|
||||
Error::invalid_params("Invalid param: stake account has not been delegated".to_string())
|
||||
})?;
|
||||
|
||||
let stake_history_account = bank
|
||||
.get_account(&stake_history::id())
|
||||
.ok_or_else(Error::internal_error)?;
|
||||
let stake_history =
|
||||
StakeHistory::from_account(&stake_history_account).ok_or_else(Error::internal_error)?;
|
||||
|
||||
let (active, activating, deactivating) =
|
||||
delegation.stake_activating_and_deactivating(epoch, Some(&stake_history));
|
||||
let stake_activation_state = if deactivating > 0 {
|
||||
StakeActivationState::Deactivating
|
||||
} else if activating > 0 {
|
||||
StakeActivationState::Activating
|
||||
} else if active > 0 {
|
||||
StakeActivationState::Active
|
||||
} else {
|
||||
StakeActivationState::Inactive
|
||||
};
|
||||
let inactive_stake = match stake_activation_state {
|
||||
StakeActivationState::Activating => activating,
|
||||
StakeActivationState::Active => 0,
|
||||
StakeActivationState::Deactivating => delegation.stake.saturating_sub(active),
|
||||
StakeActivationState::Inactive => delegation.stake,
|
||||
};
|
||||
Ok(RpcStakeActivation {
|
||||
state: stake_activation_state,
|
||||
active,
|
||||
inactive: inactive_stake,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn verify_filter(input: &RpcFilterType) -> Result<()> {
|
||||
|
@ -1062,6 +1127,14 @@ pub trait RpcSol {
|
|||
|
||||
#[rpc(meta, name = "getFirstAvailableBlock")]
|
||||
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot>;
|
||||
|
||||
#[rpc(meta, name = "getStakeActivation")]
|
||||
fn get_stake_activation(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
pubkey_str: String,
|
||||
config: Option<RpcStakeConfig>,
|
||||
) -> Result<RpcStakeActivation>;
|
||||
}
|
||||
|
||||
pub struct RpcSolImpl;
|
||||
|
@ -1589,6 +1662,20 @@ impl RpcSol for RpcSolImpl {
|
|||
fn get_first_available_block(&self, meta: Self::Metadata) -> Result<Slot> {
|
||||
Ok(meta.get_first_available_block())
|
||||
}
|
||||
|
||||
fn get_stake_activation(
|
||||
&self,
|
||||
meta: Self::Metadata,
|
||||
pubkey_str: String,
|
||||
config: Option<RpcStakeConfig>,
|
||||
) -> Result<RpcStakeActivation> {
|
||||
debug!(
|
||||
"get_stake_activation rpc request received: {:?}",
|
||||
pubkey_str
|
||||
);
|
||||
let pubkey = verify_pubkey(pubkey_str)?;
|
||||
meta.get_stake_activation(&pubkey, config)
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_bs58_transaction(bs58_transaction: String) -> Result<(Vec<u8>, Transaction)> {
|
||||
|
|
|
@ -41,6 +41,7 @@ To interact with a Solana node inside a JavaScript application, use the [solana-
|
|||
* [getSignatureStatuses](jsonrpc-api.md#getsignaturestatuses)
|
||||
* [getSlot](jsonrpc-api.md#getslot)
|
||||
* [getSlotLeader](jsonrpc-api.md#getslotleader)
|
||||
* [getStakeActivation](jsonrpc-api.md#getstakeactivation)
|
||||
* [getSupply](jsonrpc-api.md#getsupply)
|
||||
* [getTransactionCount](jsonrpc-api.md#gettransactioncount)
|
||||
* [getVersion](jsonrpc-api.md#getversion)
|
||||
|
@ -943,6 +944,41 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m
|
|||
{"jsonrpc":"2.0","result":"ENvAW7JScgYq6o4zKZwewtkzzJgDzuJAFxYasvmEQdpS","id":1}
|
||||
```
|
||||
|
||||
### getStakeActivation
|
||||
|
||||
Returns epoch activation information for a stake account
|
||||
|
||||
#### Parameters:
|
||||
|
||||
* `<string>` - Pubkey of stake account to query, as base-58 encoded string
|
||||
* `<object>` - (optional) Configuration object containing the following optional fields:
|
||||
* (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||
* (optional) `epoch: <u64>` - epoch for which to calculate activation details. If parameter not provided, defaults to current epoch.
|
||||
|
||||
#### Results:
|
||||
|
||||
The result will be a JSON object with the following fields:
|
||||
|
||||
* `state: <string` - the stake account's activation state, one of: `active`, `inactive`, `activating`, `deactivating`
|
||||
* `active: <u64>` - stake active during the epoch
|
||||
* `inactive: <u64>` - stake inactive during the epoch
|
||||
|
||||
#### Example:
|
||||
|
||||
```bash
|
||||
// Request
|
||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStakeActivation", "params": ["CYRJWqiSjLitBAcRxPvWpgX3s5TvmN2SuRY3eEYypFvT"]}' http://localhost:8899
|
||||
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":{"active":197717120,"inactive":0,"state":"active"},"id":1}
|
||||
|
||||
// Request with Epoch
|
||||
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getStakeActivation", "params": ["CYRJWqiSjLitBAcRxPvWpgX3s5TvmN2SuRY3eEYypFvT", {"epoch": 4}]}' http://localhost:8899
|
||||
|
||||
// Result
|
||||
{"jsonrpc":"2.0","result":{"active":124429280,"inactive":73287840,"state":"activating"},"id":1}
|
||||
```
|
||||
|
||||
### getSupply
|
||||
|
||||
Returns information about the current supply.
|
||||
|
|
Loading…
Reference in New Issue