pub struct ParticipationTracker { /* private fields */ }Expand description
Per-validator two-epoch attestation-flag store.
Implements DSL-078 (+ DSL-079/080 in later commits). Traces to SPEC §8.2.
§Fields
current_epoch— flags accumulated during the in-flight epoch.previous_epoch— flags from the just-completed epoch. Read by reward / penalty delta computation (DSL-082..086).current_epoch_number— monotonically advancing epoch counter. Driven forward byrotate_epoch(DSL-080).
§Storage size
Both vecs are sized at construction to validator_count.
Out-of-range indices return
ParticipationError::IndexOutOfRange rather than panicking
— record_attestation is called with adversary-controllable
indices (attesters may be newly registered or slashed
between admission and record), and the tracker is expected
to degrade gracefully.
Implementations§
Source§impl ParticipationTracker
impl ParticipationTracker
Sourcepub fn new(validator_count: usize, initial_epoch: u64) -> Self
pub fn new(validator_count: usize, initial_epoch: u64) -> Self
New tracker sized for validator_count slots, starting
at initial_epoch. Both epoch vectors initialise to
ParticipationFlags::default() (all-zero).
Sourcepub fn current_epoch_number(&self) -> u64
pub fn current_epoch_number(&self) -> u64
Current epoch counter. Advanced by
rotate_epoch (DSL-080).
Sourcepub fn current_flags(&self, validator_index: u32) -> Option<ParticipationFlags>
pub fn current_flags(&self, validator_index: u32) -> Option<ParticipationFlags>
Flag bits accumulated for validator_index during the
current epoch. None when the index is out of range.
Sourcepub fn previous_flags(&self, validator_index: u32) -> Option<ParticipationFlags>
pub fn previous_flags(&self, validator_index: u32) -> Option<ParticipationFlags>
Flag bits from the previous (finalisable) epoch for
validator_index. None when the index is out of range.
Consumed by DSL-082/083 reward-delta math.
Sourcepub fn validator_count(&self) -> usize
pub fn validator_count(&self) -> usize
Number of validator slots the tracker can address.
attesting_indices with values >= validator_count
return IndexOutOfRange.
Sourcepub fn rotate_epoch(&mut self, new_epoch: u64, validator_count: usize)
pub fn rotate_epoch(&mut self, new_epoch: u64, validator_count: usize)
Advance to a new epoch: swap current → previous, reset
current to validator_count zero-initialised slots, and
update current_epoch_number.
Implements DSL-080. Traces to SPEC §8.2, §10.
§Ordering
swap(previous, current)— what was accumulated during the just-finished epoch moves intoprevious_epoch. DSL-082..086 reward / penalty math reads these bits.current.clear(); current.resize(validator_count, 0)— accept validator-set growth at the boundary. New validators that activated this epoch get zero flags.current_epoch_number = new_epoch.
§Shrinking validator set
If validator_count < old.len(), the trailing entries
are dropped. This is the correct behaviour for exited
validators — their previous-epoch flags are preserved
(in the just-swapped previous_epoch), only the current
-epoch slot is discarded.
§Previous-epoch sizing
previous_epoch keeps whatever length current had
before rotation. Downstream reward math reads
previous_flags(idx) via .get(idx).copied(), so
out-of-range reads return None rather than panicking.
Sourcepub fn rewind_on_reorg(
&mut self,
new_tip_epoch: u64,
validator_count: usize,
) -> u64
pub fn rewind_on_reorg( &mut self, new_tip_epoch: u64, validator_count: usize, ) -> u64
Rewind the tracker on fork-choice reorg.
Implements the participation leg of DSL-130
rewind_all_on_reorg. Drops both flag vectors and
reinstates new_tip_epoch as the current epoch with
zero-initialised flags.
Why zero-fill instead of restoring pre-reorg state: the
tracker does NOT retain historical snapshots (each
rotate_epoch overwrites in place). Post-rewind, flag
accumulation resumes fresh from the new canonical tip —
the reward-delta pass at the NEXT epoch boundary
observes no activity over the rewound span (conservative;
no false reward credits from a ghost chain). Also zero-
fills the previous_epoch slot so the first post-rewind
compute_flag_deltas cannot read ghost data.
Returns the number of epochs dropped
(old_current_epoch - new_tip_epoch, saturating at 0
when the tip is already current or ahead).
Sourcepub fn record_attestation(
&mut self,
_data: &AttestationData,
attesting_indices: &[u32],
flags: ParticipationFlags,
) -> Result<(), ParticipationError>
pub fn record_attestation( &mut self, _data: &AttestationData, attesting_indices: &[u32], flags: ParticipationFlags, ) -> Result<(), ParticipationError>
Record an attestation: apply flags to every entry in
attesting_indices via bit-OR into the current epoch’s
per-validator bucket.
Implements DSL-078.
§Errors
Returns ParticipationError::IndexOutOfRange(i) for the
FIRST offending index; later indices are not touched.
Structural non-ascending / duplicate checks land in
DSL-079 and run before this bit-OR pass in that cycle.
§Behaviour
- Bit-OR is additive.
record_attestation(.., TIMELY_SOURCE)followed byrecord_attestation(.., TIMELY_TARGET)on the same validator leaves both bits set. current_epoch_numberis NOT mutated — epoch advancement is the sole responsibility ofrotate_epoch(DSL-080).
Trait Implementations§
Source§impl Clone for ParticipationTracker
impl Clone for ParticipationTracker
Source§fn clone(&self) -> ParticipationTracker
fn clone(&self) -> ParticipationTracker
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for ParticipationTracker
impl RefUnwindSafe for ParticipationTracker
impl Send for ParticipationTracker
impl Sync for ParticipationTracker
impl Unpin for ParticipationTracker
impl UnsafeUnpin for ParticipationTracker
impl UnwindSafe for ParticipationTracker
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.