From 9d493fd4f0e5178dde91d8e15b47b0477b58731e Mon Sep 17 00:00:00 2001 From: Sasha Bogicevic Date: Mon, 11 Mar 2024 15:42:00 +0100 Subject: [PATCH] Fixes after rebase --- hydra-cluster/test/Test/ChainObserverSpec.hs | 2 +- hydra-node/golden/Event SimpleTx.json | 163 ++++++++++++++----- hydra-node/json-schemas/logs.yaml | 19 ++- hydra-node/src/Hydra/Chain/Direct/Tx.hs | 3 +- hydra-node/src/Hydra/HeadLogic.hs | 56 +++---- hydra-node/src/Hydra/HeadLogic/Outcome.hs | 2 +- hydra-node/test/Hydra/HeadLogicSpec.hs | 5 +- 7 files changed, 165 insertions(+), 85 deletions(-) diff --git a/hydra-cluster/test/Test/ChainObserverSpec.hs b/hydra-cluster/test/Test/ChainObserverSpec.hs index 7f1550f3d59..a5d1737ec52 100644 --- a/hydra-cluster/test/Test/ChainObserverSpec.hs +++ b/hydra-cluster/test/Test/ChainObserverSpec.hs @@ -61,7 +61,7 @@ spec = do commitTx <- requestCommitTx hydraNode commitUTxO - pure (signTx walletSk commitTx) >>= submitTx cardanoNode + submitTx cardanoNode (signTx walletSk commitTx) waitFor hydraTracer 5 [hydraNode] $ output "HeadIsOpen" ["utxo" .= commitUTxO, "headId" .= headId] diff --git a/hydra-node/golden/Event SimpleTx.json b/hydra-node/golden/Event SimpleTx.json index a1420cf7114..d4a628fb6f0 100644 --- a/hydra-node/golden/Event SimpleTx.json +++ b/hydra-node/golden/Event SimpleTx.json @@ -2,62 +2,45 @@ "samples": [ { "clientInput": { - "tag": "Contest" + "tag": "Fanout" }, "tag": "ClientEvent" }, { "message": { - "tag": "ReqTx", + "decommitRequester": { + "vkey": "6250421a689f91e7b1e18875710835624d01d9d0fd031562127f019ebdffc859" + }, + "tag": "ReqDec", "transaction": { - "id": -2, + "id": 5, "inputs": [ - -29, - -27, - -26, - -25, - -24, + -30, + -23, + -21, + -20, -18, - -14, - -11, + -17, + -12, -8, - -7, - -6, -4, -3, - -1, - 2, - 4, - 5, + -2, + 0, 6, - 9, - 17, - 18, + 8, + 16, 20, - 25, + 21, 27 ], "outputs": [ - -27, - -25, - -21, - -18, - -15, - -3, - -1, - 0, - 5, - 6, - 11, - 14, - 17, - 20, - 21, - 22, - 23, - 25, - 26, - 30 + -29, + -24, + -19, + -17, + 13, + 26 ] } }, @@ -110,11 +93,63 @@ }, { "message": { + "decommitTx": { + "id": 9, + "inputs": [ + -23, + -21, + -19, + -17, + -14, + -13, + -7, + 0, + 2, + 4, + 5, + 16, + 17, + 19, + 24, + 26, + 30 + ], + "outputs": [ + -27, + -17, + -16, + -14, + -11, + -9, + -3, + -1, + 7, + 22, + 24, + 26, + 28 + ] + }, "snapshotNumber": 3, "tag": "ReqSn", "transactionIds": [ - 22, - -13 + 0, + 4, + 16, + 26, + -19, + -1, + 11, + 0, + 10, + -6, + 19, + -2, + -20, + 12, + 7, + 8, + 14 ] }, "party": { @@ -125,9 +160,47 @@ }, { "message": { - "signed": "a27f8582e9c12e66b02b24b029716d5a4ab32da11c899b1aba99650c7a972318b031e8a57df63f22d38561da7dbb23e9c8504ecb11bee34877b01a02372aa20b", - "snapshotNumber": 0, - "tag": "AckSn" + "decommitRequester": { + "vkey": "928cc3b30d0f3d3f6e31d82c95ee98d06702affde1918c2d5d13177470598154" + }, + "tag": "ReqDec", + "transaction": { + "id": 4, + "inputs": [ + -25, + -9, + 6, + 11, + 24, + 27, + 30 + ], + "outputs": [ + -29, + -28, + -26, + -21, + -13, + -11, + -10, + -9, + -6, + -3, + -1, + 1, + 2, + 5, + 10, + 13, + 14, + 15, + 19, + 22, + 24, + 26, + 27 + ] + } }, "party": { "vkey": "3a31af3b199ce0f7d1efda02534708c9cb969d018b5b09e16584c1b40f41ec47" diff --git a/hydra-node/json-schemas/logs.yaml b/hydra-node/json-schemas/logs.yaml index 116791a16d3..83a725b2f89 100644 --- a/hydra-node/json-schemas/logs.yaml +++ b/hydra-node/json-schemas/logs.yaml @@ -1531,7 +1531,10 @@ definitions: seenSnapshot: $ref: "logs.yaml#/definitions/SeenSnapshot" decommitTx: - $ref: "api.yaml#/components/schemas/Transaction" + oneOf: + - type: "null" + - type: object + $ref: "api.yaml#/components/schemas/Transaction" SeenSnapshot: oneOf: @@ -2171,6 +2174,20 @@ definitions: type: array items: $ref: "api.yaml#/components/schemas/TxId" + - title: WaitOnNotApplicableDecommitTx + description: >- + Somebody requested a Decommit but there is another one in flight already. + type: object + additionalProperties: false + required: + - tag + - waitingOnDecommitTx + properties: + tag: + type: string + enum: ["WaitOnNotApplicableDecommitTx"] + waitingOnDecommitTx: + $ref: "api.yaml#/components/schemas/Transaction" IP: type: object diff --git a/hydra-node/src/Hydra/Chain/Direct/Tx.hs b/hydra-node/src/Hydra/Chain/Direct/Tx.hs index a72ec94cf26..20f34c88f1a 100644 --- a/hydra-node/src/Hydra/Chain/Direct/Tx.hs +++ b/hydra-node/src/Hydra/Chain/Direct/Tx.hs @@ -481,8 +481,7 @@ closeTx scriptRegistry vk closing startSlotNo (endSlotNo, utcTime) openThreadOut Head.Closed { snapshotNumber , utxoHash = toBuiltin utxoHashBytes - , -- TODO: find a way to introduce this value - utxoToDecommitHash = toBuiltin decommitUTxOHashBytes + , utxoToDecommitHash = toBuiltin decommitUTxOHashBytes , parties = openParties , contestationDeadline , contestationPeriod = openContestationPeriod diff --git a/hydra-node/src/Hydra/HeadLogic.hs b/hydra-node/src/Hydra/HeadLogic.hs index 037b15c7dff..a59bb10870c 100644 --- a/hydra-node/src/Hydra/HeadLogic.hs +++ b/hydra-node/src/Hydra/HeadLogic.hs @@ -300,15 +300,14 @@ onOpenNetworkReqTx env ledger st ttl tx = (newState TransactionReceived{tx} <>) $ -- Spec: wait L̂ ◦ tx ≠ ⊥ combined with L̂ ← L̂ ◦ tx waitApplyTx $ \newLocalUTxO -> - -- Spec: if ŝ = s̄ ∧ leader(s̄ + 1) = i - ( if not snapshotInFlight && isLeader parameters party nextSn - then - newState TransactionAppliedToLocalUTxO{tx = tx, newLocalUTxO} - <> - newState SnapshotRequestDecided{snapshotNumber = nextSn} - <> cause (NetworkEffect $ ReqSn nextSn (txId <$> localTxs') decommitTx) - else newState TransactionAppliedToLocalUTxO{tx, newLocalUTxO} - ) + -- Spec: if ŝ = s̄ ∧ leader(s̄ + 1) = i + ( if not snapshotInFlight && isLeader parameters party nextSn + then + newState TransactionAppliedToLocalUTxO{tx = tx, newLocalUTxO} + <> newState SnapshotRequestDecided{snapshotNumber = nextSn} + <> cause (NetworkEffect $ ReqSn nextSn (txId <$> localTxs') decommitTx) + else newState TransactionAppliedToLocalUTxO{tx, newLocalUTxO} + ) <> cause (ClientEffect $ ServerOutput.TxValid headId tx) where waitApplyTx cont = @@ -579,7 +578,7 @@ onOpenNetworkAckSn Environment{party} openState otherParty snapshotSignature sn case utxoToDecommit of Just utxoToDecommit' -> outcome - <> Effects + <> causes [ ClientEffect $ ServerOutput.DecommitApproved{headId, utxoToDecommit = utxoToDecommit'} , OnChainEffect { postChainTx = @@ -620,27 +619,25 @@ onOpenClientDecommit :: onOpenClientDecommit env headId ledger currentSlot coordinatedHeadState decommitTx = checkNoDecommitInFlight $ checkValidDecommitTx $ - Effects - [ NetworkEffect ReqDec{transaction = decommitTx, decommitRequester = party} - ] + cause (NetworkEffect ReqDec{transaction = decommitTx, decommitRequester = party}) where checkNoDecommitInFlight continue = case mExistingDecommitTx of Just existingDecommitTx -> - Effects - [ ClientEffect + cause + ( ClientEffect ServerOutput.DecommitInvalid { headId , decommitInvalidReason = ServerOutput.DecommitAlreadyInFlight{decommitTx = existingDecommitTx} } - ] + ) Nothing -> continue checkValidDecommitTx cont = case applyTransactions ledger currentSlot confirmedUTxO [decommitTx] of Left (_, err) -> - Effects - [ ClientEffect + cause + ( ClientEffect ServerOutput.DecommitInvalid { headId , decommitInvalidReason = @@ -650,7 +647,7 @@ onOpenClientDecommit env headId ledger currentSlot coordinatedHeadState decommit , validationError = err } } - ] + ) Right _ -> cont confirmedUTxO = (getSnapshot confirmedSnapshot).utxo @@ -691,22 +688,18 @@ onOpenNetworkReqDec :: onOpenNetworkReqDec env ttl openState decommitTx = waitOnApplicableDecommit $ let decommitUTxO = utxoFromTx decommitTx - in StateChanged (DecommitRecorded decommitTx) - <> Effects - [ ClientEffect $ ServerOutput.DecommitRequested headId decommitUTxO - ] + in newState (DecommitRecorded decommitTx) + <> cause (ClientEffect $ ServerOutput.DecommitRequested headId decommitUTxO) <> if isLeader parameters party nextSn - then - Effects - [NetworkEffect (ReqSn nextSn (txId <$> localTxs) (Just decommitTx))] - else Error $ RequireFailed $ ReqSnNotLeader{requestedSn = nextSn, leader = party} + then cause (NetworkEffect (ReqSn nextSn (txId <$> localTxs) (Just decommitTx))) + else noop where waitOnApplicableDecommit cont = case mExistingDecommitTx of Nothing -> cont Just existingDecommitTx | ttl > 0 -> - Wait $ WaitOnNotApplicableDecommitTx decommitTx + wait $ WaitOnNotApplicableDecommitTx decommitTx | otherwise -> Error $ RequireFailed $ DecommitTxInFlight{decommitTx = existingDecommitTx} Environment{party} = env @@ -916,13 +909,10 @@ update env ledger st ev = case (st, ev) of ) -- TODO: What happens if observed decrement tx get's rolled back? | ourHeadId == headId -> - Effects - [ClientEffect $ ServerOutput.DecommitFinalized{headId}] - <> StateChanged DecommitFinalized + cause (ClientEffect $ ServerOutput.DecommitFinalized{headId}) + <> newState DecommitFinalized | otherwise -> Error NotOurHead{ourHeadId, otherHeadId = headId} - (Open{}, PostTxError{postChainTx = CollectComTx{}}) -> - Effects [] -- Closed (Closed closedState@ClosedState{headId = ourHeadId}, OnChainEvent Observation{observedTx = OnContestTx{headId, snapshotNumber, contestationDeadline}, newChainState}) | ourHeadId == headId -> diff --git a/hydra-node/src/Hydra/HeadLogic/Outcome.hs b/hydra-node/src/Hydra/HeadLogic/Outcome.hs index 32d50c630e8..a6d5d7802d9 100644 --- a/hydra-node/src/Hydra/HeadLogic/Outcome.hs +++ b/hydra-node/src/Hydra/HeadLogic/Outcome.hs @@ -133,7 +133,7 @@ data WaitReason tx | WaitOnSeenSnapshot | WaitOnTxs {waitingForTxIds :: [TxIdType tx]} | WaitOnContestationDeadline - | WaitOnNotApplicableDecommitTx { waitingOnDecommitTx :: tx} + | WaitOnNotApplicableDecommitTx {waitingOnDecommitTx :: tx} deriving stock (Generic) deriving stock instance IsTx tx => Eq (WaitReason tx) diff --git a/hydra-node/test/Hydra/HeadLogicSpec.hs b/hydra-node/test/Hydra/HeadLogicSpec.hs index 520356faaf2..bc3eefb620e 100644 --- a/hydra-node/test/Hydra/HeadLogicSpec.hs +++ b/hydra-node/test/Hydra/HeadLogicSpec.hs @@ -46,6 +46,7 @@ import Hydra.HeadLogic ( aggregateState, defaultTTL, update, + cause, ) import Hydra.HeadLogic.State (getHeadParameters) import Hydra.Ledger (ChainSlot (..), IsTx (..), Ledger (..), ValidationError (..)) @@ -158,7 +159,7 @@ spec = st <- pickBlind $ oneof $ pure <$> [inInitialState threeParties, inIdleState, inClosedState threeParties] pure $ update aliceEnv ledger st event - `shouldNotBe` Effects [NetworkEffect reqDec] + `shouldNotBe` cause (NetworkEffect reqDec) it "wait for second decommit when another one is in flight" $ do let decommitTx1 = SimpleTx 1 mempty (utxoRef 1) @@ -176,7 +177,7 @@ spec = let outcome = update bobEnv ledger s1 reqDecEvent2 outcome `shouldSatisfy` \case - Wait (WaitOnNotApplicableDecommitTx{waitingOnDecommitTx = decommitTx''}) -> + Wait (WaitOnNotApplicableDecommitTx{waitingOnDecommitTx = decommitTx''}) _ -> decommitTx2 == decommitTx'' _ -> False