| Safe Haskell | Safe-Inferred |
|---|---|
| Language | GHC2021 |
Hydra.OffChainAgreementSpec
Description
Off-chain differential (real-node bindings): the Agda-extracted §6 handler decisions
(Hydra.Agda.OffChainReference) checked against the REAL update outcomes, not
against transcriptions of the figure. This extends OffChainLeaderSpec (which binds
leaderRef to the real isLeader) to three more decisions, closing the figure↔Agda↔Haskell loop:
signEligibleRefvsonOpenNetworkReqSn: we driveupdatewith aReqSnover an open state with version v̂ and a settled snapshot ŝ (confirmed = seen, nothing in flight) and binarise the outcome: ACCEPT iff the node reaches the signing continuation (SnapshotRequested+ anAckSneffect). The node splits the figure's singlerequireinto an Error (number:ReqSnNumberInvalid, leader:ReqSnNotLeader) and a Wait (version:WaitOnSnapshotVersion, so a follower behind on the version bump does not drop the message); Error and Wait both map to non-accept. The reference's leader input is resolved by the EXTRACTEDleaderRef(itself bound to the realisLeaderinOffChainLeaderSpec), so the composed decision is fully Agda-derived.reqDecEligibleRefvsonOpenNetworkReqDec: ACCEPT iff the node records the decommit (DecommitRecorded). A PENDING deposit makes the node WAIT (WaitOnUnresolvedCommit) at ttl > 0, and so does an in-flight decommit (WaitOnNotApplicableDecommitTxwithDecommitAlreadyInFlight); both are non-accept. The commit axis is the reference'sHsPendingCommit, not a Bool, so this test cannot decide which commits count: an expired or already-recovered deposit is a state the node reaches (it clearscurrentDepositTxIdon neither) and the reference is what says those do not block.reqSnNotBothRefreqSnDecommitOutputsRefreqSnDepositSettledRefvsonOpenNetworkReqSn's incremental-action guards: a request carrying both a deposit and a decommit isReqSnBothCommitAndDecommit; a decommit producing no outputs isReqSnDecommitNoOutputs; and settling a same-version pending commit requires the request to name the deposit bound into the confirmed snapshot by tx-id (ReqSnCommitNotSettledotherwise) - the look-alike-deposit case, where content matches and only identity differs.depositStatusRefvs the deposit-status transition the node applies on a chainTick(onOpenChainTickviadetermineNextDepositStatus): starting from a fresh Inactive deposit, one tick at time t yieldsDepositExpiredDepositActivatedno status event, mapping to ExpiredS ActiveS InactiveS.notAlreadySignedRefvsonOpenNetworkAckSn'srequireNotSignedYet: over a directly constructed in-flightSeenSnapshotwhose signatories map holds REAL signatures, anAckSnfrom a sender already in the map is the node'sSnapshotAlreadySigned; a fresh sender is not.allSignedRefvs the round completion ofonOpenNetworkAckSn: a fresh sender's ack CONFIRMS (the node aggregates the real signatures in order and verifies the real multisignature before emittingSnapshotConfirmed) exactly when it completes the n-of-n signer set; the composed decision isnotAlreadySignedRef ∧ allSignedRef (sender ∷ Σ̂).contestEligibleRefvsonOpenChainCloseTx: observing a close of snapshot s_c while our confirmed snapshot is S̄.s posts aContestTxexactly when S̄.s > s_c.
Domain note (deposit status): the extracted decision uses Nat truncated subtraction for
deadline − T_deposit whereas the node subtracts over UTCTime; the two agree whenever
deadline ≥ T_deposit, which the protocol guarantees (an observed deposit deadline sits a full
deposit period after creation). The property therefore quantifies over that domain, with all times
as whole POSIX seconds (exact in both representations).
Scope note (ackSn): the extracted guards model the COUNTING decisions (who signed, n-of-n); the
collected signatures themselves are held healthy, exactly as the on-chain reference holds crypto
conjuncts healthy. The real node additionally verifies the aggregate multisignature at
confirmation; a corrupt collected signature makes it reject (InvalidMultisignature) where the
counting reference alone would accept, demonstrated as a validator-only rejection below.