Skip to content

fix(proposer): canonical-descendant gate on rejected-buffer recovery exemption#497

Merged
spreston8 merged 1 commit intorust/stagingfrom
fix/recovery-repeat-deploy-misfire
May 2, 2026
Merged

fix(proposer): canonical-descendant gate on rejected-buffer recovery exemption#497
spreston8 merged 1 commit intorust/stagingfrom
fix/recovery-repeat-deploy-misfire

Conversation

@spreston8
Copy link
Copy Markdown
Collaborator

@spreston8 spreston8 commented May 2, 2026

Summary

prepare_user_deploys exempts deploys in rejected_in_scope from the in-scope filter so genuinely rejected deploys can be re-proposed. Without a canonical-descendant gate, the exemption also fires when the rejection sits in a non-canonical sibling while the deploy's effects are already in canonical state — producing a recovery block that downstream validators correctly flag as InvalidRepeatDeploy (the post-55cbbb06 defense). On FTT=0 shards this triggers mutual slashing and a permanent split.

The fix mirrors the validator-side repeat_deploy gate at the proposer: when a candidate sig is in both deploys_in_scope and rejected_in_scope, resolve its finalization status via resolve_batch and decline the exemption when status is Finalized. Resolver failure declines conservatively for the cycle (sigs retry next cycle).

Tests

  • repeat_deploy_correctly_rejects_stale_recovery_when_d_is_finalized — validator-side defense regression. Passes pre- and post-fix; locks in Validate::repeat_deploy behavior so future changes can't silently regress it.
  • proposer_must_skip_recovery_when_deploy_is_canonically_finalized — RED pre-fix, GREEN post-fix. Verified by stash/restore RED→GREEN sanity check.

Verification

  • cargo test -p casper --test mod batch2::recovery_repeat_deploy_misfire_spec — 2/2 pass
  • test_shard_degradation 5/5 PASS via subprocess provider against the fixed binary (no flake, no cascade)

Test plan

  • CI green (unit tests + integration tests on amd64/arm64)

Co-Authored-By: Claude noreply@anthropic.com

…exemption

prepare_user_deploys exempts deploys in `rejected_in_scope` from the
in-scope filter so genuinely rejected deploys can be re-proposed. Without
a canonical-descendant gate, the exemption also fires when the rejection
sits in a non-canonical sibling while the deploy's effects are already in
canonical state — producing a recovery block that downstream validators
correctly flag as `InvalidRepeatDeploy`. On FTT=0 shards this triggers
mutual slashing.

Mirror the validator-side `repeat_deploy` gate at the proposer: resolve
the candidate sigs in batch and decline the exemption when status is
`Finalized`. Resolver failure → decline conservatively.

Tests:
  - validator-side defense regression (already passes pre-fix)
  - proposer-side gate (RED pre-fix, GREEN post-fix)
@spreston8 spreston8 requested a review from metaweta May 2, 2026 21:48
@spreston8 spreston8 merged commit 9f4c209 into rust/staging May 2, 2026
39 of 40 checks passed
@spreston8 spreston8 deleted the fix/recovery-repeat-deploy-misfire branch May 2, 2026 21:57
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