Speed up getLeaderSchedule RPC call by reducing pubkey duplication

This commit is contained in:
Michael Vines 2019-12-18 12:42:58 -07:00
parent 6a9005645a
commit bd22b641b3
4 changed files with 36 additions and 18 deletions

View File

@ -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:
@ -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

View File

@ -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::*;
@ -248,7 +251,7 @@ 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())
}
@ -256,7 +259,7 @@ impl RpcClient {
&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

View File

@ -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>>;
@ -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 {

View File

@ -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};
@ -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(
@ -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
},
),
)
@ -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 {
@ -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()
@ -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 {