Add getVoteAccounts RPC method parameter to restrict results to a single vote account
This commit is contained in:
committed by
mergify[bot]
parent
b66a68975b
commit
59fc33635a
@ -496,10 +496,17 @@ impl RpcClient {
|
|||||||
&self,
|
&self,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> ClientResult<RpcVoteAccountStatus> {
|
) -> ClientResult<RpcVoteAccountStatus> {
|
||||||
self.send(
|
self.get_vote_accounts_with_config(RpcGetVoteAccountsConfig {
|
||||||
RpcRequest::GetVoteAccounts,
|
commitment: Some(self.maybe_map_commitment(commitment_config)?),
|
||||||
json!([self.maybe_map_commitment(commitment_config)?]),
|
..RpcGetVoteAccountsConfig::default()
|
||||||
)
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_vote_accounts_with_config(
|
||||||
|
&self,
|
||||||
|
config: RpcGetVoteAccountsConfig,
|
||||||
|
) -> ClientResult<RpcVoteAccountStatus> {
|
||||||
|
self.send(RpcRequest::GetVoteAccounts, json!([config]))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait_for_max_stake(
|
pub fn wait_for_max_stake(
|
||||||
@ -884,15 +891,12 @@ impl RpcClient {
|
|||||||
slot: Option<Slot>,
|
slot: Option<Slot>,
|
||||||
commitment_config: CommitmentConfig,
|
commitment_config: CommitmentConfig,
|
||||||
) -> ClientResult<Option<RpcLeaderSchedule>> {
|
) -> ClientResult<Option<RpcLeaderSchedule>> {
|
||||||
self.send(
|
self.get_leader_schedule_with_config(
|
||||||
RpcRequest::GetLeaderSchedule,
|
|
||||||
json!([
|
|
||||||
slot,
|
slot,
|
||||||
RpcLeaderScheduleConfig {
|
RpcLeaderScheduleConfig {
|
||||||
commitment: Some(self.maybe_map_commitment(commitment_config)?),
|
commitment: Some(self.maybe_map_commitment(commitment_config)?),
|
||||||
..RpcLeaderScheduleConfig::default()
|
..RpcLeaderScheduleConfig::default()
|
||||||
}
|
},
|
||||||
]),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,14 @@ pub struct RpcLeaderScheduleConfig {
|
|||||||
pub commitment: Option<CommitmentConfig>,
|
pub commitment: Option<CommitmentConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcGetVoteAccountsConfig {
|
||||||
|
pub vote_pubkey: Option<String>, // validator vote address, as a base-58 encoded string
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub commitment: Option<CommitmentConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum RpcLeaderScheduleConfigWrapper {
|
pub enum RpcLeaderScheduleConfigWrapper {
|
||||||
|
@ -702,9 +702,17 @@ impl JsonRpcRequestProcessor {
|
|||||||
|
|
||||||
fn get_vote_accounts(
|
fn get_vote_accounts(
|
||||||
&self,
|
&self,
|
||||||
commitment: Option<CommitmentConfig>,
|
config: Option<RpcGetVoteAccountsConfig>,
|
||||||
) -> Result<RpcVoteAccountStatus> {
|
) -> Result<RpcVoteAccountStatus> {
|
||||||
let bank = self.bank(commitment);
|
let config = config.unwrap_or_default();
|
||||||
|
|
||||||
|
let filter_by_vote_pubkey = if let Some(ref vote_pubkey) = config.vote_pubkey {
|
||||||
|
Some(verify_pubkey(vote_pubkey)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let bank = self.bank(config.commitment);
|
||||||
let vote_accounts = bank.vote_accounts();
|
let vote_accounts = bank.vote_accounts();
|
||||||
let epoch_vote_accounts = bank
|
let epoch_vote_accounts = bank
|
||||||
.epoch_vote_accounts(bank.get_epoch_and_slot_index(bank.slot()).0)
|
.epoch_vote_accounts(bank.get_epoch_and_slot_index(bank.slot()).0)
|
||||||
@ -715,7 +723,13 @@ impl JsonRpcRequestProcessor {
|
|||||||
Vec<RpcVoteAccountInfo>,
|
Vec<RpcVoteAccountInfo>,
|
||||||
) = vote_accounts
|
) = vote_accounts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(pubkey, (activated_stake, account))| {
|
.filter_map(|(vote_pubkey, (activated_stake, account))| {
|
||||||
|
if let Some(filter_by_vote_pubkey) = filter_by_vote_pubkey {
|
||||||
|
if *vote_pubkey != filter_by_vote_pubkey {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let vote_state = account.vote_state();
|
let vote_state = account.vote_state();
|
||||||
let vote_state = vote_state.as_ref().unwrap_or(&default_vote_state);
|
let vote_state = vote_state.as_ref().unwrap_or(&default_vote_state);
|
||||||
let last_vote = if let Some(vote) = vote_state.votes.iter().last() {
|
let last_vote = if let Some(vote) = vote_state.votes.iter().last() {
|
||||||
@ -735,16 +749,16 @@ impl JsonRpcRequestProcessor {
|
|||||||
epoch_credits.clone()
|
epoch_credits.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
RpcVoteAccountInfo {
|
Some(RpcVoteAccountInfo {
|
||||||
vote_pubkey: (pubkey).to_string(),
|
vote_pubkey: vote_pubkey.to_string(),
|
||||||
node_pubkey: vote_state.node_pubkey.to_string(),
|
node_pubkey: vote_state.node_pubkey.to_string(),
|
||||||
activated_stake: *activated_stake,
|
activated_stake: *activated_stake,
|
||||||
commission: vote_state.commission,
|
commission: vote_state.commission,
|
||||||
root_slot: vote_state.root_slot.unwrap_or(0),
|
root_slot: vote_state.root_slot.unwrap_or(0),
|
||||||
epoch_credits,
|
epoch_credits,
|
||||||
epoch_vote_account: epoch_vote_accounts.contains_key(pubkey),
|
epoch_vote_account: epoch_vote_accounts.contains_key(vote_pubkey),
|
||||||
last_vote,
|
last_vote,
|
||||||
}
|
})
|
||||||
})
|
})
|
||||||
.partition(|vote_account_info| {
|
.partition(|vote_account_info| {
|
||||||
if bank.slot() >= DELINQUENT_VALIDATOR_SLOT_DISTANCE as u64 {
|
if bank.slot() >= DELINQUENT_VALIDATOR_SLOT_DISTANCE as u64 {
|
||||||
@ -2100,7 +2114,7 @@ pub mod rpc_minimal {
|
|||||||
fn get_vote_accounts(
|
fn get_vote_accounts(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
commitment: Option<CommitmentConfig>,
|
config: Option<RpcGetVoteAccountsConfig>,
|
||||||
) -> Result<RpcVoteAccountStatus>;
|
) -> Result<RpcVoteAccountStatus>;
|
||||||
|
|
||||||
// TODO: Refactor `solana-validator wait-for-restart-window` to not require this method, so
|
// TODO: Refactor `solana-validator wait-for-restart-window` to not require this method, so
|
||||||
@ -2203,10 +2217,10 @@ pub mod rpc_minimal {
|
|||||||
fn get_vote_accounts(
|
fn get_vote_accounts(
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
commitment: Option<CommitmentConfig>,
|
config: Option<RpcGetVoteAccountsConfig>,
|
||||||
) -> Result<RpcVoteAccountStatus> {
|
) -> Result<RpcVoteAccountStatus> {
|
||||||
debug!("get_vote_accounts rpc request received");
|
debug!("get_vote_accounts rpc request received");
|
||||||
meta.get_vote_accounts(commitment)
|
meta.get_vote_accounts(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Refactor `solana-validator wait-for-restart-window` to not require this method, so
|
// TODO: Refactor `solana-validator wait-for-restart-window` to not require this method, so
|
||||||
@ -6046,6 +6060,33 @@ pub mod tests {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Filter request based on the leader:
|
||||||
|
{
|
||||||
|
let req = format!(
|
||||||
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getVoteAccounts","params":{}}}"#,
|
||||||
|
json!([RpcGetVoteAccountsConfig {
|
||||||
|
vote_pubkey: Some(leader_vote_keypair.pubkey().to_string()),
|
||||||
|
commitment: Some(CommitmentConfig::processed())
|
||||||
|
}])
|
||||||
|
);
|
||||||
|
|
||||||
|
let res = io.handle_request_sync(&req, meta.clone());
|
||||||
|
let result: Value = serde_json::from_str(&res.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
let vote_account_status: RpcVoteAccountStatus =
|
||||||
|
serde_json::from_value(result["result"].clone()).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(vote_account_status.current.len(), 1);
|
||||||
|
assert_eq!(vote_account_status.delinquent.len(), 0);
|
||||||
|
for vote_account_info in vote_account_status.current {
|
||||||
|
assert_eq!(
|
||||||
|
vote_account_info.vote_pubkey,
|
||||||
|
leader_vote_keypair.pubkey().to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Overflow the epoch credits history and ensure only `MAX_RPC_EPOCH_CREDITS_HISTORY`
|
// Overflow the epoch credits history and ensure only `MAX_RPC_EPOCH_CREDITS_HISTORY`
|
||||||
// results are returned
|
// results are returned
|
||||||
for _ in 0..(TEST_SLOTS_PER_EPOCH * (MAX_RPC_EPOCH_CREDITS_HISTORY) as u64) {
|
for _ in 0..(TEST_SLOTS_PER_EPOCH * (MAX_RPC_EPOCH_CREDITS_HISTORY) as u64) {
|
||||||
|
@ -2848,11 +2848,14 @@ Returns the account info and associated stake for all the voting accounts in the
|
|||||||
|
|
||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
- `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
- `<object>` - (optional) Configuration object containing the following field:
|
||||||
|
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
|
- (optional) `votePubkey: <string>` - Only return results for this validator vote address (base-58 encoded)
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
The result field will be a JSON object of `current` and `delinquent` accounts, each containing an array of JSON objects with the following sub fields:
|
The result field will be a JSON object of `current` and `delinquent` accounts,
|
||||||
|
each containing an array of JSON objects with the following sub fields:
|
||||||
|
|
||||||
- `votePubkey: <string>` - Vote account address, as base-58 encoded string
|
- `votePubkey: <string>` - Vote account address, as base-58 encoded string
|
||||||
- `nodePubkey: <string>` - Validator identity, as base-58 encoded string
|
- `nodePubkey: <string>` - Validator identity, as base-58 encoded string
|
||||||
@ -2905,6 +2908,49 @@ Result:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Example: Restrict results to a single validator vote account
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "getVoteAccounts",
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"votePubkey": "3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
'
|
||||||
|
```
|
||||||
|
|
||||||
|
Result:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"result": {
|
||||||
|
"current": [
|
||||||
|
{
|
||||||
|
"commission": 0,
|
||||||
|
"epochVoteAccount": true,
|
||||||
|
"epochCredits": [
|
||||||
|
[ 1, 64, 0 ],
|
||||||
|
[ 2, 192, 64 ]
|
||||||
|
],
|
||||||
|
"nodePubkey": "B97CCUW3AEZFGy6uUg6zUdnNYvnVq5VG8PUtb2HayTDD",
|
||||||
|
"lastVote": 147,
|
||||||
|
"activatedStake": 42,
|
||||||
|
"votePubkey": "3ZT31jkAGhUaw8jsy4bTknwBMP8i4Eueh52By4zXcsVw"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"delinquent": []
|
||||||
|
},
|
||||||
|
"id": 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### minimumLedgerSlot
|
### minimumLedgerSlot
|
||||||
|
|
||||||
Returns the lowest slot that the node has information about in its ledger. This
|
Returns the lowest slot that the node has information about in its ledger. This
|
||||||
|
Reference in New Issue
Block a user