Change range of leader scheduler to match current broadcasts (#1920)

This commit is contained in:
carllin 2018-12-03 00:10:43 -08:00 committed by GitHub
parent 1fbbf13ec9
commit 4ae58cc854
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 85 additions and 36 deletions

View File

@ -1300,7 +1300,7 @@ impl Bank {
self.leader_scheduler self.leader_scheduler
.read() .read()
.unwrap() .unwrap()
.get_scheduled_leader(self.tick_height()) .get_scheduled_leader(self.tick_height() + 1)
} }
pub fn tick_height(&self) -> u64 { pub fn tick_height(&self) -> u64 {

View File

@ -280,6 +280,9 @@ pub fn process_blob(
let slot = blob.read().unwrap().slot()?; let slot = blob.read().unwrap().slot()?;
let leader = leader_scheduler.get_leader_for_slot(slot); let leader = leader_scheduler.get_leader_for_slot(slot);
// TODO: Once the original leader signature is added to the blob, make sure that
// the blob was originally generated by the expected leader for this slot
if leader.is_none() { if leader.is_none() {
return Ok(()); return Ok(());
} }

View File

@ -306,8 +306,9 @@ impl Fullnode {
} else { } else {
let max_tick_height = { let max_tick_height = {
let ls_lock = bank.leader_scheduler.read().unwrap(); let ls_lock = bank.leader_scheduler.read().unwrap();
ls_lock.max_height_for_leader(bank.tick_height()) ls_lock.max_height_for_leader(bank.tick_height() + 1)
}; };
// Start in leader mode. // Start in leader mode.
let (tpu, entry_receiver, tpu_exit) = Tpu::new( let (tpu, entry_receiver, tpu_exit) = Tpu::new(
&bank, &bank,
@ -468,7 +469,7 @@ impl Fullnode {
let max_tick_height = { let max_tick_height = {
let ls_lock = self.bank.leader_scheduler.read().unwrap(); let ls_lock = self.bank.leader_scheduler.read().unwrap();
ls_lock.max_height_for_leader(tick_height) ls_lock.max_height_for_leader(tick_height + 1)
}; };
let (tpu, blob_receiver, tpu_exit) = Tpu::new( let (tpu, blob_receiver, tpu_exit) = Tpu::new(

View File

@ -155,7 +155,8 @@ impl LeaderScheduler {
} }
} }
pub fn is_leader_rotation_height(&self, height: u64) -> bool { // Returns true if the given height is the first tick of a slot
pub fn is_first_slot_tick(&self, height: u64) -> bool {
if self.use_only_bootstrap_leader { if self.use_only_bootstrap_leader {
return false; return false;
} }
@ -164,16 +165,19 @@ impl LeaderScheduler {
return false; return false;
} }
(height - self.bootstrap_height) % self.leader_rotation_interval == 0 (height - self.bootstrap_height) % self.leader_rotation_interval == 1
} }
pub fn count_until_next_leader_rotation(&self, height: u64) -> Option<u64> { // Returns the number of ticks until the last tick the current slot
pub fn num_ticks_left_in_slot(&self, height: u64) -> Option<u64> {
if self.use_only_bootstrap_leader { if self.use_only_bootstrap_leader {
return None; return None;
} }
if height < self.bootstrap_height { if height <= self.bootstrap_height {
Some(self.bootstrap_height - height) Some(self.bootstrap_height - height)
} else if (height - self.bootstrap_height) % self.leader_rotation_interval == 0 {
Some(0)
} else { } else {
Some( Some(
self.leader_rotation_interval self.leader_rotation_interval
@ -190,7 +194,7 @@ impl LeaderScheduler {
} }
let result = { let result = {
if height < self.bootstrap_height || self.leader_schedule.len() > 1 { if height <= self.bootstrap_height || self.leader_schedule.len() > 1 {
// Two cases to consider: // Two cases to consider:
// //
// 1) If height is less than the bootstrap height, then the current leader's // 1) If height is less than the bootstrap height, then the current leader's
@ -202,8 +206,8 @@ impl LeaderScheduler {
// to take over) // to take over)
// //
// Both above cases are calculated by the function: // Both above cases are calculated by the function:
// count_until_next_leader_rotation() + height // num_ticks_left_in_slot() + height
self.count_until_next_leader_rotation(height).expect( self.num_ticks_left_in_slot(height).expect(
"Should return some value when not using default implementation "Should return some value when not using default implementation
of LeaderScheduler", of LeaderScheduler",
) + height ) + height
@ -255,7 +259,7 @@ impl LeaderScheduler {
// This covers cases where the schedule isn't yet generated. // This covers cases where the schedule isn't yet generated.
if self.last_seed_height == None { if self.last_seed_height == None {
if height < self.bootstrap_height { if height <= self.bootstrap_height {
return Some((self.bootstrap_leader, 0)); return Some((self.bootstrap_leader, 0));
} else { } else {
// If there's been no schedule generated yet before we reach the end of the // If there's been no schedule generated yet before we reach the end of the
@ -265,16 +269,23 @@ impl LeaderScheduler {
} }
// If we have a schedule, then just check that we are within the bounds of that // If we have a schedule, then just check that we are within the bounds of that
// schedule [last_seed_height, last_seed_height + seed_rotation_interval). // schedule (last_seed_height, last_seed_height + seed_rotation_interval].
// Leaders outside of this bound are undefined. // Leaders outside of this bound are undefined.
let last_seed_height = self.last_seed_height.unwrap(); let last_seed_height = self.last_seed_height.unwrap();
if height >= last_seed_height + self.seed_rotation_interval || height < last_seed_height {
if height > last_seed_height + self.seed_rotation_interval || height <= last_seed_height {
return None; return None;
} }
// Find index into the leader_schedule that this PoH height maps to // Find index into the leader_schedule that this PoH height maps to. Note by the time
let leader_slot = (height - self.bootstrap_height) / self.leader_rotation_interval + 1; // we reach here, last_seed_height is not None, which implies:
let index = (height - last_seed_height) / self.leader_rotation_interval; //
// last_seed_height >= self.bootstrap_height
//
// Also we know from the recent range check that height > last_seed_height, so
// height - self.bootstrap_height >= 1, so the below logic is safe.
let leader_slot = (height - self.bootstrap_height - 1) / self.leader_rotation_interval + 1;
let index = (height - last_seed_height - 1) / self.leader_rotation_interval;
let validator_index = index as usize % self.leader_schedule.len(); let validator_index = index as usize % self.leader_schedule.len();
Some((self.leader_schedule[validator_index], leader_slot)) Some((self.leader_schedule[validator_index], leader_slot))
} }
@ -290,7 +301,7 @@ impl LeaderScheduler {
if slot_height == 0 { if slot_height == 0 {
0 0
} else { } else {
(slot_height - 1) * self.leader_rotation_interval + self.bootstrap_height (slot_height - 1) * self.leader_rotation_interval + self.bootstrap_height + 1
} }
} }
@ -327,7 +338,7 @@ impl LeaderScheduler {
} }
// Called every seed_rotation_interval entries, generates the leader schedule // Called every seed_rotation_interval entries, generates the leader schedule
// for the range of entries: [height, height + seed_rotation_interval) // for the range of entries: (height, height + seed_rotation_interval]
fn generate_schedule(&mut self, height: u64, bank: &Bank) { fn generate_schedule(&mut self, height: u64, bank: &Bank) {
assert!(height >= self.bootstrap_height); assert!(height >= self.bootstrap_height);
assert!((height - self.bootstrap_height) % self.seed_rotation_interval == 0); assert!((height - self.bootstrap_height) % self.seed_rotation_interval == 0);
@ -598,6 +609,10 @@ mod tests {
); );
assert_eq!( assert_eq!(
leader_scheduler.get_scheduled_leader(bootstrap_height), leader_scheduler.get_scheduled_leader(bootstrap_height),
Some((bootstrap_leader_id, 0))
);
assert_eq!(
leader_scheduler.get_scheduled_leader(bootstrap_height + 1),
None None
); );
@ -606,15 +621,15 @@ mod tests {
leader_scheduler.generate_schedule(bootstrap_height, &bank); leader_scheduler.generate_schedule(bootstrap_height, &bank);
// The leader outside of the newly generated schedule window: // The leader outside of the newly generated schedule window:
// [bootstrap_height, bootstrap_height + seed_rotation_interval) // (bootstrap_height, bootstrap_height + seed_rotation_interval]
// should be undefined // should be undefined
assert_eq!( assert_eq!(
leader_scheduler.get_scheduled_leader(bootstrap_height - 1), leader_scheduler.get_scheduled_leader(bootstrap_height),
None, None,
); );
assert_eq!( assert_eq!(
leader_scheduler.get_scheduled_leader(bootstrap_height + seed_rotation_interval), leader_scheduler.get_scheduled_leader(bootstrap_height + seed_rotation_interval + 1),
None, None,
); );
@ -627,7 +642,7 @@ mod tests {
let num_rounds = seed_rotation_interval / leader_rotation_interval; let num_rounds = seed_rotation_interval / leader_rotation_interval;
let mut start_leader_index = None; let mut start_leader_index = None;
for i in 0..num_rounds { for i in 0..num_rounds {
let begin_height = bootstrap_height + i * leader_rotation_interval; let begin_height = bootstrap_height + i * leader_rotation_interval + 1;
let (current_leader, slot) = leader_scheduler let (current_leader, slot) = leader_scheduler
.get_scheduled_leader(begin_height) .get_scheduled_leader(begin_height)
.expect("Expected a leader from scheduler"); .expect("Expected a leader from scheduler");
@ -649,7 +664,7 @@ mod tests {
validators[(start_leader_index.unwrap() + i as usize) % num_validators]; validators[(start_leader_index.unwrap() + i as usize) % num_validators];
assert_eq!(current_leader, expected_leader); assert_eq!(current_leader, expected_leader);
assert_eq!(slot, i + 1); assert_eq!(slot, i + 1);
// Check that the same leader is in power for the next leader_rotation_interval entries // Check that the same leader is in power for the next leader_rotation_interval - 1 entries
assert_eq!( assert_eq!(
leader_scheduler.get_scheduled_leader(begin_height + leader_rotation_interval - 1), leader_scheduler.get_scheduled_leader(begin_height + leader_rotation_interval - 1),
Some((current_leader, slot)) Some((current_leader, slot))
@ -1281,8 +1296,8 @@ mod tests {
.id; .id;
let initial_vote_height = 1; let initial_vote_height = 1;
// No schedule generated yet, so for all heights < bootstrap height, the // No schedule generated yet, so for all heights <= bootstrap height, the
// max height will be bootstrap leader // max height will be bootstrap height
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(0), leader_scheduler.max_height_for_leader(0),
Some(bootstrap_height) Some(bootstrap_height)
@ -1293,6 +1308,10 @@ mod tests {
); );
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height), leader_scheduler.max_height_for_leader(bootstrap_height),
Some(bootstrap_height)
);
assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + 1),
None None
); );
@ -1306,19 +1325,23 @@ mod tests {
leader_scheduler.generate_schedule(bootstrap_height, &bank); leader_scheduler.generate_schedule(bootstrap_height, &bank);
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height), leader_scheduler.max_height_for_leader(bootstrap_height),
Some(bootstrap_height + seed_rotation_interval) None
); );
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height - 1), leader_scheduler.max_height_for_leader(bootstrap_height - 1),
None None
); );
assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + 1),
Some(bootstrap_height + seed_rotation_interval)
);
leader_scheduler.generate_schedule(bootstrap_height + seed_rotation_interval, &bank); leader_scheduler.generate_schedule(bootstrap_height + seed_rotation_interval, &bank);
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval), leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval + 1),
Some(bootstrap_height + 2 * seed_rotation_interval) Some(bootstrap_height + 2 * seed_rotation_interval)
); );
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval - 1), leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval),
None None
); );
@ -1361,33 +1384,55 @@ mod tests {
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height), leader_scheduler.max_height_for_leader(bootstrap_height),
Some(bootstrap_height + leader_rotation_interval)
);
assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height - 1),
None None
); );
assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + 1),
Some(bootstrap_height + leader_rotation_interval)
);
assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + leader_rotation_interval - 1),
Some(bootstrap_height + leader_rotation_interval)
);
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + leader_rotation_interval), leader_scheduler.max_height_for_leader(bootstrap_height + leader_rotation_interval),
Some(bootstrap_height + leader_rotation_interval)
);
assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + leader_rotation_interval + 1),
Some(bootstrap_height + 2 * leader_rotation_interval) Some(bootstrap_height + 2 * leader_rotation_interval)
); );
assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval - 1),
Some(bootstrap_height + seed_rotation_interval),
);
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval), leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval),
Some(bootstrap_height + seed_rotation_interval),
);
assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval + 1),
None, None,
); );
// Generate another schedule
leader_scheduler.generate_schedule(bootstrap_height + seed_rotation_interval, &bank); leader_scheduler.generate_schedule(bootstrap_height + seed_rotation_interval, &bank);
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval), leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval),
Some(bootstrap_height + seed_rotation_interval + leader_rotation_interval)
);
assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval - 1),
None None
); );
assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + seed_rotation_interval + 1),
Some(bootstrap_height + seed_rotation_interval + leader_rotation_interval)
);
assert_eq!( assert_eq!(
leader_scheduler.max_height_for_leader(bootstrap_height + 2 * seed_rotation_interval), leader_scheduler.max_height_for_leader(bootstrap_height + 2 * seed_rotation_interval),
Some(bootstrap_height + 2 * seed_rotation_interval)
);
assert_eq!(
leader_scheduler
.max_height_for_leader(bootstrap_height + 2 * seed_rotation_interval + 1),
None None
); );
} }