Use epoch_height to generate schedule instead of last_id

I had suggested the last_id, but that puts an unnecessary dependency
on LastIdsQueue. Using epoch height is pretty interesting in that
given the same set of stakers, you simply increment the seed once
per epoch.

Also, tighten up the LeaderSchedule code.
This commit is contained in:
Greg Fitzgerald
2019-02-25 07:23:21 -07:00
committed by Grimes
parent 72b4834446
commit aad0d90fdd

View File

@ -12,27 +12,20 @@ pub struct LeaderSchedule {
} }
impl LeaderSchedule { impl LeaderSchedule {
pub fn new(ids_and_stakes: &[(Pubkey, u64)], seed: &[u8; 32], len: u64) -> Self { // Note: passing in zero stakers will cause a panic.
let (pubkeys, stakes): (Vec<Pubkey>, Vec<u64>) = ids_and_stakes pub fn new(ids_and_stakes: &[(Pubkey, u64)], seed: [u8; 32], len: u64) -> Self {
.iter() let (ids, stakes): (Vec<_>, Vec<_>) = ids_and_stakes.iter().cloned().unzip();
.map(|&(ref id, ref stake)| (id, stake)) let rng = &mut ChaChaRng::from_seed(seed);
.unzip();
// Should have no zero weighted stakes
let mut rng = ChaChaRng::from_seed(*seed);
let weighted_index = WeightedIndex::new(stakes).unwrap(); let weighted_index = WeightedIndex::new(stakes).unwrap();
let slot_leaders = (0..len) let slot_leaders = (0..len).map(|_| ids[weighted_index.sample(rng)]).collect();
.map(|_| pubkeys[weighted_index.sample(&mut rng)])
.collect();
Self { slot_leaders } Self { slot_leaders }
} }
pub fn new_with_bank(bank: &Bank) -> Self { pub fn new_with_bank(bank: &Bank) -> Self {
let id_and_stakes: Vec<_> = bank.staked_nodes().into_iter().collect();
let mut seed = [0u8; 32]; let mut seed = [0u8; 32];
seed.copy_from_slice(bank.last_id().as_ref()); seed[0..8].copy_from_slice(&bank.epoch_height().to_le_bytes());
let stakes: Vec<_> = bank.staked_nodes().into_iter().collect(); Self::new(&id_and_stakes, seed, bank.slots_per_epoch())
Self::new(&stakes, &seed, bank.slots_per_epoch())
} }
} }
@ -73,8 +66,8 @@ mod tests {
let mut seed_bytes = [0u8; 32]; let mut seed_bytes = [0u8; 32];
seed_bytes.copy_from_slice(seed.as_ref()); seed_bytes.copy_from_slice(seed.as_ref());
let len = num_keys * 10; let len = num_keys * 10;
let leader_schedule = LeaderSchedule::new(&stakes, &seed_bytes, len); let leader_schedule = LeaderSchedule::new(&stakes, seed_bytes, len);
let leader_schedule2 = LeaderSchedule::new(&stakes, &seed_bytes, len); let leader_schedule2 = LeaderSchedule::new(&stakes, seed_bytes, len);
assert_eq!(leader_schedule.slot_leaders.len() as u64, len); assert_eq!(leader_schedule.slot_leaders.len() as u64, len);
// 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);