Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions consensus/fast_confirmation/src/balance_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,14 @@ impl BalanceSourceData {
self.effective_balances.get(val_idx).copied().unwrap_or(0)
}

pub(crate) fn unslashed_and_active_indices(&self) -> impl Iterator<Item = usize> + '_ {
pub(crate) fn unslashed_and_active_indices(&self) -> impl Iterator<Item = (usize, u64)> + '_ {
self.effective_balances
.iter()
.copied()
.enumerate()
.filter_map(|(i, balance)| {
(*balance > 0 && !self.slashed.get(i).copied().unwrap_or(false)).then_some(i)
(balance > 0 && !self.slashed.get(i).copied().unwrap_or(false))
.then_some((i, balance))
})
}

Expand Down
46 changes: 22 additions & 24 deletions consensus/fast_confirmation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -666,11 +666,6 @@ impl FastConfirmationRule {
// -----------------------------------------------------------------------

/// Spec: `get_block_support_between_slots`.
/// Counts weight of validators whose latest vote is for EXACTLY `block_root`
/// (not descendants) and whose committee assignment is in [start_slot, end_slot].
/// Equivalent to the spec's `participants` set, but iterates validators with latest
/// messages and tests committee membership with precomputed head assignments instead of
/// materializing all committee participants for the slot range.
fn get_block_support_between_slots(
&self,
balance_source: &BalanceSourceData,
Expand All @@ -680,10 +675,17 @@ impl FastConfirmationRule {
votes: &[VoteTracker],
equivocating_indices: &BTreeSet<u64>,
) -> Result<u64, Error> {
// Spec: sum effective balance of validators that:
// - Are assigned to attest in a committee in the `range(start_slot, end_slot + 1)`
// - Are active in `balance_source` tracked here as `balance > 0`
// - Are not slashed in `balance_source` tracked here as `slashed == false`
// - Do not belong to the `store.equivocating_indices` set
// - Their vote is for exactly `block_root`
let mut score = 0u64;
for (val_idx, vote) in votes.iter().enumerate() {
let balance = balance_source.unslashed_balance(val_idx);
// `balance > 0` is the spec's active-and-unslashed validator filter.
for (val_idx, balance) in balance_source.unslashed_and_active_indices() {
let Some(vote) = votes.get(val_idx) else {
continue;
};
if balance > 0
&& self
.head_assignments
Expand Down Expand Up @@ -892,9 +894,9 @@ impl FastConfirmationRule {
equivocating_indices: &BTreeSet<u64>,
) -> Result<u64, Error> {
let mut score = 0u64;
// Spec: Sum the balance of validators that:
// Spec: Sum the effective balance of validators that:
// - Belong to the `store.equivocating_indices` set
// - As assigned to attest in a committee in the `range(start_slot, end_slot + 1)`
// - Are assigned to attest in a committee in the `range(start_slot, end_slot + 1)`
// - Are active in `balance_source` tracked here as `balance > 0`
for &idx in equivocating_indices {
let idx = idx as usize;
Expand Down Expand Up @@ -988,33 +990,29 @@ impl FastConfirmationRule {
let mut balance_by_vote_checkpoint =
optimizations::RootBalanceMap::<(Hash256, Epoch)>::new();

// Spec: iterate `unslashed_and_active_indices`; zero roots mean no latest message.
for val_idx in self.head_balance_source.unslashed_and_active_indices() {
// Spec: sum the effective balance of validators that:
// - Are active the current epoch
// - Are not slashed in the current epoch
// - Don't belong in the equivocating_indices set
// - Have a vote for the current target
let mut score = 0u64;

for (val_idx, balance) in self.head_balance_source.unslashed_and_active_indices() {
let Some(vote) = votes.get(val_idx) else {
continue;
};
let vote_root = vote.current_root();
// Spec: get_latest_message_epoch(latest_messages[i]).
let vote_epoch = vote.current_slot().epoch(E::slots_per_epoch());

// vote_root.is_zero() == true means no latest message
if !vote_root.is_zero()
&& vote_epoch == target.epoch
&& !equivocating_indices.contains(&(val_idx as u64))
{
balance_by_vote_checkpoint.add(
(vote_root, vote_epoch),
self.head_balance_source.balance(val_idx),
)?;
balance_by_vote_checkpoint.add((vote_root, vote_epoch), balance)?;
}
}

// Spec: sum the effective balance of validators that:
// - Are active the current epoch
// - Are not slashed in the current epoch
// - Don't belong in the equivocating_indices set
// - Have a vote for the current target
let mut score = 0u64;

for ((vote_root, vote_epoch), balance) in balance_by_vote_checkpoint.iter() {
// Spec: get_checkpoint_for_block(store, latest_messages[i].root,
// get_latest_message_epoch(latest_messages[i])).
Expand Down
Loading