Change range of leader scheduler to match current broadcasts (#1920)
This commit is contained in:
parent
1fbbf13ec9
commit
4ae58cc854
|
@ -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 {
|
||||||
|
|
|
@ -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(());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue