From 8c21c5487d3bf2b7f4545728ae4735e9097a0e00 Mon Sep 17 00:00:00 2001 From: Sasha Bogicevic Date: Tue, 24 Sep 2024 17:49:07 +0200 Subject: [PATCH] Use path instead of query string for recover --- hydra-cluster/hydra-cluster.cabal | 2 +- hydra-cluster/src/Hydra/Cluster/Scenarios.hs | 6 +- hydra-node/src/Hydra/API/HTTPServer.hs | 75 +++++++++----------- 3 files changed, 39 insertions(+), 44 deletions(-) diff --git a/hydra-cluster/hydra-cluster.cabal b/hydra-cluster/hydra-cluster.cabal index 6d46120ce98..4150ac089de 100644 --- a/hydra-cluster/hydra-cluster.cabal +++ b/hydra-cluster/hydra-cluster.cabal @@ -86,7 +86,6 @@ library , aeson , async , base >=4.7 && <5 - , base16-bytestring , bytestring , cardano-slotting , containers @@ -95,6 +94,7 @@ library , directory , filepath , http-conduit + , http-types , hydra-cardano-api , hydra-node , hydra-prelude diff --git a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs index dc6c30993d0..00a72a4176b 100644 --- a/hydra-cluster/src/Hydra/Cluster/Scenarios.hs +++ b/hydra-cluster/src/Hydra/Cluster/Scenarios.hs @@ -25,7 +25,6 @@ import Data.Aeson.Lens (key, values, _JSON) import Data.Aeson.Types (parseMaybe) import Data.ByteString (isInfixOf) import Data.ByteString qualified as B -import Data.ByteString.Base16 qualified as Base16 import Data.ByteString.Char8 qualified as BSC import Data.List qualified as List import Data.Set qualified as Set @@ -102,6 +101,7 @@ import Network.HTTP.Req ( (/:), ) import Network.HTTP.Simple (getResponseBody, httpJSON, setRequestBodyJSON) +import Network.HTTP.Types (urlEncode) import System.Directory (removeDirectoryRecursive) import System.FilePath (()) import Test.Hydra.Tx.Gen (genKeyPair) @@ -702,11 +702,11 @@ canRecoverDeposit tracer workDir node hydraScriptsTxId = (selectLovelace . balance <$> queryUTxOFor networkId nodeSocket QueryTip walletVk) `shouldReturn` 0 - let queryStr = BSC.unpack $ Base16.encode $ encodeUtf8 $ "\"" <> renderTxIn (fst . List.head . UTxO.pairs $ utxoFromTx tx) <> "\"" + let path = BSC.unpack $ urlEncode False $ encodeUtf8 $ "\"" <> renderTxIn (fst . List.head . UTxO.pairs $ utxoFromTx tx) <> "\"" recoverResp <- -- TODO: use slash instead of question mark to utilize the path instead of query params - parseUrlThrow ("DELETE " <> hydraNodeBaseUrl n1 <> "/commits?" <> queryStr) + parseUrlThrow ("DELETE " <> hydraNodeBaseUrl n1 <> "/commits/" <> path) >>= httpJSON (getResponseBody recoverResp :: String) `shouldBe` "OK" diff --git a/hydra-node/src/Hydra/API/HTTPServer.hs b/hydra-node/src/Hydra/API/HTTPServer.hs index de8d7a9fc77..81ac9f5f402 100644 --- a/hydra-node/src/Hydra/API/HTTPServer.hs +++ b/hydra-node/src/Hydra/API/HTTPServer.hs @@ -7,7 +7,6 @@ import Hydra.Prelude import Cardano.Ledger.Core (PParams) import Data.Aeson (KeyValue ((.=)), object, withObject, (.:)) import Data.Aeson qualified as Aeson -import Data.ByteString.Base16 qualified as Base16 import Data.ByteString.Lazy qualified as LBS import Data.ByteString.Short () import Data.Text (pack) @@ -30,13 +29,12 @@ import Hydra.Tx ( IsTx (..), UTxOType, ) -import Network.HTTP.Types (QueryItem, status200, status400, status404, status500) +import Network.HTTP.Types (status200, status400, status404, status500) import Network.Wai ( Application, Request (pathInfo, requestMethod), Response, consumeRequestBodyStrict, - queryString, rawPathInfo, responseLBS, ) @@ -152,33 +150,33 @@ httpApp tracer directChain pparams getCommitInfo getConfirmedUTxO putClientInput , path = PathInfo $ rawPathInfo request } case (requestMethod request, pathInfo request) of - ("GET", ["snapshot", "utxo"]) -> - -- XXX: Should ensure the UTxO is of the right head and the head is still - -- open. This is something we should fix on the "read model" side of the - -- server. - getConfirmedUTxO >>= \case - Nothing -> respond notFound - Just utxo -> respond $ okJSON utxo - ("POST", ["commit"]) -> - consumeRequestBodyStrict request - >>= handleDraftCommitUtxo directChain getCommitInfo - >>= respond - ("DELETE", ["commits"]) -> - consumeRequestBodyStrict request - >>= handleRecoverCommitUtxo directChain putClientInput (queryString request) - >>= respond - ("POST", ["decommit"]) -> - consumeRequestBodyStrict request - >>= handleDecommit putClientInput - >>= respond - ("GET", ["protocol-parameters"]) -> - respond . responseLBS status200 [] . Aeson.encode $ pparams - ("POST", ["cardano-transaction"]) -> - consumeRequestBodyStrict request - >>= handleSubmitUserTx directChain - >>= respond - _ -> - respond $ responseLBS status400 [] "Resource not found" + ("GET", ["snapshot", "utxo"]) -> + -- XXX: Should ensure the UTxO is of the right head and the head is still + -- open. This is something we should fix on the "read model" side of the + -- server. + getConfirmedUTxO >>= \case + Nothing -> respond notFound + Just utxo -> respond $ okJSON utxo + ("POST", ["commit"]) -> + consumeRequestBodyStrict request + >>= handleDraftCommitUtxo directChain getCommitInfo + >>= respond + ("DELETE", ["commits", _]) -> + consumeRequestBodyStrict request + >>= handleRecoverCommitUtxo directChain putClientInput (last . fromList $ pathInfo request) + >>= respond + ("POST", ["decommit"]) -> + consumeRequestBodyStrict request + >>= handleDecommit putClientInput + >>= respond + ("GET", ["protocol-parameters"]) -> + respond . responseLBS status200 [] . Aeson.encode $ pparams + ("POST", ["cardano-transaction"]) -> + consumeRequestBodyStrict request + >>= handleSubmitUserTx directChain + >>= respond + _ -> + respond $ responseLBS status400 [] "Resource not found" -- * Handlers @@ -245,11 +243,11 @@ handleRecoverCommitUtxo :: IsChainState tx => Chain tx IO -> (ClientInput tx -> IO ()) -> - [QueryItem] -> + Text -> LBS.ByteString -> IO Response -handleRecoverCommitUtxo directChain putClientInput recoverQuery _body = do - case checkRecover recoverQuery of +handleRecoverCommitUtxo directChain putClientInput recoverPath _body = do + case parseTxInFromPath recoverPath of Left err -> pure err Right recoverTxIn -> draftRecoverTx recoverTxIn >>= \case @@ -258,13 +256,10 @@ handleRecoverCommitUtxo directChain putClientInput recoverQuery _body = do putClientInput Recover{recoverTx} pure $ responseLBS status200 [] (Aeson.encode $ Aeson.String "OK") where - checkRecover query = - case Base16.decode $ foldMap fst query of - Left e -> Left (responseLBS status400 [] (Aeson.encode $ Aeson.String $ "Cannot recover funds. Failed to decode TxIn string: " <> pack e)) - Right txInStr -> - case Aeson.eitherDecode (fromStrict txInStr) :: Either String TxIn of - Left e -> Left (responseLBS status400 [] (Aeson.encode $ Aeson.String $ "Cannot recover funds. Failed to parse TxIn: " <> pack e)) - Right txIn -> Right txIn + parseTxInFromPath txInStr = + case Aeson.eitherDecode (encodeUtf8 txInStr) :: Either String TxIn of + Left e -> Left (responseLBS status400 [] (Aeson.encode $ Aeson.String $ "Cannot recover funds. Failed to parse TxIn: " <> pack e)) + Right txIn -> Right txIn Chain{draftRecoverTx} = directChain