getLeaderSchedule now supports filtered results based on validator identity
This commit is contained in:
parent
3f92abedd5
commit
6004c0abf5
|
@ -9,11 +9,7 @@ use {
|
||||||
http_sender::HttpSender,
|
http_sender::HttpSender,
|
||||||
mock_sender::{MockSender, Mocks},
|
mock_sender::{MockSender, Mocks},
|
||||||
rpc_config::RpcAccountInfoConfig,
|
rpc_config::RpcAccountInfoConfig,
|
||||||
rpc_config::{
|
rpc_config::*,
|
||||||
RpcBlockConfig, RpcEpochConfig, RpcLargestAccountsConfig, RpcProgramAccountsConfig,
|
|
||||||
RpcRequestAirdropConfig, RpcSendTransactionConfig, RpcSignaturesForAddressConfig,
|
|
||||||
RpcSimulateTransactionConfig, RpcTokenAccountsFilter, RpcTransactionConfig,
|
|
||||||
},
|
|
||||||
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData, TokenAccountsFilter},
|
rpc_request::{RpcError, RpcRequest, RpcResponseErrorData, TokenAccountsFilter},
|
||||||
rpc_response::*,
|
rpc_response::*,
|
||||||
rpc_sender::RpcSender,
|
rpc_sender::RpcSender,
|
||||||
|
@ -880,7 +876,7 @@ impl RpcClient {
|
||||||
&self,
|
&self,
|
||||||
slot: Option<Slot>,
|
slot: Option<Slot>,
|
||||||
) -> ClientResult<Option<RpcLeaderSchedule>> {
|
) -> ClientResult<Option<RpcLeaderSchedule>> {
|
||||||
self.get_leader_schedule_with_commitment(slot, self.commitment_config)
|
self.get_leader_schedule_with_config(slot, RpcLeaderScheduleConfig::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_leader_schedule_with_commitment(
|
pub fn get_leader_schedule_with_commitment(
|
||||||
|
@ -890,10 +886,24 @@ impl RpcClient {
|
||||||
) -> ClientResult<Option<RpcLeaderSchedule>> {
|
) -> ClientResult<Option<RpcLeaderSchedule>> {
|
||||||
self.send(
|
self.send(
|
||||||
RpcRequest::GetLeaderSchedule,
|
RpcRequest::GetLeaderSchedule,
|
||||||
json!([slot, self.maybe_map_commitment(commitment_config)?]),
|
json!([
|
||||||
|
slot,
|
||||||
|
RpcLeaderScheduleConfig {
|
||||||
|
commitment: Some(self.maybe_map_commitment(commitment_config)?),
|
||||||
|
..RpcLeaderScheduleConfig::default()
|
||||||
|
}
|
||||||
|
]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_leader_schedule_with_config(
|
||||||
|
&self,
|
||||||
|
slot: Option<Slot>,
|
||||||
|
config: RpcLeaderScheduleConfig,
|
||||||
|
) -> ClientResult<Option<RpcLeaderSchedule>> {
|
||||||
|
self.send(RpcRequest::GetLeaderSchedule, json!([slot, config]))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_epoch_schedule(&self) -> ClientResult<EpochSchedule> {
|
pub fn get_epoch_schedule(&self) -> ClientResult<EpochSchedule> {
|
||||||
self.send(RpcRequest::GetEpochSchedule, Value::Null)
|
self.send(RpcRequest::GetEpochSchedule, Value::Null)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,14 @@ pub struct RpcRequestAirdropConfig {
|
||||||
pub commitment: Option<CommitmentConfig>,
|
pub commitment: Option<CommitmentConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct RpcLeaderScheduleConfig {
|
||||||
|
pub identity: Option<String>, // validator identity, as a base-58 encoded string
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub commitment: Option<CommitmentConfig>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub enum RpcLargestAccountsFilter {
|
pub enum RpcLargestAccountsFilter {
|
||||||
|
|
|
@ -254,10 +254,10 @@ pub struct RpcVoteAccountStatus {
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct RpcVoteAccountInfo {
|
pub struct RpcVoteAccountInfo {
|
||||||
/// Vote account pubkey as base-58 encoded string
|
/// Vote account address, as base-58 encoded string
|
||||||
pub vote_pubkey: String,
|
pub vote_pubkey: String,
|
||||||
|
|
||||||
/// The pubkey of the node that votes using this account
|
/// The validator identity, as base-58 encoded string
|
||||||
pub node_pubkey: String,
|
pub node_pubkey: String,
|
||||||
|
|
||||||
/// The current stake, in lamports, delegated to this vote account
|
/// The current stake, in lamports, delegated to this vote account
|
||||||
|
|
|
@ -2110,7 +2110,7 @@ pub mod rpc_minimal {
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
slot: Option<Slot>,
|
slot: Option<Slot>,
|
||||||
commitment: Option<CommitmentConfig>,
|
config: Option<RpcLeaderScheduleConfig>,
|
||||||
) -> Result<Option<RpcLeaderSchedule>>;
|
) -> Result<Option<RpcLeaderSchedule>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2215,9 +2215,15 @@ pub mod rpc_minimal {
|
||||||
&self,
|
&self,
|
||||||
meta: Self::Metadata,
|
meta: Self::Metadata,
|
||||||
slot: Option<Slot>,
|
slot: Option<Slot>,
|
||||||
commitment: Option<CommitmentConfig>,
|
config: Option<RpcLeaderScheduleConfig>,
|
||||||
) -> Result<Option<RpcLeaderSchedule>> {
|
) -> Result<Option<RpcLeaderSchedule>> {
|
||||||
let bank = meta.bank(commitment);
|
let config = config.unwrap_or_default();
|
||||||
|
|
||||||
|
if let Some(ref identity) = config.identity {
|
||||||
|
let _ = verify_pubkey(identity)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let bank = meta.bank(config.commitment);
|
||||||
let slot = slot.unwrap_or_else(|| bank.slot());
|
let slot = slot.unwrap_or_else(|| bank.slot());
|
||||||
let epoch = bank.epoch_schedule().get_epoch(slot);
|
let epoch = bank.epoch_schedule().get_epoch(slot);
|
||||||
|
|
||||||
|
@ -2227,9 +2233,14 @@ pub mod rpc_minimal {
|
||||||
.leader_schedule_cache
|
.leader_schedule_cache
|
||||||
.get_epoch_leader_schedule(epoch)
|
.get_epoch_leader_schedule(epoch)
|
||||||
.map(|leader_schedule| {
|
.map(|leader_schedule| {
|
||||||
solana_ledger::leader_schedule_utils::leader_schedule_by_identity(
|
let mut schedule_by_identity =
|
||||||
leader_schedule.get_slot_leaders().iter().enumerate(),
|
solana_ledger::leader_schedule_utils::leader_schedule_by_identity(
|
||||||
)
|
leader_schedule.get_slot_leaders().iter().enumerate(),
|
||||||
|
);
|
||||||
|
if let Some(identity) = config.identity {
|
||||||
|
schedule_by_identity.retain(|k, _| *k == identity);
|
||||||
|
}
|
||||||
|
schedule_by_identity
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4235,6 +4246,10 @@ pub mod tests {
|
||||||
for req in [
|
for req in [
|
||||||
r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [0]}"#,
|
r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [0]}"#,
|
||||||
r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule"}"#,
|
r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule"}"#,
|
||||||
|
&format!(
|
||||||
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [null, {{ "identity": "{}" }}]}}"#,
|
||||||
|
bank.collector_id().to_string()
|
||||||
|
),
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
{
|
{
|
||||||
|
@ -4267,7 +4282,7 @@ pub mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
let req = r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [42424242]}"#;
|
let req = r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [42424242]}"#;
|
||||||
let rep = io.handle_request_sync(&req, meta);
|
let rep = io.handle_request_sync(&req, meta.clone());
|
||||||
let res: Response = serde_json::from_str(&rep.expect("actual response"))
|
let res: Response = serde_json::from_str(&rep.expect("actual response"))
|
||||||
.expect("actual response deserialization");
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
@ -4281,6 +4296,27 @@ pub mod tests {
|
||||||
panic!("Expected single response");
|
panic!("Expected single response");
|
||||||
};
|
};
|
||||||
assert_eq!(schedule, None);
|
assert_eq!(schedule, None);
|
||||||
|
|
||||||
|
// `bob` is not in the leader schedule, look for an empty response
|
||||||
|
let req = format!(
|
||||||
|
r#"{{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [null, {{ "identity": "{}"}}]}}"#,
|
||||||
|
bob_pubkey
|
||||||
|
);
|
||||||
|
|
||||||
|
let rep = io.handle_request_sync(&req, meta);
|
||||||
|
let res: Response = serde_json::from_str(&rep.expect("actual response"))
|
||||||
|
.expect("actual response deserialization");
|
||||||
|
|
||||||
|
let schedule: Option<RpcLeaderSchedule> = if let Response::Single(res) = res {
|
||||||
|
if let Output::Success(res) = res {
|
||||||
|
serde_json::from_value(res.result).unwrap()
|
||||||
|
} else {
|
||||||
|
panic!("Expected success");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Expected single response");
|
||||||
|
};
|
||||||
|
assert_eq!(schedule, Some(HashMap::default()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1366,14 +1366,17 @@ Returns the leader schedule for an epoch
|
||||||
|
|
||||||
#### Parameters:
|
#### Parameters:
|
||||||
|
|
||||||
- `<u64>` - (optional) Fetch the leader schedule for the epoch that corresponds to the provided slot. If unspecified, the leader schedule for the current epoch is fetched
|
- `<u64>` - (optional) Fetch the leader schedule for the epoch that corresponds to the provided slot.
|
||||||
- `<object>` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
If unspecified, the leader schedule for the current epoch is fetched
|
||||||
|
- `<object>` - (optional) Configuration object containing the following field:
|
||||||
|
- (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)
|
||||||
|
- (optional) `identity: <string>` - Only return results for this validator identity (base-58 encoded)
|
||||||
|
|
||||||
#### Results:
|
#### Results:
|
||||||
|
|
||||||
- `<null>` - if requested epoch is not found
|
- `<null>` - if requested epoch is not found
|
||||||
- `<object>` - otherwise, the result field will be a dictionary of leader public keys
|
- `<object>` - otherwise, the result field will be a dictionary of validator identities,
|
||||||
\(as base-58 encoded strings\) and their corresponding leader slot indices as values
|
as base-58 encoded strings, and their corresponding leader slot indices as values
|
||||||
(indices are relative to the first slot in the requested epoch)
|
(indices are relative to the first slot in the requested epoch)
|
||||||
|
|
||||||
#### Example:
|
#### Example:
|
||||||
|
@ -1396,6 +1399,36 @@ Result:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Example:
|
||||||
|
|
||||||
|
Request:
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8899 -X POST -H "Content-Type: application/json" -d '
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "getLeaderSchedule",
|
||||||
|
"params": [
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
"identity": "4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
'
|
||||||
|
```
|
||||||
|
|
||||||
|
Result:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"jsonrpc":"2.0",
|
||||||
|
"result":{
|
||||||
|
"4Qkev8aNZcqFNSRhQzwyLMFSsi94jHqE8WNVTJzTP99F":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63]
|
||||||
|
},
|
||||||
|
"id":1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### getMaxRetransmitSlot
|
### getMaxRetransmitSlot
|
||||||
|
|
||||||
Get the max slot seen from retransmit stage.
|
Get the max slot seen from retransmit stage.
|
||||||
|
@ -2820,8 +2853,8 @@ Returns the account info and associated stake for all the voting accounts in the
|
||||||
|
|
||||||
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 public key, as base-58 encoded string
|
- `votePubkey: <string>` - Vote account address, as base-58 encoded string
|
||||||
- `nodePubkey: <string>` - Node public key, as base-58 encoded string
|
- `nodePubkey: <string>` - Validator identity, as base-58 encoded string
|
||||||
- `activatedStake: <u64>` - the stake, in lamports, delegated to this vote account and active in this epoch
|
- `activatedStake: <u64>` - the stake, in lamports, delegated to this vote account and active in this epoch
|
||||||
- `epochVoteAccount: <bool>` - bool, whether the vote account is staked for this epoch
|
- `epochVoteAccount: <bool>` - bool, whether the vote account is staked for this epoch
|
||||||
- `commission: <number>`, percentage (0-100) of rewards payout owed to the vote account
|
- `commission: <number>`, percentage (0-100) of rewards payout owed to the vote account
|
||||||
|
|
|
@ -16,7 +16,10 @@ use {
|
||||||
},
|
},
|
||||||
keypair::SKIP_SEED_PHRASE_VALIDATION_ARG,
|
keypair::SKIP_SEED_PHRASE_VALIDATION_ARG,
|
||||||
},
|
},
|
||||||
solana_client::{rpc_client::RpcClient, rpc_request::MAX_MULTIPLE_ACCOUNTS},
|
solana_client::{
|
||||||
|
rpc_client::RpcClient, rpc_config::RpcLeaderScheduleConfig,
|
||||||
|
rpc_request::MAX_MULTIPLE_ACCOUNTS,
|
||||||
|
},
|
||||||
solana_core::ledger_cleanup_service::{
|
solana_core::ledger_cleanup_service::{
|
||||||
DEFAULT_MAX_LEDGER_SHREDS, DEFAULT_MIN_MAX_LEDGER_SHREDS,
|
DEFAULT_MAX_LEDGER_SHREDS, DEFAULT_MIN_MAX_LEDGER_SHREDS,
|
||||||
},
|
},
|
||||||
|
@ -154,7 +157,13 @@ fn wait_for_restart_window(
|
||||||
));
|
));
|
||||||
let first_slot_in_epoch = epoch_info.absolute_slot - epoch_info.slot_index;
|
let first_slot_in_epoch = epoch_info.absolute_slot - epoch_info.slot_index;
|
||||||
leader_schedule = rpc_client
|
leader_schedule = rpc_client
|
||||||
.get_leader_schedule(Some(first_slot_in_epoch))?
|
.get_leader_schedule_with_config(
|
||||||
|
Some(first_slot_in_epoch),
|
||||||
|
RpcLeaderScheduleConfig {
|
||||||
|
identity: Some(identity.to_string()),
|
||||||
|
..RpcLeaderScheduleConfig::default()
|
||||||
|
},
|
||||||
|
)?
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
format!(
|
format!(
|
||||||
"Unable to get leader schedule from slot {}",
|
"Unable to get leader schedule from slot {}",
|
||||||
|
|
Loading…
Reference in New Issue