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 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. /// 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 epoch_slot_height = epoch_height * self.slots_per_epoch();
let expected = epoch_slot_height.saturating_sub(self.leader_schedule_slot_offset); let expected = epoch_slot_height.saturating_sub(self.leader_schedule_slot_offset);
self.parents() self.parents()
.into_iter() .into_iter()
.find(|bank| bank.slot_height() <= expected) .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 { fn leader_schedule(&self, epoch_height: u64) -> LeaderSchedule {
match self.leader_schedule_bank(epoch_height) { let (stakes, epoch_height) = match self.leader_schedule_stakes(epoch_height) {
None => LeaderSchedule::new_with_bank(self), None => (self.staked_nodes(), self.epoch_height()),
Some(bank) => LeaderSchedule::new_with_bank(&bank), 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 /// Return the leader for the slot at the slot_index and epoch_height returned
@ -1189,26 +1194,43 @@ mod tests {
} }
#[test] #[test]
fn test_leader_schedule_bank() { fn test_leader_schedule_stakes() {
let (genesis_block, _) = GenesisBlock::new(5); 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); 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 bank = Bank::new_from_parent(&Arc::new(bank));
let ticks_per_offset = bank.leader_schedule_slot_offset * bank.ticks_per_slot(); let ticks_per_offset = bank.leader_schedule_slot_offset * bank.ticks_per_slot();
register_ticks(&bank, ticks_per_offset); register_ticks(&bank, ticks_per_offset);
assert_eq!(bank.slot_height(), bank.leader_schedule_slot_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)); let bank = Bank::new_from_parent(&Arc::new(bank));
assert_eq!( assert_eq!(
bank.leader_schedule_bank(bank.epoch_height()) bank.leader_schedule_stakes(bank.epoch_height()).unwrap(),
.unwrap() expected,
.slot_height(),
slot_height
); );
} }
#[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] #[test]
fn test_interleaving_locks() { fn test_interleaving_locks() {
let (genesis_block, mint_keypair) = GenesisBlock::new(3); 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::distributions::{Distribution, WeightedIndex};
use rand::SeedableRng; use rand::SeedableRng;
use rand_chacha::ChaChaRng; use rand_chacha::ChaChaRng;
@ -20,13 +19,6 @@ impl LeaderSchedule {
let slot_leaders = (0..len).map(|_| ids[weighted_index.sample(rng)]).collect(); let slot_leaders = (0..len).map(|_| ids[weighted_index.sample(rng)]).collect();
Self { slot_leaders } 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 { impl Index<usize> for LeaderSchedule {
@ -39,9 +31,7 @@ impl Index<usize> for LeaderSchedule {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use solana_sdk::genesis_block::GenesisBlock;
use solana_sdk::signature::{Keypair, KeypairUtil}; use solana_sdk::signature::{Keypair, KeypairUtil};
use std::iter;
#[test] #[test]
fn test_leader_schedule_index() { fn test_leader_schedule_index() {
@ -72,15 +62,4 @@ mod tests {
// Check that the same schedule is reproducibly generated // Check that the same schedule is reproducibly generated
assert_eq!(leader_schedule, leader_schedule2); 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);
}
} }