Skip to main content

SlashingManager

Struct SlashingManager 

Source
pub struct SlashingManager { /* private fields */ }
Expand description

Top-level slashing lifecycle manager.

Traces to SPEC §7. Owns the processed-hash dedup map, the pending-slash book, and correlation- window counters — all of which land in subsequent DSL commits. For DSL-022 the manager holds only the current_epoch field, which is consumed when calling ValidatorEntry::slash_absolute.

Implementations§

Source§

impl SlashingManager

Source

pub fn new(current_epoch: u64) -> Self

New manager at current_epoch with the default MAX_PENDING_SLASHES book capacity. Further fields (pending book, processed map) start empty.

Source

pub fn with_book_capacity(current_epoch: u64, book_capacity: usize) -> Self

New manager with a caller-specified book capacity. Used by DSL-027 tests to exercise the PendingBookFull rejection.

Source

pub fn current_epoch(&self) -> u64

Current epoch accessor.

Source

pub fn book(&self) -> &PendingSlashBook

Immutable view of the pending-slash book.

Source

pub fn book_mut(&mut self) -> &mut PendingSlashBook

Mutable access to the pending-slash book.

Exposed for adjudication code (DSL-064..070) that needs to transition pending statuses to Reverted/ChallengeOpen outside the manager’s own submit_evidence + finalise_expired_slashes flow. Test suites also use this to inject pre-Reverted state for DSL-033 skip-path coverage.

Source

pub fn is_processed(&self, hash: &Bytes32) -> bool

true iff the evidence hash has been admitted. Used by DSL-026 (AlreadySlashed short-circuit) + tests.

Source

pub fn processed_epoch(&self, hash: &Bytes32) -> Option<u64>

Admission epoch recorded for a processed hash. None when the hash is not in the map.

Source

pub fn submit_evidence( &mut self, evidence: SlashingEvidence, validator_set: &mut dyn ValidatorView, effective_balances: &dyn EffectiveBalanceView, bond_escrow: &mut dyn BondEscrow, reward_payout: &mut dyn RewardPayout, proposer: &dyn ProposerView, network_id: &Bytes32, ) -> Result<SlashingResult, SlashingError>

Optimistic-admission entry point for validator slashing evidence.

Implements the base-slash branch of DSL-022. Traces to SPEC §7.3 step 5, §4.

§Pipeline (DSL-022 + DSL-023 scope)
  1. verify_evidence(...)VerifiedEvidence (DSL-011..020). Failure propagates as SlashingError.
  2. bond_escrow.lock(reporter_idx, REPORTER_BOND_MOJOS, BondTag::Reporter(evidence.hash())) (DSL-023). Lock failure collapses to SlashingError::BondLockFailed with no validator-side mutation — hence the ordering (bond BEFORE any slash_absolute).
  3. For each slashable index:
    • eff_bal = effective_balances.get(idx)
    • bps_term = eff_bal * base_bps / BPS_DENOMINATOR
    • floor_term = eff_bal / MIN_SLASHING_PENALTY_QUOTIENT
    • base_slash = max(bps_term, floor_term)
    • Skip iff validator_set.get(idx).is_slashed() OR index absent from the view (defensive tolerance per SPEC §7.3).
    • Otherwise validator_set.get_mut(idx).slash_absolute( base_slash, self.current_epoch).
    • Record a PerValidatorSlash.
  4. Return SlashingResult { per_validator, reporter_bond_escrowed: REPORTER_BOND_MOJOS, .. } — reward / pending-slash fields stay 0 / empty until DSL-024/025.
§Deviations from SPEC signature

SPEC §7.3 lists additional parameters (CollateralSlasher, RewardPayout, ProposerView) that are consumed by DSL-025. Signature grows incrementally — each future DSL adds the trait it needs.

Source

pub fn finalise_expired_slashes( &mut self, validator_set: &mut dyn ValidatorView, effective_balances: &dyn EffectiveBalanceView, bond_escrow: &mut dyn BondEscrow, total_active_balance: u64, ) -> Vec<FinalisationResult>

Transition every expired pending slash from Accepted/ChallengeOpen to Finalised { finalised_at_epoch: self.current_epoch } and emit one FinalisationResult per transition.

Implements DSL-029. Traces to SPEC §7.4 steps 1, 6–7.

§Scope (incremental)

This method currently covers the status transition + result emission only. Side effects land in subsequent DSLs:

  • DSL-030 populates per_validator_correlation_penalty.
  • DSL-031 populates reporter_bond_returned via bond_escrow.release.
  • DSL-032 populates exit_lock_until_epoch via validator_set.schedule_exit.
§Behaviour
  • Iterates book.expired_by(self.current_epoch) in ascending window-expiry order (stable across calls).
  • Skips pendings already in Reverted { .. } or Finalised { .. } (DSL-033).
  • Idempotent: calling twice in the same epoch yields an empty second result vec.
Source

pub fn submit_appeal( &mut self, appeal: &SlashAppeal, bond_escrow: &mut dyn BondEscrow, ) -> Result<(), SlashingError>

Submit an appeal against an existing pending slash.

Implements DSL-055. Traces to SPEC §6.1, §7.2.

§Scope (incremental)

