Skip to content

tests: slashing-conservation property tests (staking)#454

Merged
adamkrellenstein merged 1 commit into
feat/ordering-rewardsfrom
test/staking-slashing-properties
Jun 3, 2026
Merged

tests: slashing-conservation property tests (staking)#454
adamkrellenstein merged 1 commit into
feat/ordering-rewardsfrom
test/staking-slashing-properties

Conversation

@adamkrellenstein

@adamkrellenstein adamkrellenstein commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Stacked on #440. Adds seeded-random conservation property tests over the slashing surface — slashing is security-critical and adversarially exposed (the audit found a real self-publication leak here), so it warrants invariants beyond the existing point tests.

Tests (mirror the existing distribute_ordering_reward_conserves pattern)

  • slash: burned + redistributable == slashed; burned is exactly the τ_slash 50% share; slashed == min(amount, stake) (saturates, never negative); stake drops by exactly slashed.
  • distribute_slash: Σ recipient stake == n·base + amount (exact, no dust).
  • slash_equivocation: λ_equiv=100% (full stake taken); burned + bounty == slashed; offender zeroed/ejected; self-publication ⇒ no bounty.

Design decisions

  • Seeded StdRng-style loop, not proptest — matches the existing *_over_random_cases template and the lite-harness style (fresh test_runtime_with_genesis per case, Signer::Core calls, post-state asserts). No new dependency.
  • Conservation checked via +/== only (e.g. burned + burned == slashed rather than a * or -), since the host Decimal operator surface used elsewhere in these tests is +/comparison.

Test-only; no contract change.


Note

Low Risk
Test-only additions to indexer contract tests; no production staking logic is modified.

Overview
Adds seeded-random conservation property tests in staking_slash.rs for the staking slashing APIs, using the same lite-runtime *_over_random_cases style as distribute_ordering_reward_conserves_over_random_cases (fresh genesis per seed, Decimal checked with +/== only).

slash: many cases assert slashed == min(amount, stake), burned + redistributable == slashed, 50% burn via burned + burned == slashed, and stake reduced by exactly slashed (including amounts above stake).

distribute_slash: asserts total recipient stake equals n·base + amount with no dust.

slash_equivocation: full-stake slash, burned + bounty == slashed, offender stake zeroed, and alternating self vs external publisher (no bounty on self-publication, positive bounty otherwise).

Test-only; no contract or runtime behavior changes.

Reviewed by Cursor Bugbot for commit 9faf910. Bugbot is set up for automated code reviews on this repo. Configure here.

Add seeded-random property tests over the slashing surface, mirroring the
existing distribute_ordering_reward_conserves pattern (fresh
test_runtime_with_genesis per case, core-context calls, post-state asserts):

- slash: burned + redistributable == slashed; burned is exactly the τ_slash 50%
  share; slashed == min(amount, stake) (saturates, never negative); stake drops
  by exactly slashed.
- distribute_slash: Σ recipient stake == n·base + amount (exact, no dust).
- slash_equivocation: λ_equiv=100% (full stake taken); burned + bounty ==
  slashed; offender zeroed; self-publication ⇒ no bounty.

Slashing is security-critical and adversarially exposed (the audit found a real
self-publication leak here), so it warrants conservation properties beyond the
point tests. Test-only; no contract change.
@adamkrellenstein
adamkrellenstein merged commit c6e0daf into feat/ordering-rewards Jun 3, 2026
8 checks passed
@adamkrellenstein
adamkrellenstein deleted the test/staking-slashing-properties branch June 3, 2026 13:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant