Inline LeaderSchedule::new_from_bank()

Breaks circular dependency and offers more flexibility in bank's
usage.
This commit is contained in:
Greg Fitzgerald 2019-02-25 07:50:25 -07:00 committed by Grimes
parent aad0d90fdd
commit db899a2813
2 changed files with 37 additions and 36 deletions

View File

@ -684,22 +684,27 @@ impl Bank {
self.slots_per_epoch
}
/// Return the checkpointed bank that should be used to generate a leader schedule.
/// Return the checkpointed stakes that should be used to generate a leader schedule.
/// Return None if a sufficiently old bank checkpoint doesn't exist.
fn leader_schedule_bank(&self, epoch_height: u64) -> Option<Arc<Bank>> {
fn leader_schedule_stakes(&self, epoch_height: u64) -> Option<HashMap<Pubkey, u64>> {
let epoch_slot_height = epoch_height * self.slots_per_epoch();
let expected = epoch_slot_height.saturating_sub(self.leader_schedule_slot_offset);
self.parents()
.into_iter()
.find(|bank| bank.slot_height() <= expected)
.map(|bank| bank.staked_nodes())
}
/// Return the leader schedule for the current epoch.
/// Return the leader schedule for the given epoch.
fn leader_schedule(&self, epoch_height: u64) -> LeaderSchedule {
match self.leader_schedule_bank(epoch_height) {
None => LeaderSchedule::new_with_bank(self),
Some(bank) => LeaderSchedule::new_with_bank(&bank),
}
let (stakes, epoch_height) = match self.leader_schedule_stakes(epoch_height) {
None => (self.staked_nodes(), self.epoch_height()),
Some(stakes) => (stakes, epoch_height),
};
let mut seed = [0u8; 32];
seed[0..8].copy_from_slice(&epoch_height.to_le_bytes());
let stakes: Vec<_> = stakes.into_iter().collect();
LeaderSchedule::new(&stakes, seed, self.slots_per_epoch())
}
/// Return the leader for the slot at the slot_index and epoch_height returned
@ -1189,26 +1194,43 @@ mod tests {
}
#[test]
fn test_leader_schedule_bank() {
let (genesis_block, _) = GenesisBlock::new(5);
fn test_leader_schedule_stakes() {
let pubkey = Keypair::new().pubkey();
let bootstrap_tokens = 2;
let (genesis_block, _) = GenesisBlock::new_with_leader(2, pubkey, bootstrap_tokens);
let bank = Bank::new(&genesis_block);
assert!(bank.leader_schedule_bank(bank.epoch_height()).is_none());
assert!(bank.leader_schedule_stakes(bank.epoch_height()).is_none());
let bank = Bank::new_from_parent(&Arc::new(bank));
let ticks_per_offset = bank.leader_schedule_slot_offset * bank.ticks_per_slot();
register_ticks(&bank, ticks_per_offset);
assert_eq!(bank.slot_height(), bank.leader_schedule_slot_offset);
let slot_height = bank.slots_per_epoch() - bank.leader_schedule_slot_offset;
let mut expected = HashMap::new();
expected.insert(pubkey, bootstrap_tokens - 1);
let bank = Bank::new_from_parent(&Arc::new(bank));
assert_eq!(
bank.leader_schedule_bank(bank.epoch_height())
.unwrap()
.slot_height(),
slot_height
bank.leader_schedule_stakes(bank.epoch_height()).unwrap(),
expected,
);
}
#[test]
fn test_leader_schedule_basic() {
let pubkey = Keypair::new().pubkey();
let (genesis_block, _mint_keypair) = GenesisBlock::new_with_leader(2, pubkey, 2);
let bank = Bank::new(&genesis_block);
let ids_and_stakes: Vec<_> = bank.staked_nodes().into_iter().collect();
let mut seed = [0u8; 32];
seed[0..8].copy_from_slice(&bank.epoch_height().to_le_bytes());
let leader_schedule = LeaderSchedule::new(&ids_and_stakes, seed, bank.slots_per_epoch());
assert_eq!(leader_schedule[0], pubkey);
assert_eq!(leader_schedule[1], pubkey);
assert_eq!(leader_schedule[2], pubkey);
}
#[test]
fn test_interleaving_locks() {
let (genesis_block, mint_keypair) = GenesisBlock::new(3);

View File

@ -1,4 +1,3 @@
use crate::bank::Bank;
use rand::distributions::{Distribution, WeightedIndex};
use rand::SeedableRng;
use rand_chacha::ChaChaRng;
@ -20,13 +19,6 @@ impl LeaderSchedule {
let slot_leaders = (0..len).map(|_| ids[weighted_index.sample(rng)]).collect();
Self { slot_leaders }
}
pub fn new_with_bank(bank: &Bank) -> Self {
let id_and_stakes: Vec<_> = bank.staked_nodes().into_iter().collect();
let mut seed = [0u8; 32];
seed[0..8].copy_from_slice(&bank.epoch_height().to_le_bytes());
Self::new(&id_and_stakes, seed, bank.slots_per_epoch())
}
}
impl Index<usize> for LeaderSchedule {
@ -39,9 +31,7 @@ impl Index<usize> for LeaderSchedule {
#[cfg(test)]
mod tests {
use super::*;
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::signature::{Keypair, KeypairUtil};
use std::iter;
#[test]
fn test_leader_schedule_index() {
@ -72,15 +62,4 @@ mod tests {
// Check that the same schedule is reproducibly generated
assert_eq!(leader_schedule, leader_schedule2);
}
#[test]
fn test_leader_schedule_via_bank() {
let pubkey = Keypair::new().pubkey();
let (genesis_block, _mint_keypair) = GenesisBlock::new_with_leader(2, pubkey, 2);
let bank = Bank::new(&genesis_block);
let leader_schedule = LeaderSchedule::new_with_bank(&bank);
let len = bank.slots_per_epoch() as usize;
let expected: Vec<_> = iter::repeat(pubkey).take(len).collect();
assert_eq!(leader_schedule.slot_leaders, expected);
}
}