You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
V2's much larger in-flight blast radius (potentially dozens of real third-party positions locked into one round, across a multi-phase lifecycle, settled by meaningfully more complex math than v1's fixed-committee vote) means v1's "block new assertions only" pause isn't enough: if a bug is found in registration, reveal, or settlement logic while real capital is already locked into an active round, blocking new assertions does nothing to protect it. This issue designs and implements a real freeze/cancel mechanism for already-active v2 rounds. This was explicitly out of scope for the v1-style pause and was never designed in docs/src/V2_RESOLUTION.md; the shape below is a starting proposal, not a settled spec, and needs maintainer sign-off before merging.
Proposed shape
Before a terminal outcome is locked (assertion is Pending, Registration, or Reveal with no strict majority reached yet): admin may cancel the round. Cancellation refunds every already-funded position (asserter, disputer, and any third-party positions) their exact principal, no forfeiture, no reward, as if the round never happened. This is the safe phase to cancel in, since no side has been declared right yet, refunding everyone equally can't be read as picking a winner.
After a terminal outcome is locked (strict majority reached, or the optimistic timeout default has fired): the admin cannot cancel or alter the outcome. Settlement and withdrawal for that round continue exactly as normal, even during a pause. Allowing an admin to unwind an already-decided result would reintroduce exactly the kind of "pause can choose a winner" risk v1's pause design already explicitly avoids, just at the settlement stage instead of the dispute stage.
New assertions: still blocked during a pause, same as v1.
What to build
set_paused_v2(admin, paused: bool), blocking new assert_outcome calls while paused (same semantics as v1's set_paused).
cancel_round(admin, id: u64), callable only while paused and only while the assertion's terminal_cause is not yet set. Refunds every funded position's exact principal via the same credit-then-withdraw path as normal settlement (see [Feature] V2: implement credit accrual and owner-authorized withdrawal #70), so the reentrancy and accounting guarantees stay identical. Sets a distinct terminal_cause = AdminCancelled so it's clearly distinguishable from a real dispute outcome in history/events.
Reject cancel_round outright (not just a no-op) if terminal_cause is already set, to make it structurally impossible for this call to alter a decided outcome.
Emit a distinct event for cancellation, separate from normal settlement events, so indexers can tell the two apart.
Open question for maintainer review
Should cancel_round be available the instant a pause starts, or only after some grace period (giving in-flight reveals a chance to land first, since a reveal transaction submitted right before a pause could otherwise be preempted by a cancellation)? Needs a decision before implementation, not left to the implementer's judgment given the security sensitivity here.
Depends on
#64 (assertion/policy state), #70 (shares the credit/withdrawal path for refunds).
Summary
V2's much larger in-flight blast radius (potentially dozens of real third-party positions locked into one round, across a multi-phase lifecycle, settled by meaningfully more complex math than v1's fixed-committee vote) means v1's "block new assertions only" pause isn't enough: if a bug is found in registration, reveal, or settlement logic while real capital is already locked into an active round, blocking new assertions does nothing to protect it. This issue designs and implements a real freeze/cancel mechanism for already-active v2 rounds. This was explicitly out of scope for the v1-style pause and was never designed in docs/src/V2_RESOLUTION.md; the shape below is a starting proposal, not a settled spec, and needs maintainer sign-off before merging.
Proposed shape
Before a terminal outcome is locked (assertion is
Pending,Registration, orRevealwith no strict majority reached yet): admin may cancel the round. Cancellation refunds every already-funded position (asserter, disputer, and any third-party positions) their exact principal, no forfeiture, no reward, as if the round never happened. This is the safe phase to cancel in, since no side has been declared right yet, refunding everyone equally can't be read as picking a winner.After a terminal outcome is locked (strict majority reached, or the optimistic timeout default has fired): the admin cannot cancel or alter the outcome. Settlement and withdrawal for that round continue exactly as normal, even during a pause. Allowing an admin to unwind an already-decided result would reintroduce exactly the kind of "pause can choose a winner" risk v1's pause design already explicitly avoids, just at the settlement stage instead of the dispute stage.
New assertions: still blocked during a pause, same as v1.
What to build
set_paused_v2(admin, paused: bool), blocking newassert_outcomecalls while paused (same semantics as v1'sset_paused).cancel_round(admin, id: u64), callable only while paused and only while the assertion'sterminal_causeis not yet set. Refunds every funded position's exact principal via the same credit-then-withdraw path as normal settlement (see [Feature] V2: implement credit accrual and owner-authorized withdrawal #70), so the reentrancy and accounting guarantees stay identical. Sets a distinctterminal_cause = AdminCancelledso it's clearly distinguishable from a real dispute outcome in history/events.cancel_roundoutright (not just a no-op) ifterminal_causeis already set, to make it structurally impossible for this call to alter a decided outcome.Open question for maintainer review
Should
cancel_roundbe available the instant a pause starts, or only after some grace period (giving in-flight reveals a chance to land first, since a reveal transaction submitted right before a pause could otherwise be preempted by a cancellation)? Needs a decision before implementation, not left to the implementer's judgment given the security sensitivity here.Depends on
#64 (assertion/policy state), #70 (shares the credit/withdrawal path for refunds).