feat(chalg): underwriter-fault challenge — bonded, council-adjudicated slashing (WIRE-297) - #549
Open
heifner wants to merge 1 commit into
Open
feat(chalg): underwriter-fault challenge — bonded, council-adjudicated slashing (WIRE-297)#549heifner wants to merge 1 commit into
heifner wants to merge 1 commit into
Conversation
…d slashing (WIRE-297) Security property #4 ("the bond is slashable") was unenforced: no production path could slash an UNDERWRITER-type operator, and the collateral-lock window ended in an unconditional release. This adds the missing trigger, mirroring the batch-operator envelope dispute everywhere the problem allows. sysio.chalg — the envelope dispute's sibling: * openuwchal(challenger, uwreq_id, underwriter, reason, detail) — permissionless filing against a CONFIRMED commitment, time-gated to its collateral-lock window. The challenger escrows a WIRE bond = the WIRE value of the challenged locks, each leg priced through its OWN reserve's live books (token_to_wire; u128-summed). One challenge EVER per (uwreq, underwriter) — a council verdict is final per commitment; other commitments are independently challengeable. * uwchalbond — read-only quote sharing ONE formula helper with the charge, so quote and escrow can never drift (the split_wire_fee principle). * voteuwchal — record-only Tier-1 ballot (electorate + quorum snapshotted at open via snapshot_t1_electorate, now shared with opendispute). Three-way: UPHOLD / REJECT_REFUND / REJECT_FORFEIT — forfeiture to the wrongly-challenged underwriter happens ONLY by an explicit majority of the rejectors (tie favours refund); an honest mistake refunds. * chkuwchal — permissionless tally, chkdispute-shaped. UPHELD: slashop, then uwrit::sweeplocks (inline actions run depth-first in send order, so releaselock takes its deferred-slash branch — locked collateral debited, outbound SLASH attestations queued). REJECTED: freelocks; the locks live out their window. Past the deadline with no quorum: LAPSED — bond refunded, nobody punished. Deliberately NO after-deadline relaxed tally (a challenge must be voted inside the window) and NO epoch pause (an unresolved challenge is survivable; the chain keeps advancing). sysio.uwrit — the lock hold: * lock_entry.challenge_id (ABI change): a held lock is NOT released at expiry; chklocks skips it and pokes chkuwchal instead — the epoch tick is the challenge system's only cadence (possible precisely because the chain is not paused; envelope disputes need a standalone crank because theirs is). * holdlocks / freelocks / sweeplocks (auth sysio.chalg): hold is the authoritative liveness gate for a filing (a stale open aborts whole, escrow included); free/sweep are soft past auth — they run inline from the epoch tick, where an abort would stall advancement chain-wide. * The COMPLETED-flip / evidence-clear / retention tail is extracted to finalize_settled_uwreqs, shared by chklocks and sweeplocks. The evidence-retention prerequisite flagged on WIRE-297 needed no work: CONFIRMED uwreqs carry expires_at_epoch == 0 and pruneuwreqs skips them, so the stored SwapRequest / source_tx_id / UIC bytes already survive the whole lock window; the deadline is only stamped when the locks leave. Tests (sysio.dispatch_tests, reusing its CONFIRMED-uwreq machinery): the bond quote pinned to the shared AMM kernel over LIVE post-settlement books (winner selection settles inline — challenge-time books have already moved); escrow/hold/uniqueness; every filing guard incl. whole-transaction rollback; ballot guards; uphold end-to-end (SLASHED, locked collateral debited via the deferred-slash branch, bond returned, uwreq COMPLETED, chalg custody zero); reject-forfeit (bond to the underwriter, collateral byte-identical after the healthy release); reject-tie → refund; the epoch-tick skip/poke/lapse/ second-sweep sequence; and chalg-only auth on the lock trio. contracts_unit_test: 592 cases, No errors detected. ABI delta: chalg + uwrit only; other wasm churn is ABI-identical rebuilds from the full build. Change-Id: I3f2c743bbca520558d959ac3deac4e5193c9bf8f
Contributor
Author
|
Companion PRs: Wire-Network/wire-libraries-ts#61 (regenerated SysioContractTypes) and Wire-Network/wire-tools-ts#56 (flow-underwriter-slashing, the live-cluster validation — 154/154 steps green). Merge order: this → libraries → tools. |
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.
Security property #4 ("the bond is slashable") was unenforced: no production path could slash an UNDERWRITER-type operator, and the collateral-lock window ended in an unconditional release. This adds the missing trigger, mirroring the batch-operator envelope dispute everywhere the problem allows.
sysio.chalg — the envelope dispute's sibling
openuwchal(challenger, uwreq_id, underwriter, reason, detail)— permissionless filing against a CONFIRMED commitment, time-gated to its collateral-lock window. The challenger escrows a WIRE bond = the WIRE value of the challenged locks, each leg priced through its OWN reserve's live books (token_to_wire; u128-summed). One challenge EVER per (uwreq, underwriter) — a council verdict is final per commitment; other commitments are independently challengeable.uwchalbond— read-only quote sharing ONE formula helper with the charge, so quote and escrow can never drift (thesplit_wire_feeprinciple).voteuwchal— record-only Tier-1 ballot (electorate + quorum snapshotted at open viasnapshot_t1_electorate, now shared withopendispute). Three-way: UPHOLD / REJECT_REFUND / REJECT_FORFEIT — forfeiture to the wrongly-challenged underwriter happens ONLY by an explicit majority of the rejectors (tie favours refund); an honest mistake refunds.chkuwchal— permissionless tally,chkdispute-shaped. UPHELD:slashop, thenuwrit::sweeplocks(inline actions run depth-first in send order, soreleaselocktakes its deferred-slash branch — locked collateral debited, outbound SLASH attestations queued). REJECTED:freelocks; the locks live out their window. Past the deadline with no quorum: LAPSED — bond refunded, nobody punished. Deliberately NO after-deadline relaxed tally (a challenge must be voted inside the window) and NO epoch pause (an unresolved challenge is survivable; the chain keeps advancing).sysio.uwrit — the lock hold
lock_entry.challenge_id(ABI change): a held lock is NOT released at expiry;chklocksskips it and pokeschkuwchalinstead — the epoch tick is the challenge system's only cadence (possible precisely because the chain is not paused; envelope disputes need a standalone crank because theirs is).holdlocks/freelocks/sweeplocks(authsysio.chalg): hold is the authoritative liveness gate for a filing (a stale open aborts whole, escrow included); free/sweep are soft past auth — they run inline from the epoch tick, where an abort would stall advancement chain-wide.finalize_settled_uwreqs, shared bychklocksandsweeplocks.The evidence-retention prerequisite flagged on WIRE-297 needed no work: CONFIRMED uwreqs carry
expires_at_epoch == 0andpruneuwreqsskips them, so the stored SwapRequest / source_tx_id / UIC bytes already survive the whole lock window; the deadline is only stamped when the locks leave.Tests
sysio.dispatch_tests(reusing its CONFIRMED-uwreq machinery): escrow/hold/uniqueness; every filing guard incl. whole-transaction rollback; ballot guards; uphold end-to-end (SLASHED, locked collateral debited via the deferred-slash branch, bond returned, uwreq COMPLETED, chalg custody zero); reject-forfeit (bond to the underwriter, collateral byte-identical after the healthy release); reject-tie → refund; the epoch-tick skip/poke/lapse/second-sweep sequence; and chalg-only auth on the lock trio.contracts_unit_test: 592 cases, No errors detected. ABI delta: chalg + uwrit only; other wasm churn is ABI-identical rebuilds from the full build.Validated end-to-end on a live cluster by the new
flow-underwriter-slashing(154/154 Report steps green): both verdicts exercised on the real pipeline — REJECTED_FORFEIT paid the bond to the underwriter inline; UPHELD slashed the winner, swept the locks, and refunded the challenger, withsysio.chalgending at zero custody.Companion PRs (merge this first): wire-libraries-ts and wire-tools-ts links to follow in comments — merge order sysio → libraries → tools.