First-cut pipeline stops at the UnknownEvidence precondition: if appeal.evidence_hash is not present in the pending-slash book the method returns SlashingError::UnknownEvidence(hex) WITHOUT touching the bond escrow. Later DSLs extend the pipeline:

  • DSL-056: WindowExpired
  • DSL-057: VariantMismatch
  • DSL-058: DuplicateAppeal
  • DSL-059: TooManyAttempts
  • DSL-060/061: SlashAlreadyReverted / SlashAlreadyFinalised
  • DSL-062: appellant-bond lock (FIRST bond-touching step)
  • DSL-063: PayloadTooLarge
  • DSL-064+: dispatch to per-ground verifiers + adjudicate
§Error ordering invariant

UnknownEvidence MUST be checked BEFORE any bond operation so a caller with a stale / misrouted appeal does not pay gas to lock collateral that would immediately need to be returned. Preserved by running the book lookup as the first statement — see the DSL-055 test suite’s test_dsl_055_bond_not_locked guard.

Source

pub fn set_epoch(&mut self, epoch: u64)

Advance the manager’s epoch. Consumers at the consensus layer call this at every epoch boundary AFTER running finalise_expired_slashes — keeps the current epoch in lock step with the chain. Test helper.

Source

pub fn mark_processed(&mut self, hash: Bytes32, epoch: u64)

Record a processed-evidence entry for persistence load or test fixtures.

submit_evidence does this implicitly on admission; this method is the public surface for replaying a persisted book or constructing a unit-test fixture without going through the full verify + bond-lock pipeline.

Source

pub fn mark_slashed_in_window( &mut self, epoch: u64, idx: u32, effective_balance: u64, )

Record a (epoch, validator_index) → effective_balance entry in the slashed-in-window cohort map. Companion to mark_processed; used by persistence load + tests.

Source

pub fn is_slashed_in_window(&self, epoch: u64, idx: u32) -> bool

Lookup for slashed_in_window — test helper so integration tests can verify DSL-129 rewind actually cleared an entry.

Source

pub fn pending(&self, hash: &Bytes32) -> Option<&PendingSlash>

Read-side lookup for a pending slash by evidence_hash.

Implements DSL-150. Convenience wrapper over self.book().get(hash) so callers don’t need to chain through book(). Returns None when the slash has been removed via book.remove or was never admitted.

Source

pub fn prune(&mut self, before_epoch: u64) -> usize

Prune processed + slashed_in_window entries older than before_epoch. Convenience alias for prune_processed_older_than per DSL-150 naming.

Does NOT touch book — pending slashes are removed via book.remove or finalise_expired_slashes which own the status-transition lifecycle.

Typical caller: DSL-127 run_epoch_boundary with before_epoch = current.saturating_sub(CORRELATION_WINDOW_EPOCHS).

Source

pub fn is_slashed(&self, idx: u32, validator_set: &dyn ValidatorView) -> bool

Delegate to ValidatorView::get(idx)?.is_slashed().

Implements DSL-149. Returns false for unknown indices (no panic) — matches DSL-136 ValidatorView::get out-of-range semantics. Read-only: does not mutate self or the validator set.

Source

pub fn rewind_on_reorg( &mut self, new_tip_epoch: u64, validator_set: &mut dyn ValidatorView, collateral: Option<&mut dyn CollateralSlasher>, bond_escrow: &mut dyn BondEscrow, ) -> Vec<Bytes32>

Rewind every pending slash whose submitted_at_epoch is STRICTLY greater than new_tip_epoch — the canonical fork-choice reorg response.

Implements DSL-129. Traces to SPEC §13.

§Side effects per rewound entry
  • ValidatorEntry::credit_stake(base_slash_amount) on each slashable validator.
  • ValidatorEntry::restore_status() on each.
  • CollateralSlasher::credit(validator_index, collateral_slashed) on each (when collateral present).
  • BondEscrow::release of the reporter bond at BondTag::Reporter(evidence_hash) — NOT forfeit. Reorg is not the reporter’s fault; the bond returns intact.
  • Entry removed from self.book, self.processed, and self.slashed_in_window.
§What it does NOT do
  • NO reporter penalty. DSL-069 applies a reporter penalty on SUSTAINED-APPEAL revert; a reorg is a consensus-layer signal that the original evidence was never canonical, so the reporter is not at fault.
  • NO appeal-history inspection. Any filed appeals on the rewound slash are discarded along with the slash itself.
§Returns

List of evidence_hash values that were rewound. Empty when no pending slashes are past the new tip.

Source

pub fn prune_processed_older_than(&mut self, cutoff_epoch: u64) -> usize

Prune processed-evidence map entries whose recorded epoch is strictly less than cutoff_epoch. Called by the DSL-127 run_epoch_boundary step 8 (last step) to bound memory of the AlreadySlashed dedup window.

Returns the number of entries removed. Also drops any slashed_in_window rows whose epoch is older than the cutoff — the cohort-sum window (DSL-030) is CORRELATION_WINDOW_EPOCHS wide so entries older than current_epoch - CORRELATION_WINDOW_EPOCHS can never contribute to a future finalisation.

Trait Implementations§

Source§

impl Clone for SlashingManager

Source§

fn clone(&self) -> SlashingManager

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for SlashingManager

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for SlashingManager

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows 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
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows 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
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .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
where Self: BorrowMut<B>, B: ?Sized,

Calls .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
where Self: AsRef<R>, R: ?Sized,

Calls .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
where Self: AsMut<R>, R: ?Sized,

Calls .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
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more