Problem Statement / Feature Objective
The validator balance tracker deducts penalties (slashing, inactivity leaks) as score = balance - penalty. When the penalty exceeds the current balance (e.g., a validator with 1 ETH balance receives a slashable offense penalty of 1.5 ETH), the subtraction underflows using saturating arithmetic that silently clamps to zero without recording the excess as a debt. This allows the validator to re-activate after the epoch boundary with a zero balance, bypassing the ejection threshold check.
Technical Invariants & Bounds
- Effective balance: 1 ETH = 1e9 Gwei (u64).
- Slashing penalty: 1/32 of effective balance (whistleblower) + 1/32 (correlation).
- Inactivity leak penalty: proportional to (epochs_since_finality)^2.
- u64 saturating sub: balance.saturating_sub(penalty) => 0 if penalty > balance.
- Ejection threshold: 16 ETH minimum; validators below this are ejected.
- A validator with underflow to 0 can remain active for one more epoch.
Codebase Navigation Guide
- src/validator/balance-tracker.rs - apply_penalty() and apply_reward().
- src/validator/validator-set.rs - update_effective_balances() and eject_validators().
- src/slashing/penalty-calculator.rs - compute_slashing_penalty() and compute_inactivity_penalty().
- tests/validator/balance_underflow_test.rs - penalty edge case tests.
Implementation Blueprint
- In src/validator/balance-tracker.rs, change apply_penalty() from saturating_sub to checked_sub. If penalty > balance, return an InsufficientBalance error instead of silently clamping.
- When InsufficientBalance is returned, the slashing engine should mark the validator for forced ejection and record a debt in a separate Debts mapping.
- In eject_validators(), treat any validator with an outstanding debt as eligible for immediate ejection regardless of effective balance.
- Add a test: validator with 1 ETH balance receives a 1.5 ETH penalty; assert the validator is ejected in the same epoch.
- Add a property test that randomizes balances and penalties and asserts effective_balance never exceeds MAX_EFFECTIVE_BALANCE after processing.
Problem Statement / Feature Objective
The validator balance tracker deducts penalties (slashing, inactivity leaks) as score = balance - penalty. When the penalty exceeds the current balance (e.g., a validator with 1 ETH balance receives a slashable offense penalty of 1.5 ETH), the subtraction underflows using saturating arithmetic that silently clamps to zero without recording the excess as a debt. This allows the validator to re-activate after the epoch boundary with a zero balance, bypassing the ejection threshold check.
Technical Invariants & Bounds
Codebase Navigation Guide
Implementation Blueprint