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
6 changes: 4 additions & 2 deletions book/src/api-reference/jsonrpc-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,9 @@ Returns the leader schedule for an epoch

#### Results:

The result field will be an array of leader public keys \(as base-58 encoded strings\) for each slot in the epoch
The result field will be a dictionary of leader public keys \(as base-58 encoded
strings\) and their corresponding leader slot indices as values (indices are to
the first slot in the requested epoch)

#### Example:

Expand All @@ -393,7 +395,7 @@ The result field will be an array of leader public keys \(as base-58 encoded str
curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getLeaderSchedule"}' http://localhost:8899

// Result
{"jsonrpc":"2.0","result":[...],"id":1}
{"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}
```

### getMinimumBalanceForRentExemption
Expand Down
9 changes: 6 additions & 3 deletions client/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use crate::{
generic_rpc_client_request::GenericRpcClientRequest,
mock_rpc_client_request::MockRpcClientRequest,
rpc_client_request::RpcClientRequest,
rpc_request::{RpcContactInfo, RpcEpochInfo, RpcRequest, RpcVersionInfo, RpcVoteAccountStatus},
rpc_request::{
RpcContactInfo, RpcEpochInfo, RpcLeaderSchedule, RpcRequest, RpcVersionInfo,
RpcVoteAccountStatus,
},
};
use bincode::serialize;
use log::*;
Expand Down Expand Up @@ -248,15 +251,15 @@ impl RpcClient {
})
}

pub fn get_leader_schedule(&self, slot: Option<Slot>) -> io::Result<Option<Vec<String>>> {
pub fn get_leader_schedule(&self, slot: Option<Slot>) -> io::Result<Option<RpcLeaderSchedule>> {
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>>> {
) -> io::Result<Option<RpcLeaderSchedule>> {
let params = slot.map(|slot| json!(slot));
let response = self
.client
Expand Down
5 changes: 4 additions & 1 deletion client/src/rpc_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use solana_sdk::{
hash::Hash,
transaction::{Result, Transaction},
};
use std::{error, fmt, io, net::SocketAddr};
use std::{collections::HashMap, error, fmt, io, net::SocketAddr};

pub type RpcResponseIn<T> = JsonResult<Response<T>>;
pub type RpcResponse<T> = io::Result<Response<T>>;
Expand Down Expand Up @@ -52,6 +52,9 @@ pub struct RpcContactInfo {
pub rpc: Option<SocketAddr>,
}

/// Map of leader base58 identity pubkeys to the slot indices relative to the first epoch slot
pub type RpcLeaderSchedule = HashMap<String, Vec<usize>>;

#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct RpcEpochInfo {
Expand Down
34 changes: 22 additions & 12 deletions core/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use bincode::serialize;
use jsonrpc_core::{Error, Metadata, Result};
use jsonrpc_derive::rpc;
use solana_client::rpc_request::{
Response, RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcResponseContext, RpcVersionInfo,
RpcVoteAccountInfo, RpcVoteAccountStatus,
Response, RpcConfirmedBlock, RpcContactInfo, RpcEpochInfo, RpcLeaderSchedule,
RpcResponseContext, RpcVersionInfo, RpcVoteAccountInfo, RpcVoteAccountStatus,
};
use solana_faucet::faucet::request_airdrop_transaction;
use solana_ledger::{bank_forks::BankForks, blocktree::Blocktree};
Expand Down Expand Up @@ -431,7 +431,7 @@ pub trait RpcSol {
meta: Self::Metadata,
slot: Option<Slot>,
commitment: Option<CommitmentConfig>,
) -> Result<Option<Vec<String>>>;
) -> Result<Option<RpcLeaderSchedule>>;

#[rpc(meta, name = "getRecentBlockhash")]
fn get_recent_blockhash(
Expand Down Expand Up @@ -713,18 +713,23 @@ impl RpcSol for RpcSolImpl {
meta: Self::Metadata,
slot: Option<Slot>,
commitment: Option<CommitmentConfig>,
) -> Result<Option<Vec<String>>> {
) -> Result<Option<RpcLeaderSchedule>> {
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(epoch, &bank).map(
|leader_schedule| {
leader_schedule
.get_slot_leaders()
.iter()
.map(|pubkey| pubkey.to_string())
.collect()
let mut map = HashMap::new();

for (slot_index, pubkey) in
leader_schedule.get_slot_leaders().iter().enumerate()
{
let pubkey = pubkey.to_string();
map.entry(pubkey).or_insert_with(|| vec![]).push(slot_index);
}
map
},
),
)
Expand Down Expand Up @@ -1394,7 +1399,7 @@ pub mod tests {
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 {
let schedule: Option<RpcLeaderSchedule> = if let Response::Single(res) = res {
if let Output::Success(res) = res {
serde_json::from_value(res.result).unwrap()
} else {
Expand All @@ -1403,9 +1408,14 @@ pub mod tests {
} else {
panic!("Expected single response");
};
let schedule = schedule.expect("leader schedule");

let bob_schedule = schedule
.get(&bank.collector_id().to_string())
.expect("leader not in the leader schedule");

assert_eq!(
schedule.unwrap().len(),
bob_schedule.len(),
solana_ledger::leader_schedule_utils::leader_schedule(bank.epoch(), &bank)
.unwrap()
.get_slot_leaders()
Expand All @@ -1418,7 +1428,7 @@ pub mod tests {
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 {
let schedule: Option<RpcLeaderSchedule> = if let Response::Single(res) = res {
if let Output::Success(res) = res {
serde_json::from_value(res.result).unwrap()
} else {
Expand Down