Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a hydra-explorer executable that can track all heads on-chain #1235

Merged
merged 58 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
0dc6ab9
Add base e2e test for hydra-exporer
ffakenz Jan 5, 2024
590ac43
Create base explorer project
ffakenz Jan 5, 2024
e814444
Reuse the hydra-chain-observer library code to collect the observations
ffakenz Jan 5, 2024
baaa267
Fix after rebase: remove pparams arg from withHydraNode process
ffakenz Jan 10, 2024
5cb2347
Add GET /heads e2e spec
ffakenz Jan 10, 2024
13a0cc6
Draft http server for explorer
ffakenz Jan 10, 2024
73f5cdd
Introduce ObserverHandler as callback to chain-observer
ffakenz Jan 11, 2024
5273ccc
Simplify endpoint
ffakenz Jan 11, 2024
5a1cb53
Add e2e spec to explore multiple heads in the past
ffakenz Jan 11, 2024
8ccfdf1
Add check process has not die to hydra-explorer in e2e specs
ffakenz Jan 11, 2024
3b7822d
Fix minor typo on observations
ffakenz Jan 12, 2024
184cc2c
Make hydra-cluster depend on hydra-explorer to run tests
ch1bo Jan 12, 2024
844ca02
Add point to RollForward to see slots pass
ch1bo Jan 12, 2024
d597222
Refactor explorer e2e test slightly
ch1bo Jan 12, 2024
4b6ec50
Start explorer from genesis
ffakenz Jan 12, 2024
69a00e4
Enhance e2e spec over api
ffakenz Jan 12, 2024
9befece
Draft some plumbing in explorer HTTP server
ch1bo Jan 12, 2024
d2b2dfe
Make use of ObserverHandler during roll forward
ffakenz Jan 12, 2024
c2a59be
Fix GetHeadIds read model
ch1bo Jan 12, 2024
6dbc9dd
Draft openapi
ffakenz Jan 15, 2024
448d62a
Introduce ipc server on chain-observer
ffakenz Jan 15, 2024
20cc187
Revert "Introduce ipc server on chain-observer"
ffakenz Jan 16, 2024
adcc8fe
Enhance explorer state to be an aggregation of head observations
ffakenz Jan 18, 2024
580deaf
Aggregate observations into explorer state
ffakenz Jan 18, 2024
2eacbb0
Fix assertion for the HeadId equality
v0d1ch Jan 18, 2024
c915090
Add api server spec to validate openapi schema against server responses
ffakenz Jan 19, 2024
3b71137
Fix match openapi schema spec
ffakenz Jan 22, 2024
9d15d5b
Ehance e2e spec for explorer
ffakenz Jan 22, 2024
03cfee9
Fix chain-observer spec as observeTx is now returning a head observation
ffakenz Jan 23, 2024
25d25bc
Remove unused packages
ffakenz Jan 23, 2024
31bdbc0
Minor fix to readme run cmd
ffakenz Jan 23, 2024
6b815d4
Remove prints before server starts as traces already log this info
ffakenz Jan 23, 2024
b221cb8
Improve README.md spelling
ffakenz Jan 23, 2024
f3e3a0a
Remove not needed endpoints
ffakenz Jan 23, 2024
92bfead
Remove unnecessary handle from withChainObserver and withHydraExplore…
ffakenz Jan 23, 2024
155fad5
Update README
ffakenz Jan 23, 2024
c1f81cc
Refactor e2e to use http simple library instead
ffakenz Jan 23, 2024
9de27ed
Remove unimplemented endpoint from openapi spec
ffakenz Jan 23, 2024
8590af7
Rename test module to match where the actual code is implemented
ffakenz Jan 23, 2024
41b6cf7
Improve explorer spec to only assert on headers that we care about
ffakenz Jan 23, 2024
de9e943
Update explorer api spec to specify required fields
ffakenz Jan 23, 2024
d9d9853
Use eitherDecode to print why the responded bytes where not a proper …
ffakenz Jan 23, 2024
bdb28b8
Refactor HydraExplorerHandle as an easy access to the API (= a client)
ffakenz Jan 23, 2024
4f0b0eb
Remove unused import from chain observer e2e spec
ffakenz Jan 23, 2024
291c792
Replace PartyCommit by UTxO type
ffakenz Jan 23, 2024
c49c38a
Increase the time dealy to wait for the explorer http server to be li…
ffakenz Jan 23, 2024
24fde0f
Draft property spec for aggregate head observations
ffakenz Jan 24, 2024
8309f53
Update aggregate observation logic to fulfill the expected properties
ffakenz Jan 24, 2024
6740648
Refactor aggregation to work over OnChainTx type instead of HeadObser…
ffakenz Jan 25, 2024
a9e4809
Add tracking of contestation deadline as part of explorer's head states
ffakenz Jan 25, 2024
dca46e5
Add head state haddock
ffakenz Jan 25, 2024
44e3d76
Remove unsupported attribute propertyNames by swagger
ffakenz Jan 25, 2024
9ce5965
Minor fix after rebasing
ffakenz Jan 25, 2024
ea0aa8e
Use 5 ADA for internal wallets
v0d1ch Jan 25, 2024
35a9479
Remove misplaced comment
v0d1ch Jan 25, 2024
0f3ba3b
Refactor http server to use servant
ffakenz Jan 26, 2024
3e7b2d2
Fix explorer e2e specs by increasing the amount of fuel provided to e…
ffakenz Jan 26, 2024
594558b
Minor formatting changes
ffakenz Jan 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cabal.project
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ packages:
hydra-tui
hydraw
hydra-chain-observer
hydra-explorer

