Skip to content
This repository was archived by the owner on Jan 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions book/src/api-reference/jsonrpc-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,15 +373,16 @@ curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "m

### getLeaderSchedule

Returns the leader schedule for the current epoch
Returns the leader schedule for an epoch

#### Parameters:

* `slot` - (optional) Fetch the leader schedule for the epoch that corresponds to the provided slot. If unspecified, the leader schedule for the current epoch is fetch
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"fetched"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I'll scope this up in the follow-up work I'm doing now

* `object` - (optional) [Commitment](jsonrpc-api.md#configuring-state-commitment)

#### Results:

The result field will be an array of leader public keys \(as base-58 encoded strings\) for each slot in the current epoch
The result field will be an array of leader public keys \(as base-58 encoded strings\) for each slot in the epoch

#### Example:

Expand Down
33 changes: 33 additions & 0 deletions client/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,39 @@ impl RpcClient {
})
}

pub fn get_leader_schedule(&self, slot: Option<Slot>) -> io::Result<Option<Vec<String>>> {
self.get_leader_schedule_with_commitment(slot, CommitmentConfig::default())
}

pub fn get_leader_schedule_with_commitment(
&self,
slot: Option<Slot>,
commitment_config: CommitmentConfig,
) -> io::Result<Option<Vec<String>>> {
let params = slot.map(|slot| json!(slot));
let response = self
.client
.send(
&RpcRequest::GetLeaderSchedule,
params,
0,
commitment_config.ok(),
)
.map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetLeaderSchedule request failure: {:?}", err),
)
})?;

serde_json::from_value(response).map_err(|err| {
io::Error::new(
io::ErrorKind::Other,
format!("GetLeaderSchedule failure: {}", err),
)
})
}

pub fn get_epoch_schedule(&self) -> io::Result<EpochSchedule> {
let response = self
.client
Expand Down
2 changes: 2 additions & 0 deletions client/src/rpc_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ pub enum RpcRequest {
GetEpochSchedule,
GetGenesisHash,
GetInflation,
GetLeaderSchedule,
GetNumBlocksSinceSignatureConfirmation,
GetProgramAccounts,
GetRecentBlockhash,
Expand Down Expand Up @@ -161,6 +162,7 @@ impl RpcRequest {
RpcRequest::GetEpochSchedule => "getEpochSchedule",
RpcRequest::GetGenesisHash => "getGenesisHash",
RpcRequest::GetInflation => "getInflation",
RpcRequest::GetLeaderSchedule => "getLeaderSchedule",
RpcRequest::GetNumBlocksSinceSignatureConfirmation => {
"getNumBlocksSinceSignatureConfirmation"
}
Expand Down
62 changes: 59 additions & 3 deletions core/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ pub trait RpcSol {
fn get_block_commitment(
&self,
meta: Self::Metadata,
block: u64,
block: Slot,
) -> Result<(Option<BlockCommitment>, u64)>;

#[rpc(meta, name = "getGenesisHash")]
Expand All @@ -429,6 +429,7 @@ pub trait RpcSol {
fn get_leader_schedule(
&self,
meta: Self::Metadata,
slot: Option<Slot>,
commitment: Option<CommitmentConfig>,
) -> Result<Option<Vec<String>>>;

Expand Down Expand Up @@ -679,8 +680,9 @@ impl RpcSol for RpcSolImpl {
) -> Result<RpcEpochInfo> {
let bank = meta.request_processor.read().unwrap().bank(commitment);
let epoch_schedule = bank.epoch_schedule();
let (epoch, slot_index) = epoch_schedule.get_epoch_and_slot_index(bank.slot());

let slot = bank.slot();
let (epoch, slot_index) = epoch_schedule.get_epoch_and_slot_index(slot);
Ok(RpcEpochInfo {
epoch,
slot_index,
Expand Down Expand Up @@ -709,11 +711,14 @@ impl RpcSol for RpcSolImpl {
fn get_leader_schedule(
&self,
meta: Self::Metadata,
slot: Option<Slot>,
commitment: Option<CommitmentConfig>,
) -> Result<Option<Vec<String>>> {
let bank = meta.request_processor.read().unwrap().bank(commitment);
let slot = slot.unwrap_or_else(|| bank.slot());
let epoch = bank.epoch_schedule().get_epoch(slot);
Ok(
solana_ledger::leader_schedule_utils::leader_schedule(bank.epoch(), &bank).map(
solana_ledger::leader_schedule_utils::leader_schedule(epoch, &bank).map(
|leader_schedule| {
leader_schedule
.get_slot_leaders()
Expand Down Expand Up @@ -1374,6 +1379,57 @@ pub mod tests {
assert_eq!(epoch_schedule, *bank.epoch_schedule());
}

#[test]
fn test_rpc_get_leader_schedule() {
let bob_pubkey = Pubkey::new_rand();
let RpcHandler { io, meta, bank, .. } = start_rpc_handler_with_tx(&bob_pubkey);

for req in [
r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [0]}"#,
r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule"}"#,
]
.iter()
{
let rep = io.handle_request_sync(&req, meta.clone());
let res: Response = serde_json::from_str(&rep.expect("actual response"))
.expect("actual response deserialization");

let schedule: Option<Vec<String>> = if let Response::Single(res) = res {
if let Output::Success(res) = res {
serde_json::from_value(res.result).unwrap()
} else {
panic!("Expected success for {}", req);
}
} else {
panic!("Expected single response");
};

assert_eq!(
schedule.unwrap().len(),
solana_ledger::leader_schedule_utils::leader_schedule(bank.epoch(), &bank)
.unwrap()
.get_slot_leaders()
.len()
);
}

let req = r#"{"jsonrpc":"2.0","id":1,"method":"getLeaderSchedule", "params": [42424242]}"#;
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<Vec<String>> = 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, None);
}

#[test]
fn test_rpc_get_account_info() {
let bob_pubkey = Pubkey::new_rand();
Expand Down