in librabft-v2/src/pacemaker.rs [142:207]
fn update_pacemaker(
&mut self,
local_author: Context::Author,
epoch_id: EpochId,
record_store: &dyn RecordStore<Context>,
latest_query_all_time: NodeTime,
clock: NodeTime,
) -> PacemakerUpdateActions<Context> {
// Initialize actions with default values.
let mut actions = PacemakerUpdateActions::default();
// Compute the active round from the current record store.
let active_round = max(
record_store.highest_quorum_certificate_round(),
record_store.highest_timeout_certificate_round(),
) + 1;
// If the epoch changed or the active round was just updated..
if epoch_id > self.active_epoch
|| (epoch_id == self.active_epoch && active_round > self.active_round)
{
// .. store the new value
self.active_epoch = epoch_id;
self.active_round = active_round;
// .. start a timer
self.active_round_start_time = clock;
// .. compute the leader
self.active_leader = Some(Self::leader(record_store, active_round));
// .. compute the duration
self.active_round_duration = self.duration(record_store, active_round);
// .. synchronize with the leader.
if self.active_leader != Some(local_author) {
actions.should_send = self.active_leader.into_iter().collect();
}
}
// If we are the leader and have not proposed yet..
if self.active_leader == Some(local_author) && record_store.proposed_block(&*self) == None {
// .. propose a block on top of the highest QC that we know.
actions.should_propose_block = Some(record_store.highest_quorum_certificate_hash());
actions.should_broadcast = true;
// .. force an immediate update to vote on our own proposal.
actions.next_scheduled_update = clock;
}
if !record_store.has_timeout(local_author, active_round) {
let timeout_deadline = self.active_round_start_time + self.active_round_duration;
// If we have not created a timeout yet, check if the round has passed its maximal
// duration. Then, either broadcast a new timeout now, or schedule an update
// in the future.
if clock >= timeout_deadline {
actions.should_create_timeout = Some(active_round);
actions.should_broadcast = true;
} else {
actions.next_scheduled_update =
min(actions.next_scheduled_update, timeout_deadline);
}
} else {
// Otherwise, enforce frequent query-all actions if we stay too long on the same round.
let period = Duration((self.lambda * self.active_round_duration.0 as f64) as i64);
let mut query_all_deadline = latest_query_all_time + period;
if clock >= query_all_deadline {
actions.should_query_all = true;
query_all_deadline = clock + period;
}
actions.next_scheduled_update = min(actions.next_scheduled_update, query_all_deadline);
}
// Return all computed actions.
actions
}