From be947c4c8a4b727c8ef7c402115e6bb94c4c804d Mon Sep 17 00:00:00 2001 From: dapplion <35266934+dapplion@users.noreply.github.com> Date: Fri, 3 Jul 2026 11:27:51 +0200 Subject: [PATCH] FCR: drop vestigial bench root offset; fix FFG-sweep divergence doc - block_root_at hashed slot+1, a leftover from the from_low_u64_be(slot+1) form where the +1 kept genesis off the all-zero null-root sentinel. Hashing already yields a non-zero, prefix-varied root for slot 0, so hash the slot directly. - The cached-helpers divergence doc described the FFG sweep timing backwards: the epoch-boundary slot short-circuits the sweep; it runs in the slots after (the catch-up window), and at most once per get_latest_confirmed call now that it is memoized. --- consensus/fast_confirmation/benches/fcr_bench.rs | 2 +- consensus/fast_confirmation/src/lib.rs | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/consensus/fast_confirmation/benches/fcr_bench.rs b/consensus/fast_confirmation/benches/fcr_bench.rs index dbe109b4596..ae8f7a816ab 100644 --- a/consensus/fast_confirmation/benches/fcr_bench.rs +++ b/consensus/fast_confirmation/benches/fcr_bench.rs @@ -85,7 +85,7 @@ const SCENARIOS: &[Scenario] = &[ fn block_root_at(slot: u64) -> Hash256 { let mut preimage = [0u8; 16]; preimage[..8].copy_from_slice(b"fcr-root"); - preimage[8..].copy_from_slice(&(slot + 1).to_le_bytes()); + preimage[8..].copy_from_slice(&slot.to_le_bytes()); Hash256::from_slice(&hash_fixed(&preimage)) } diff --git a/consensus/fast_confirmation/src/lib.rs b/consensus/fast_confirmation/src/lib.rs index b4fed7304cd..c805a90f4d5 100644 --- a/consensus/fast_confirmation/src/lib.rs +++ b/consensus/fast_confirmation/src/lib.rs @@ -18,8 +18,9 @@ //! 2. **Cached spec helpers**: `is_one_confirmed` still reads as //! `support > compute_safety_threshold`, but `get_attestation_score` is backed by a //! precomputed chain score cache. The FFG predicates compute `compute_honest_ffg_support` -//! internally; their call sites are short-circuited, so the O(V) FFG sweep only runs near -//! epoch boundaries (and at most a couple of times) rather than every slot. +//! internally; their call sites short-circuit on most slots, so the O(V) sweep runs only in the +//! first slots after an epoch boundary (while the confirmed block still trails the previous +//! epoch), and at most once per `get_latest_confirmed` call (memoized), not every slot. //! //! 3. **Vote-root balance aggregation** (`optimizations::RootBalanceMap`): before ancestor //! lookups, validators with the same vote root (or root+epoch) are collapsed into one