fn update_pacemaker()

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
    }