diff --git a/docs/docs/how-to/incremental-commit.md b/docs/docs/how-to/incremental-commit.md index 20604a6af19..f6e1efb7ec4 100644 --- a/docs/docs/how-to/incremental-commit.md +++ b/docs/docs/how-to/incremental-commit.md @@ -19,7 +19,7 @@ We can inspect the L1 utxo with: ```shell cardano-cli query utxo --whole-utxo ``` -and +and the state of the faucet public key ```shell cardano-cli query utxo \ @@ -80,18 +80,19 @@ cardano-cli query utxo \ Inspect the pending deposits: + ``` curl -X GET localhost:4001/commits -["7fa05f9d5269d95452ed86bb7a32f2485245c781b61380673be0e33fb849c919"] ``` +and you should see the tx-id of the deposit transaction `["6b51f3787f5482004b258c60fe0c94775164f547d9284b6233bbb4f6f8b9dfa6"]` To recover, we can use the `/commits` endpoint again using the transaction id of the deposit: ```shell -curl -X DELETE localhost:4001/commits/$(printf "\"7fa05f9d5269d95452ed86bb7a32f2485245c781b61380673be0e33fb849c919"\" | jq -sRr '@uri') -OK +curl -X DELETE localhost:4001/commits/$(printf "\"6b51f3787f5482004b258c60fe0c94775164f547d9284b6233bbb4f6f8b9dfa6"\" | jq -sRr '@uri') ``` + If we inspect the faucet funds again we will see that the locked deposit is now recovered ```shell diff --git a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs index 73f42d11309..d22978c19b0 100644 --- a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs +++ b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs @@ -40,7 +40,6 @@ import Hydra.Cardano.Api ( PaymentKey, Tx, TxId, - TxIn, UTxO, getTxBody, getTxId, @@ -856,7 +855,7 @@ canSeePendingDeposits tracer workDir node hydraScriptsTxId = commitUTxO2 <- seedFromFaucet node walletVk 4_000_000 (contramap FromFaucet tracer) commitUTxO3 <- seedFromFaucet node walletVk 3_000_000 (contramap FromFaucet tracer) - flip evalStateT [] $ forM_ [commitUTxO, commitUTxO2, commitUTxO3] $ \utxo -> do + deposited <- flip execStateT [] $ forM [commitUTxO, commitUTxO2, commitUTxO3] $ \utxo -> do resp <- parseUrlThrow ("POST " <> hydraNodeBaseUrl n1 <> "/commit") <&> setRequestBodyJSON utxo @@ -868,20 +867,36 @@ canSeePendingDeposits tracer workDir node hydraScriptsTxId = liftIO $ submitTx node tx - liftIO $ waitForAllMatch 10 [n1] $ \v -> do + liftIO $ waitForAllMatch 10 [n1] $ \v -> guard $ v ^? key "tag" == Just "CommitRecorded" - recoverResp <- + pendingDepositReq <- parseUrlThrow ("GET " <> hydraNodeBaseUrl n1 <> "/commits") >>= httpJSON - -- the issue doesn't specify the format of the response so we are - -- free to use whatever is convenient for the users ([TxIn]?) - let expectedResponse = fst . List.head . UTxO.pairs $ utxoFromTx tx + let expectedResponse = getTxId (getTxBody tx) _ <- modify (expectedResponse :) expected <- get - let expectedResp = getResponseBody recoverResp :: [TxIn] + let expectedResp = getResponseBody pendingDepositReq :: [TxId] liftIO $ expectedResp `shouldBe` expected + + forM_ deposited $ \deposit -> do + let path = BSC.unpack $ urlEncode False $ encodeUtf8 $ T.pack $ show deposit + recoverResp <- + parseUrlThrow ("DELETE " <> hydraNodeBaseUrl n1 <> "/commits/" <> spy path) + >>= httpJSON + + (getResponseBody recoverResp :: String) `shouldBe` "OK" + + waitForAllMatch 10 [n1] $ \v -> do + guard $ v ^? key "tag" == Just "CommitRecovered" + + pendingDepositReq <- + parseUrlThrow ("GET " <> hydraNodeBaseUrl n1 <> "/commits") + >>= httpJSON + + let expectedResp = getResponseBody pendingDepositReq :: [TxId] + expectedResp `shouldBe` [] where RunningNode{networkId, nodeSocket, blockTime} = node diff --git a/hydra-cluster/src/HydraNode.hs b/hydra-cluster/src/HydraNode.hs index 6e94076962c..3605cd89f4e 100644 --- a/hydra-cluster/src/HydraNode.hs +++ b/hydra-cluster/src/HydraNode.hs @@ -380,14 +380,14 @@ withHydraNode' tracer chainConfig workDir hydraNodeId hydraSKey hydraVKeys allNo } ) { std_out = maybe CreatePipe UseHandle mGivenStdOut - , std_err = Inherit + , std_err = CreatePipe } traceWith tracer $ HydraNodeCommandSpec $ show $ cmdspec p withCreateProcess p $ \_stdin mCreatedStdOut mCreatedStdErr processHandle -> case (mCreatedStdOut <|> mGivenStdOut, mCreatedStdErr) of - (Just out, Nothing) -> action out stderr processHandle + (Just out, Just err) -> action out err processHandle (Nothing, _) -> error "Should not happen™" (_, Nothing) -> error "Should not happen™" where diff --git a/hydra-node/src/Hydra/Chain.hs b/hydra-node/src/Hydra/Chain.hs index 1df7dbcf17e..20de71001c8 100644 --- a/hydra-node/src/Hydra/Chain.hs +++ b/hydra-node/src/Hydra/Chain.hs @@ -133,6 +133,7 @@ data OnChainTx tx | OnRecoverTx { headId :: HeadId , recoveredUTxO :: UTxOType tx + , recoveredTxId :: TxIdType tx } | OnIncrementTx { headId :: HeadId diff --git a/hydra-node/src/Hydra/Chain/Direct/Handlers.hs b/hydra-node/src/Hydra/Chain/Direct/Handlers.hs index b8d58ac6f21..73a22af8ef1 100644 --- a/hydra-node/src/Hydra/Chain/Direct/Handlers.hs +++ b/hydra-node/src/Hydra/Chain/Direct/Handlers.hs @@ -336,8 +336,8 @@ convertObservation = \case pure OnCollectComTx{headId} Deposit DepositObservation{headId, deposited, depositTxId, deadline, depositScriptUTxO} -> pure $ OnDepositTx{headId, deposited, depositTxId, deadline = posixToUTCTime deadline, depositScriptUTxO} - Recover RecoverObservation{headId, recoveredUTxO} -> - pure OnRecoverTx{headId, recoveredUTxO} + Recover RecoverObservation{headId, recoveredUTxO, recoveredTxId} -> + pure OnRecoverTx{headId, recoveredUTxO, recoveredTxId} Increment IncrementObservation{headId, newVersion, depositTxId} -> pure OnIncrementTx{headId, newVersion, depositTxId} Decrement DecrementObservation{headId, newVersion, distributedOutputs} -> diff --git a/hydra-node/src/Hydra/HeadLogic.hs b/hydra-node/src/Hydra/HeadLogic.hs index 8f43fb981ec..6bf9179b205 100644 --- a/hydra-node/src/Hydra/HeadLogic.hs +++ b/hydra-node/src/Hydra/HeadLogic.hs @@ -977,9 +977,10 @@ onOpenChainRecoverTx :: HeadId -> OpenState tx -> UTxOType tx -> + TxIdType tx -> Outcome tx -onOpenChainRecoverTx headId st recoveredUTxO = - newState CommitRecovered{recoveredUTxO, newLocalUTxO = localUTxO `withoutUTxO` recoveredUTxO} +onOpenChainRecoverTx headId st recoveredUTxO recoveredTxId = + newState CommitRecovered{recoveredUTxO, newLocalUTxO = localUTxO `withoutUTxO` recoveredUTxO, recoveredTxId} <> cause ( ClientEffect ServerOutput.CommitRecovered @@ -1302,8 +1303,8 @@ update env ledger st ev = case (st, ev) of | ourHeadId == headId -> onOpenChainDepositTx headId env openState deposited depositTxId deadline depositScriptUTxO | otherwise -> Error NotOurHead{ourHeadId, otherHeadId = headId} - (Open openState@OpenState{headId = ourHeadId}, ChainInput Observation{observedTx = OnRecoverTx{headId, recoveredUTxO}}) - | ourHeadId == headId -> onOpenChainRecoverTx headId openState recoveredUTxO + (Open openState@OpenState{headId = ourHeadId}, ChainInput Observation{observedTx = OnRecoverTx{headId, recoveredUTxO, recoveredTxId}}) + | ourHeadId == headId -> onOpenChainRecoverTx headId openState recoveredUTxO recoveredTxId | otherwise -> Error NotOurHead{ourHeadId, otherHeadId = headId} (Open openState@OpenState{headId = ourHeadId}, ChainInput Observation{observedTx = OnIncrementTx{headId, newVersion, depositTxId}}) @@ -1421,7 +1422,7 @@ aggregate st = \case where CoordinatedHeadState{pendingDeposits = existingDeposits} = coordinatedHeadState _otherState -> st - CommitRecovered{newLocalUTxO} -> case st of + CommitRecovered{newLocalUTxO, recoveredTxId} -> case st of Open os@OpenState{coordinatedHeadState} -> Open @@ -1429,9 +1430,11 @@ aggregate st = \case { coordinatedHeadState = coordinatedHeadState { localUTxO = newLocalUTxO - , pendingDeposits = mempty + , pendingDeposits = Map.delete (spy recoveredTxId) existingDeposits } } + where + CoordinatedHeadState{pendingDeposits = existingDeposits} = coordinatedHeadState _otherState -> st DecommitRecorded{decommitTx, newLocalUTxO} -> case st of Open diff --git a/hydra-node/src/Hydra/HeadLogic/Outcome.hs b/hydra-node/src/Hydra/HeadLogic/Outcome.hs index d196d567a1c..3460cc47e6e 100644 --- a/hydra-node/src/Hydra/HeadLogic/Outcome.hs +++ b/hydra-node/src/Hydra/HeadLogic/Outcome.hs @@ -73,7 +73,7 @@ data StateChanged tx , newLocalUTxO :: UTxOType tx } | CommitRecorded {pendingDeposits :: PendingDeposits tx, newLocalUTxO :: UTxOType tx} - | CommitRecovered {recoveredUTxO :: UTxOType tx, newLocalUTxO :: UTxOType tx} + | CommitRecovered {recoveredUTxO :: UTxOType tx, newLocalUTxO :: UTxOType tx, recoveredTxId :: TxIdType tx} | DecommitRecorded {decommitTx :: tx, newLocalUTxO :: UTxOType tx} | SnapshotRequestDecided {snapshotNumber :: SnapshotNumber} | -- | A snapshot was requested by some party. diff --git a/hydra-node/test/Hydra/BehaviorSpec.hs b/hydra-node/test/Hydra/BehaviorSpec.hs index 10ad9dd9d67..6af28da8423 100644 --- a/hydra-node/test/Hydra/BehaviorSpec.hs +++ b/hydra-node/test/Hydra/BehaviorSpec.hs @@ -845,8 +845,8 @@ toOnChainTx now = \case OnAbortTx{headId = testHeadId} CollectComTx{headId} -> OnCollectComTx{headId} - RecoverTx{headId, utxoToDeposit} -> - OnRecoverTx{headId, recoveredUTxO = utxoToDeposit} + RecoverTx{headId, utxoToDeposit, recoverTxId} -> + OnRecoverTx{headId, recoveredUTxO = utxoToDeposit, recoveredTxId = recoverTxId} IncrementTx{headId, incrementingSnapshot, depositTxId} -> OnIncrementTx { headId diff --git a/hydra-tx/src/Hydra/Tx/Recover.hs b/hydra-tx/src/Hydra/Tx/Recover.hs index 25bef4a53f0..06c49a52991 100644 --- a/hydra-tx/src/Hydra/Tx/Recover.hs +++ b/hydra-tx/src/Hydra/Tx/Recover.hs @@ -50,6 +50,7 @@ recoverTx depositTxId deposited lowerBoundSlot = data RecoverObservation = RecoverObservation { headId :: HeadId , recoveredUTxO :: UTxO + , recoveredTxId :: TxId } deriving stock (Show, Eq, Generic) @@ -60,7 +61,7 @@ observeRecoverTx :: Maybe RecoverObservation observeRecoverTx networkId utxo tx = do let inputUTxO = resolveInputsUTxO utxo tx - (_, depositOut) <- findTxOutByScript @PlutusScriptV2 inputUTxO depositScript + (TxIn depositTxId _, depositOut) <- findTxOutByScript @PlutusScriptV2 inputUTxO depositScript dat <- txOutScriptData $ toTxContext depositOut Deposit.DepositDatum (headCurrencySymbol, _, onChainDeposits) <- fromScriptData dat deposits <- do @@ -76,6 +77,7 @@ observeRecoverTx networkId utxo tx = do ( RecoverObservation { headId , recoveredUTxO = deposits + , recoveredTxId = depositTxId } ) else Nothing