-- Compile more things in parallel
package *
Expand Down
3 changes: 2 additions & 1 deletion hydra-chain-observer/exe/Main.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
module Main where

import Hydra.ChainObserver (defaultObserverHandler)
import Hydra.ChainObserver qualified
import Hydra.Prelude

main :: IO ()
main = Hydra.ChainObserver.main
main = Hydra.ChainObserver.main defaultObserverHandler
71 changes: 44 additions & 27 deletions hydra-chain-observer/src/Hydra/ChainObserver.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Hydra.Cardano.Api (
SocketPath,
Tx,
UTxO,
chainTipToChainPoint,
connectToLocalNode,
getTxBody,
getTxId,
Expand Down Expand Up @@ -52,8 +53,13 @@ import Ouroboros.Network.Protocol.ChainSync.Client (
ClientStNext (..),
)

main :: IO ()
main = do
type ObserverHandler m = [HeadObservation] -> m ()

defaultObserverHandler :: Applicative m => ObserverHandler m
defaultObserverHandler = const $ pure ()

main :: ObserverHandler IO -> IO ()
main observerHandler = do
Options{networkId, nodeSocket, startChainFrom} <- execParser hydraChainObserverOptions
withTracer (Verbose "hydra-chain-observer") $ \tracer -> do
traceWith tracer KnownScripts{scriptInfo = Contract.scriptInfo}
Expand All @@ -64,7 +70,7 @@ main = do
traceWith tracer StartObservingFrom{chainPoint}
connectToLocalNode
(connectInfo nodeSocket networkId)
(clientProtocols tracer networkId chainPoint)
(clientProtocols tracer networkId chainPoint observerHandler)

type ChainObserverLog :: Type
data ChainObserverLog
Expand All @@ -79,7 +85,7 @@ data ChainObserverLog
| HeadAbortTx {headId :: HeadId}
| HeadContestTx {headId :: HeadId}
| Rollback {point :: ChainPoint}
| RollForward {receivedTxIds :: [TxId]}
| RollForward {point :: ChainPoint, receivedTxIds :: [TxId]}
deriving stock (Eq, Show, Generic)
deriving anyclass (ToJSON)

Expand All @@ -101,10 +107,11 @@ clientProtocols ::
Tracer IO ChainObserverLog ->
NetworkId ->
ChainPoint ->
ObserverHandler IO ->
LocalNodeClientProtocols BlockType ChainPoint ChainTip slot tx txid txerr query IO
clientProtocols tracer networkId startingPoint =
clientProtocols tracer networkId startingPoint observerHandler =
LocalNodeClientProtocols
{ localChainSyncClient = LocalChainSyncClient $ chainSyncClient tracer networkId startingPoint
{ localChainSyncClient = LocalChainSyncClient $ chainSyncClient tracer networkId startingPoint observerHandler
, localTxSubmissionClient = Nothing
, localStateQueryClient = Nothing
, localTxMonitoringClient = Nothing
Expand All @@ -128,8 +135,9 @@ chainSyncClient ::
Tracer m ChainObserverLog ->
NetworkId ->
ChainPoint ->
ObserverHandler m ->
ChainSyncClient BlockType ChainPoint ChainTip m ()
chainSyncClient tracer networkId startingPoint =
chainSyncClient tracer networkId startingPoint observerHandler =
ChainSyncClient $
pure $
SendMsgFindIntersect [startingPoint] clientStIntersect
Expand All @@ -143,44 +151,53 @@ chainSyncClient tracer networkId startingPoint =
ChainSyncClient $ throwIO (IntersectionNotFound startingPoint)
}

clientStIdle :: UTxO -> ClientStIdle BlockType ChainPoint tip m ()
clientStIdle :: UTxO -> ClientStIdle BlockType ChainPoint ChainTip m ()
clientStIdle utxo = SendMsgRequestNext (clientStNext utxo) (pure $ clientStNext utxo)

clientStNext :: UTxO -> ClientStNext BlockType ChainPoint tip m ()
clientStNext :: UTxO -> ClientStNext BlockType ChainPoint ChainTip m ()
clientStNext utxo =
ClientStNext
{ recvMsgRollForward = \blockInMode _tip -> ChainSyncClient $ do
{ recvMsgRollForward = \blockInMode tip -> ChainSyncClient $ do
case blockInMode of
BlockInMode _ (Block _header txs) BabbageEraInCardanoMode -> do
traceWith tracer RollForward{receivedTxIds = getTxId . getTxBody <$> txs}
let (utxo', logs) = observeAll networkId utxo txs
forM_ logs (traceWith tracer)
let point = chainTipToChainPoint tip
let receivedTxIds = getTxId . getTxBody <$> txs
traceWith tracer RollForward{point, receivedTxIds}
let (utxo', observations) = observeAll networkId utxo txs
-- FIXME we should be exposing OnChainTx instead of working around NoHeadTx.
forM_ observations (maybe (pure ()) (traceWith tracer) . logObservation)
observerHandler observations
pure $ clientStIdle utxo'
_ -> pure $ clientStIdle utxo
, recvMsgRollBackward = \point _tip -> ChainSyncClient $ do
traceWith tracer Rollback{point}
pure $ clientStIdle utxo
}

observeTx :: NetworkId -> UTxO -> Tx -> (UTxO, Maybe ChainObserverLog)
logObservation :: HeadObservation -> Maybe ChainObserverLog
logObservation = \case
NoHeadTx -> Nothing
Init InitObservation{headId} -> pure $ HeadInitTx{headId}
Commit CommitObservation{headId} -> pure $ HeadCommitTx{headId}
CollectCom CollectComObservation{headId} -> pure $ HeadCollectComTx{headId}
Close CloseObservation{headId} -> pure $ HeadCloseTx{headId}
Fanout FanoutObservation{headId} -> pure $ HeadFanoutTx{headId}
Abort AbortObservation{headId} -> pure $ HeadAbortTx{headId}
Contest ContestObservation{headId} -> pure $ HeadContestTx{headId}

observeTx :: NetworkId -> UTxO -> Tx -> (UTxO, Maybe HeadObservation)
observeTx networkId utxo tx =
let utxo' = adjustUTxO tx utxo
in case observeHeadTx networkId utxo tx of
NoHeadTx -> (utxo, Nothing)
Init InitObservation{headId} -> (utxo', pure $ HeadInitTx{headId})
Commit CommitObservation{headId} -> (utxo', pure $ HeadCommitTx{headId})
CollectCom CollectComObservation{headId} -> (utxo', pure $ HeadCollectComTx{headId})
Close CloseObservation{headId} -> (utxo', pure $ HeadCloseTx{headId})
Fanout FanoutObservation{headId} -> (utxo', pure $ HeadFanoutTx{headId})
Abort AbortObservation{headId} -> (utxo', pure $ HeadAbortTx{headId})
Contest ContestObservation{headId} -> (utxo', pure $ HeadContestTx{headId})

observeAll :: NetworkId -> UTxO -> [Tx] -> (UTxO, [ChainObserverLog])
observation -> (utxo', pure observation)

observeAll :: NetworkId -> UTxO -> [Tx] -> (UTxO, [HeadObservation])
observeAll networkId utxo txs =
second reverse $ foldr go (utxo, []) txs
where
go :: Tx -> (UTxO, [ChainObserverLog]) -> (UTxO, [ChainObserverLog])
go tx (utxo'', logs) =
go :: Tx -> (UTxO, [HeadObservation]) -> (UTxO, [HeadObservation])
go tx (utxo'', observations) =
case observeTx networkId utxo'' tx of
(utxo', Nothing) -> (utxo', logs)
(utxo', Just logEntry) -> (utxo', logEntry : logs)
(utxo', Nothing) -> (utxo', observations)
(utxo', Just observation) -> (utxo', observation : observations)
17 changes: 9 additions & 8 deletions hydra-chain-observer/test/Hydra/ChainObserverSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import Test.Hydra.Prelude
import Hydra.Chain.Direct.Fixture (testNetworkId)
import Hydra.Chain.Direct.State (HasKnownUTxO (getKnownUTxO), genChainStateWithTx)
import Hydra.Chain.Direct.State qualified as Transition
import Hydra.ChainObserver (ChainObserverLog (..), observeAll, observeTx)
import Hydra.Chain.Direct.Tx (HeadObservation (..))
import Hydra.ChainObserver (observeAll, observeTx)
import Hydra.Ledger.Cardano (genSequenceOfSimplePaymentTransactions)
import Test.QuickCheck (counterexample, forAll, forAllBlind, property, (=/=), (===))
import Test.QuickCheck.Property (checkCoverage)
Expand All @@ -21,13 +22,13 @@ spec =
counterexample (show transition) $
let utxo = getKnownUTxO st
in case snd $ observeTx testNetworkId utxo tx of
Just (HeadInitTx{}) -> transition === Transition.Init
Just (HeadCommitTx{}) -> transition === Transition.Commit
Just (HeadCollectComTx{}) -> transition === Transition.Collect
Just (HeadAbortTx{}) -> transition === Transition.Abort
Just (HeadCloseTx{}) -> transition === Transition.Close
Just (HeadContestTx{}) -> transition === Transition.Contest
Just (HeadFanoutTx{}) -> transition === Transition.Fanout
Just (Init{}) -> transition === Transition.Init
Just (Commit{}) -> transition === Transition.Commit
Just (CollectCom{}) -> transition === Transition.Collect
Just (Abort{}) -> transition === Transition.Abort
Just (Close{}) -> transition === Transition.Close
Just (Contest{}) -> transition === Transition.Contest
Just (Fanout{}) -> transition === Transition.Fanout
_ -> property False

prop "Updates UTxO state given transaction part of Head lifecycle" $
Expand Down
4 changes: 4 additions & 0 deletions hydra-cluster/hydra-cluster.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ test-suite tests
Test.Hydra.Cluster.CardanoCliSpec
Test.Hydra.Cluster.FaucetSpec
Test.Hydra.Cluster.MithrilSpec
Test.HydraExplorerSpec
Test.OfflineChainSpec

build-depends:
Expand All @@ -168,6 +169,8 @@ test-suite tests
, directory
, filepath
, hspec
, http-client
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could: remove this as http-conduit includes the same things

, http-conduit
, hydra-cardano-api
, hydra-cluster
, hydra-node:{hydra-node, testlib}
Expand All @@ -185,6 +188,7 @@ test-suite tests
build-tool-depends:
, hspec-discover:hspec-discover
, hydra-chain-observer:hydra-chain-observer
, hydra-explorer:hydra-explorer
, hydra-node:hydra-node

ghc-options: -threaded -rtsopts
Expand Down
16 changes: 5 additions & 11 deletions hydra-cluster/test/Test/ChainObserverSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import Test.Hydra.Prelude
import CardanoClient (RunningNode (..), submitTx)
import CardanoNode (NodeLog, withCardanoNodeDevnet)
import Control.Concurrent.Class.MonadSTM (modifyTVar', newTVarIO, readTVarIO)
import Control.Exception (IOException)
import Control.Lens ((^?))
import Data.Aeson as Aeson
import Data.Aeson.Lens (key, _String)
Expand Down Expand Up @@ -112,16 +111,11 @@ data ChainObserverLog
-- | Starts a 'hydra-chain-observer' on some Cardano network.
withChainObserver :: RunningNode -> (ChainObserverHandle -> IO ()) -> IO ()
withChainObserver cardanoNode action =
-- XXX: If this throws an IOException, 'withFile' invocations around mislead
-- to the file path opened (e.g. the cardano-node log file) in the test
-- failure output. Print the exception here to have some debuggability at
-- least.
handle (\(e :: IOException) -> print e >> throwIO e) $
withCreateProcess process{std_out = CreatePipe} $ \_in (Just out) _err _ph ->
action
ChainObserverHandle
{ awaitNext = awaitNext out
}
withCreateProcess process{std_out = CreatePipe} $ \_in (Just out) _err _ph ->
action
ChainObserverHandle
{ awaitNext = awaitNext out
}
where
awaitNext :: Handle -> IO Aeson.Value
awaitNext out = do
Expand Down
134 changes: 134 additions & 0 deletions hydra-cluster/test/Test/HydraExplorerSpec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
{-# LANGUAGE DeriveAnyClass #-}

-- | Integration tests for the 'hydra-explorer' executable. These will run
-- also 'hydra-node' on a devnet and assert correct observation.
module Test.HydraExplorerSpec where

import Hydra.Prelude hiding (get)
import Test.Hydra.Prelude

import CardanoClient (RunningNode (..))
import CardanoNode (NodeLog, withCardanoNodeDevnet)
import Control.Lens ((^.), (^?))
import Data.Aeson as Aeson
import Data.Aeson.Lens (key, nth, _Array, _String)
import Hydra.Cardano.Api (NetworkId (..), NetworkMagic (..), unFile)
import Hydra.Cluster.Faucet (FaucetLog, publishHydraScriptsAs, seedFromFaucet_)
import Hydra.Cluster.Fixture (Actor (..), aliceSk, bobSk, cperiod)
import Hydra.Cluster.Util (chainConfigFor, keysFor)
import Hydra.Logging (showLogsOnFailure)
import HydraNode (HydraNodeLog, input, send, waitMatch, withHydraNode)
import Network.HTTP.Client (responseBody)
import Network.HTTP.Simple (httpJSON, parseRequestThrow)
import System.Process (CreateProcess (..), StdStream (..), proc, withCreateProcess)

spec :: Spec
spec = do
it "can observe hydra transactions created by multiple hydra-nodes" $
failAfter 60 $
showLogsOnFailure "HydraExplorerSpec" $ \tracer -> do
withTempDir "hydra-explorer-history" $ \tmpDir -> do
withCardanoNodeDevnet (contramap FromCardanoNode tracer) tmpDir $ \cardanoNode@RunningNode{nodeSocket} -> do
let hydraTracer = contramap FromHydraNode tracer
hydraScriptsTxId <- publishHydraScriptsAs cardanoNode Faucet

let initHead hydraNode = do
send hydraNode $ input "Init" []
waitMatch 5 hydraNode $ \v -> do
guard $ v ^? key "tag" == Just "HeadIsInitializing"
v ^? key "headId" . _String

(aliceCardanoVk, _aliceCardanoSk) <- keysFor Alice
aliceChainConfig <- chainConfigFor Alice tmpDir nodeSocket hydraScriptsTxId [] cperiod
seedFromFaucet_ cardanoNode aliceCardanoVk 25_000_000 (contramap FromFaucet tracer)
aliceHeadId <- withHydraNode hydraTracer aliceChainConfig tmpDir 1 aliceSk [] [1] initHead

(bobCardanoVk, _bobCardanoSk) <- keysFor Bob
bobChainConfig <- chainConfigFor Bob tmpDir nodeSocket hydraScriptsTxId [] cperiod
seedFromFaucet_ cardanoNode bobCardanoVk 25_000_000 (contramap FromFaucet tracer)
bobHeadId <- withHydraNode hydraTracer bobChainConfig tmpDir 2 bobSk [] [2] initHead

withHydraExplorer cardanoNode $ \explorer -> do
allHeads <- getHeads explorer
length (allHeads ^. _Array) `shouldBe` 2
allHeads ^. nth 0 . key "headId" . _String `shouldBe` aliceHeadId
allHeads ^. nth 0 . key "status" . _String `shouldBe` "Initializing"
allHeads ^. nth 1 . key "headId" . _String `shouldBe` bobHeadId
allHeads ^. nth 1 . key "status" . _String `shouldBe` "Initializing"

it "can query for all hydra heads observed" $
failAfter 60 $
showLogsOnFailure "HydraExplorerSpec" $ \tracer -> do
withTempDir "hydra-explorer-get-heads" $ \tmpDir -> do
withCardanoNodeDevnet (contramap FromCardanoNode tracer) tmpDir $ \cardanoNode@RunningNode{nodeSocket} -> do
let hydraTracer = contramap FromHydraNode tracer
hydraScriptsTxId <- publishHydraScriptsAs cardanoNode Faucet
withHydraExplorer cardanoNode $ \explorer -> do
(aliceCardanoVk, _aliceCardanoSk) <- keysFor Alice
aliceChainConfig <- chainConfigFor Alice tmpDir nodeSocket hydraScriptsTxId [] cperiod
seedFromFaucet_ cardanoNode aliceCardanoVk 25_000_000 (contramap FromFaucet tracer)
aliceHeadId <- withHydraNode hydraTracer aliceChainConfig tmpDir 1 aliceSk [] [1] $ \hydraNode -> do
v0d1ch marked this conversation as resolved.
Show resolved Hide resolved
send hydraNode $ input "Init" []

waitMatch 5 hydraNode $ \v -> do
guard $ v ^? key "tag" == Just "HeadIsInitializing"
v ^? key "headId" . _String

(bobCardanoVk, _bobCardanoSk) <- keysFor Bob
bobChainConfig <- chainConfigFor Bob tmpDir nodeSocket hydraScriptsTxId [] cperiod
seedFromFaucet_ cardanoNode bobCardanoVk 25_000_000 (contramap FromFaucet tracer)
bobHeadId <- withHydraNode hydraTracer bobChainConfig tmpDir 2 bobSk [] [2] $ \hydraNode -> do
send hydraNode $ input "Init" []

bobHeadId <- waitMatch 5 hydraNode $ \v -> do
guard $ v ^? key "tag" == Just "HeadIsInitializing"
v ^? key "headId" . _String

send hydraNode $ input "Abort" []

waitMatch 5 hydraNode $ \v -> do
guard $ v ^? key "tag" == Just "HeadIsAborted"
guard $ v ^? key "headId" . _String == Just bobHeadId

pure bobHeadId

allHeads <- getHeads explorer
length (allHeads ^. _Array) `shouldBe` 2
allHeads ^. nth 0 . key "headId" . _String `shouldBe` aliceHeadId
allHeads ^. nth 0 . key "status" . _String `shouldBe` "Initializing"
allHeads ^. nth 1 . key "headId" . _String `shouldBe` bobHeadId
allHeads ^. nth 1 . key "status" . _String `shouldBe` "Aborted"

newtype HydraExplorerHandle = HydraExplorerHandle {getHeads :: IO Value}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


data HydraExplorerLog
v0d1ch marked this conversation as resolved.
Show resolved Hide resolved
= FromCardanoNode NodeLog
| FromHydraNode HydraNodeLog
| FromFaucet FaucetLog
deriving (Eq, Show, Generic)
deriving anyclass (ToJSON)

-- | Starts a 'hydra-explorer' on some Cardano network.
withHydraExplorer :: RunningNode -> (HydraExplorerHandle -> IO ()) -> IO ()
withHydraExplorer cardanoNode action =
withCreateProcess process{std_out = CreatePipe, std_err = CreatePipe} $
\_in _stdOut err processHandle ->
race
(checkProcessHasNotDied "hydra-explorer" processHandle err)
( -- XXX: wait for the http server to be listening on port
threadDelay 3
*> action HydraExplorerHandle{getHeads}
)
<&> either absurd id
where
getHeads = responseBody <$> (parseRequestThrow "http://127.0.0.1:9090/heads" >>= httpJSON)

process =
proc
"hydra-explorer"
$ ["--node-socket", unFile nodeSocket]
<> case networkId of
Mainnet -> ["--mainnet"]
Testnet (NetworkMagic magic) -> ["--testnet-magic", show magic]

RunningNode{nodeSocket, networkId} = cardanoNode
Loading
Loading