feat: make multi-sig releases safe against signature replay and dupli…#464
Open
Faromzy wants to merge 1 commit into
Open
feat: make multi-sig releases safe against signature replay and dupli…#464Faromzy wants to merge 1 commit into
Faromzy wants to merge 1 commit into
Conversation
…cation - Add DuplicateSigner error: collect_signature now returns an explicit error instead of silently succeeding when the same address signs twice - Add InvalidRequiredSignatures error: configure_multisig rejects required_signatures == 0 or > MAX_REQUIRED_SIGNATURES (10) - Add MAX_REQUIRED_SIGNATURES constant (10) as an upper bound cap - Clear collected_signatures after every milestone release so signatures from one release window cannot be replayed on the next milestone - Clear collected_signatures on raise_dispute, cancel_escrow, and refund_expired so stale signatures never survive state transitions - Add SignatureResetEvent emitted on each clear with a reason field: 'milestone', 'dispute', 'cancel', or 'expired' - Add 13 new tests covering duplicate rejection, replay prevention, reset semantics per state transition, and bounds validation - Update test_raise_dispute_happy_path and test_full_lifecycle_event_summaries_are_accurate to account for the new trailing SignatureReset events All 121 tests pass.
|
@Faromzy Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Multi-sig Signature Safety: Prevent Replay and Duplication
Summary
Hardens the multi-signature milestone release mechanism so collected signatures are scoped
strictly to a single release window. Signatures can no longer be replayed across milestones or
survive terminal state transitions.
───────────────────────────────────────────────────────────────────────────────────────────────
What Changed
New error variants
same escrow
required_signatures = 0 or > 10
New constant
New event
collected_signatures is cleared, with reason set to "milestone", "dispute", "cancel", or
"expired" so off-chain listeners always know why the slate was wiped
Behaviour changes
┌───────────────────┬────────┬───────┐
│ Location │ Before │ After │
├────────────────────┼────────────────────────────────────┼──────────────────────────────┤
│ collect_signature │ Duplicate silently returned Ok(()) │ Returns Err(DuplicateSigner) │
│ │ Ok(()) │ Err(DuplicateSigner) │
├───────────────────────────┼─────────────────────────────────┼────────────────────────────┤
│ configure_multisig │ Accepted any u32 including 0 │ Rejects 0 and values > 10 │
├───────────────────────────┼───────────────────────────────┼──────────────────────────────┤
│ release_pending_milestone │ Signatures persisted after │ Cleared immediately after │
│ │ release │ release │
├───────────────────────────┼───────────────────────────────┼──────────────────────────────┤
│ raise_dispute │ Signatures persisted │ Cleared, SignatureReset │
│ │ │ emitted │
├───────────────────────────┼───────────────────────────────┼──────────────────────────────┤
│ cancel_escrow │ Signatures persisted │ Cleared, SignatureReset │
│ │ │ emitted │
├───────────────────────────┼───────────────────────────────┼──────────────────────────────┤
│ refund_expired │ Signatures persisted │ Cleared, SignatureReset │
│ │ │ emitted │
└───────────────────────────┴───────────────────────────────┴──────────────────────────────┘
───────────────────────────────────────────────────────────────────────────────────────────────
Tests Added (13 new)
fails with UnauthorizedAccess after milestone N is released
not trigger multi-sig (condition is strictly >)
Tests Updated (2)
now follows it
DeliveryConfirmed
Result: 121/121 tests pass.
───────────────────────────────────────────────────────────────────────────────────────────────
Security Impact
┌─────────────────────────────────────┬────────┐
│ Threat │ Status │
├──────────────────────────────────────────────────────┼─────────────────────────────────┤
│ Signer counted twice in same window │ Blocked — DuplicateSigner error │
├──────────────────────────────────────────────────────┼─────────────────────────────────┤
│ Signatures from milestone N reused for milestone N+1 │ Blocked — cleared on release │
├──────────────────────────────────────────────────────┼────────────────────────────────────┤
├─────────────────────────────────────────────────────┼─────────────────────────────────────┤
│ Partially-collected signatures surviving a dispute │ Blocked — cleared on raise_dispute │
├─────────────────────────────────────────────────────┼─────────────────────────────────────┤
├───────────────────────────────────────────────┼───────────────────────────────────────────┤
│ Stale signatures surviving cancellation or │ Blocked — cleared on cancel/expired │
│ expiry │ │
├───────────────────────────────────────────────┼───────────────────────────────────────────┤
│ Zero-threshold bypass (required_signatures = │ Blocked — InvalidRequiredSignatures error │
│ 0) │ │
└───────────────────────────────────────────────┴───────────────────────────────────────────┘
closes #211