Skip to content

Commit b26f832

Browse files
committed
Complete minimal example, Multiple minor fixes
1 parent 743b379 commit b26f832

File tree

18 files changed

+208
-122
lines changed

18 files changed

+208
-122
lines changed

Makefile

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
.PHONY: build, format, repl, docs, build-example, run-example
1+
.PHONY: build, format, repl, docs, build-example, run-example, docker-cleanup
22

33
ps-sources := $(shell fd --no-ignore-parent -epurs)
44
nix-sources := $(shell fd --no-ignore-parent -enix --exclude='spago*')
55
purs-args := "--stash --censor-lib --censor-codes=ImplicitImport,ImplicitQualifiedImport,ImplicitQualifiedImportReExport,UserDefinedWarning"
6+
example-docker := example/minimal/docker/cluster/docker-compose.yaml
67

78
system := $(shell uname -s)
89
ifeq (${system},Linux)
@@ -36,5 +37,9 @@ build-example:
3637
cd example/minimal && \
3738
spago build --purs-args ${purs-args}
3839

39-
run-example:
40-
docker compose -f example/minimal/docker/cluster/docker-compose.yaml up --build --no-attach cardano-node
40+
run-example: docker-cleanup
41+
docker compose -f ${example-docker} up --build --no-attach cardano-node
42+
43+
docker-cleanup:
44+
docker compose -f ${example-docker} rm --force --stop
45+
docker volume rm -f cluster_hydra-persist-a cluster_hydra-persist-b

example/minimal/app/Main.purs

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,23 @@ module HydraSdk.Example.Minimal.Main
55
import Prelude
66

77
import Cardano.AsCbor (encodeCbor)
8+
import Cardano.Types (Language(PlutusV2), Transaction)
89
import Contract.CborBytes (cborBytesToHex)
910
import Contract.Log (logError', logInfo', logTrace', logWarn')
10-
import Contract.Monad (ContractEnv, stopContractEnv)
11+
import Contract.Monad (Contract, ContractEnv, stopContractEnv)
12+
import Contract.ProtocolParameters (getProtocolParameters)
1113
import Contract.Transaction (submit)
1214
import Control.Monad.Error.Class (throwError)
1315
import Control.Monad.Reader (ask)
16+
import Ctl.Internal.Transaction (setScriptDataHash)
1417
import Data.Argonaut (stringifyWithIndent)
18+
import Data.Array (length) as Array
1519
import Data.Codec.Argonaut (encode) as CA
1620
import Data.Either (Either(Left, Right))
1721
import Data.Log.Level (LogLevel(Info, Error))
18-
import Data.Map (empty, fromFoldable) as Map
22+
import Data.Map (empty, filterKeys, fromFoldable) as Map
1923
import Data.Maybe (Maybe(Just, Nothing))
24+
import Data.Newtype (unwrap)
2025
import Data.Posix.Signal (Signal(SIGINT, SIGTERM))
2126
import Data.Traversable (traverse_)
2227
import Data.UInt (fromInt) as UInt
@@ -34,12 +39,14 @@ import HydraSdk.Example.Minimal.App
3439
, appLogger
3540
, initApp
3641
, readHeadStatus
42+
, readUtxoSnapshot
3743
, runAppEff
3844
, runContractInApp
3945
)
4046
import HydraSdk.Example.Minimal.App (setHeadStatus, setUtxoSnapshot) as App
4147
import HydraSdk.Example.Minimal.Config (configFromArgv)
42-
import HydraSdk.Lib (log')
48+
import HydraSdk.Example.Minimal.Contract.L2 (placeArbitraryDatumL2)
49+
import HydraSdk.Lib (log', reSignTransaction, setAuxDataHash)
4350
import HydraSdk.NodeApi
4451
( HydraNodeApiWebSocket
4552
, HydraTxRetryStrategy(RetryTxWithParams, DontRetryTx)
@@ -53,8 +60,19 @@ import HydraSdk.Types
5360
, HeadStatus_Initializing
5461
, HeadStatus_Open
5562
, HeadStatus_Closed
63+
, HeadStatus_FanoutPossible
64+
, HeadStatus_Final
65+
)
66+
, HydraNodeApi_InMessage
67+
( Greetings
68+
, HeadIsInitializing
69+
, HeadIsOpen
70+
, SnapshotConfirmed
71+
, HeadIsClosed
72+
, HeadIsContested
73+
, ReadyToFanout
74+
, HeadIsFinalized
5675
)
57-
, HydraNodeApi_InMessage(Greetings, HeadIsInitializing, HeadIsOpen)
5876
, HydraSnapshot(HydraSnapshot)
5977
, hydraSnapshotCodec
6078
, mkSimpleCommitRequest
@@ -161,7 +179,7 @@ messageHandler ws =
161179
throwError $ error $ "Commit request failed with error: "
162180
<> show httpErr
163181
Right { cborHex: commitTx } -> do
164-
txHash <- runContractInApp $ submit commitTx
182+
txHash <- runContractInApp $ submit =<< fixCommitTx commitTx
165183
logInfo' $ "Submitted Commit transaction: " <> cborBytesToHex
166184
(encodeCbor txHash)
167185
HeadIsOpen { headId, utxo } -> do
@@ -171,8 +189,52 @@ messageHandler ws =
171189
{ snapshotNumber: zero
172190
, utxo
173191
}
192+
tx <- runContractInApp $ placeArbitraryDatumL2 $ toUtxoMap utxo
193+
liftEffect $ ws.submitTxL2 tx
194+
SnapshotConfirmed { snapshot } -> do
195+
setUtxoSnapshot snapshot
196+
{ config: { hydraNodeStartupParams: { peers } } } <- ask
197+
when ((unwrap snapshot).snapshotNumber > Array.length peers) do
198+
logInfo' "All Head participants must have advanced the L2 state. Closing Head..."
199+
liftEffect ws.closeHead
200+
HeadIsClosed { snapshotNumber } -> do
201+
-- TODO: set head status implicitly
202+
setHeadStatus HeadStatus_Closed
203+
contestClosureIfNeeded ws snapshotNumber
204+
HeadIsContested { snapshotNumber } ->
205+
contestClosureIfNeeded ws snapshotNumber
206+
ReadyToFanout _ -> do
207+
setHeadStatus HeadStatus_FanoutPossible
208+
liftEffect ws.fanout
209+
HeadIsFinalized _ -> do
210+
setHeadStatus HeadStatus_Final
211+
-- TODO: output fanout tx hash
212+
throwError $ error "SUCCESS: Head finalized, Funds transfered to L1 - Exiting..."
174213
_ -> pure unit
175214

215+
fixCommitTx :: Transaction -> Contract Transaction
216+
fixCommitTx = reSignTransaction <=< fixScriptIntegrityHash <<< setAuxDataHash
217+
where
218+
fixScriptIntegrityHash :: Transaction -> Contract Transaction
219+
fixScriptIntegrityHash tx = do
220+
pparams <- unwrap <$> getProtocolParameters
221+
let
222+
costModels = Map.filterKeys (eq PlutusV2) pparams.costModels
223+
ws = unwrap (unwrap tx).witnessSet
224+
liftEffect $ setScriptDataHash costModels ws.redeemers ws.plutusData tx
225+
226+
contestClosureIfNeeded :: HydraNodeApiWebSocket AppM -> Int -> AppM Unit
227+
contestClosureIfNeeded ws closeSnapshot = do
228+
HydraSnapshot { snapshotNumber: localSnapshot } <- readUtxoSnapshot
229+
when (closeSnapshot < localSnapshot) do
230+
logInfo' $
231+
"Detected attempt to close the Head with older snapshot. Close snapshot: "
232+
<> show closeSnapshot
233+
<> ", local snapshot: "
234+
<> show localSnapshot
235+
<> ". Contesting Head closure..."
236+
liftEffect ws.challengeSnapshot
237+
176238
setHeadStatus :: HydraHeadStatus -> AppM Unit
177239
setHeadStatus status = do
178240
App.setHeadStatus status

example/minimal/docker/cluster/config-a.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"nodeSocket": "node-ipc/node.socket",
1414
"pparams": "protocol-parameters.json",
1515
"hydraScriptsTxHash": "03f8deb122fbbd98af8eb58ef56feda37728ec957d39586b78198a0cf624412a",
16-
"contestPeriodSec": 60,
16+
"contestPeriodSec": 120,
1717
"peers": [
1818
{
1919
"hydraNodeAddress": "delegate-node-b:7002",
@@ -24,5 +24,6 @@
2424
},
2525
"blockfrostApiKey": null,
2626
"logLevel": "trace",
27+
"ctlLogLevel": "warn",
2728
"commitOutRef": null
2829
}

example/minimal/docker/cluster/config-b.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"nodeSocket": "node-ipc/node.socket",
1414
"pparams": "protocol-parameters.json",
1515
"hydraScriptsTxHash": "03f8deb122fbbd98af8eb58ef56feda37728ec957d39586b78198a0cf624412a",
16-
"contestPeriodSec": 60,
16+
"contestPeriodSec": 120,
1717
"peers": [
1818
{
1919
"hydraNodeAddress": "delegate-node-a:7000",
@@ -23,6 +23,7 @@
2323
]
2424
},
2525
"blockfrostApiKey": null,
26-
"logLevel": "trace",
26+
"logLevel": "info",
27+
"ctlLogLevel": "warn",
2728
"commitOutRef": null
2829
}

example/minimal/docker/cluster/docker-compose.yaml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,47 +19,47 @@ services:
1919

2020
delegate-node-a:
2121
build:
22-
context: "../.."
23-
dockerfile: "docker/node/Dockerfile"
22+
context: "../../../.."
23+
dockerfile: "example/minimal/docker/node/Dockerfile"
2424
depends_on:
2525
cardano-node:
2626
condition: service_healthy
2727
command: "config.json"
2828
volumes:
2929
- type: "bind"
3030
source: "./config-a.json"
31-
target: "/app/config.json"
31+
target: "/app/example/minimal/config.json"
3232
- type: "bind"
3333
source: "keys"
34-
target: "/app/keys"
34+
target: "/app/example/minimal/keys"
3535
- type: "volume"
3636
source: "node-ipc"
37-
target: "/app/node-ipc"
37+
target: "/app/example/minimal/node-ipc"
3838
- type: "volume"
3939
source: "hydra-persist-a"
40-
target: "/app/hydra-persist"
40+
target: "/app/example/minimal/hydra-persist"
4141

4242
delegate-node-b:
4343
build:
44-
context: "../.."
45-
dockerfile: "docker/node/Dockerfile"
44+
context: "../../../.."
45+
dockerfile: "example/minimal/docker/node/Dockerfile"
4646
depends_on:
4747
cardano-node:
4848
condition: service_healthy
4949
command: "config.json"
5050
volumes:
5151
- type: "bind"
5252
source: "./config-b.json"
53-
target: "/app/config.json"
53+
target: "/app/example/minimal/config.json"
5454
- type: "bind"
5555
source: "keys"
56-
target: "/app/keys"
56+
target: "/app/example/minimal/keys"
5757
- type: "volume"
5858
source: "node-ipc"
59-
target: "/app/node-ipc"
59+
target: "/app/example/minimal/node-ipc"
6060
- type: "volume"
6161
source: "hydra-persist-b"
62-
target: "/app/hydra-persist"
62+
target: "/app/example/minimal/hydra-persist"
6363

6464
volumes:
6565
hydra-persist-a:

example/minimal/docker/node/Dockerfile

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,22 @@
33
FROM node:18
44
WORKDIR /app
55

6-
COPY package.json package-lock.json .
6+
COPY src src
7+
COPY spago.dhall spago.dhall
8+
9+
WORKDIR example/minimal
10+
11+
COPY example/minimal/package.json example/minimal/package-lock.json .
712
RUN npm clean-install --production=false --loglevel=verbose
813
RUN npm install purescript@0.15.8
914
RUN npm install spago@0.21.0
1015

11-
COPY packages.dhall spago.dhall .
16+
COPY example/minimal/packages.dhall example/minimal/spago.dhall .
1217
RUN npx --no-install spago install
1318

14-
COPY src src
15-
COPY app app
16-
COPY protocol-parameters.json .
19+
COPY example/minimal/src src
20+
COPY example/minimal/app app
21+
COPY example/minimal/protocol-parameters.json .
1722
RUN npx --no-install spago build
1823

1924
RUN curl -LO https://github.com/input-output-hk/hydra/releases/download/0.19.0/hydra-x86_64-linux-0.19.0.zip

example/minimal/packages.dhall

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ let upstream =
33
sha256:3e9fbc9ba03e9a1fcfd895f65e2d50ee2f5e86c4cd273f3d5c841b655a0e1bda
44

55
let additions =
6-
{ aeson =
6+
{ hydra-sdk = ../../spago.dhall as Location
7+
, aeson =
78
{ dependencies =
89
[ "aff"
910
, "argonaut"
@@ -601,59 +602,6 @@ let additions =
601602
, repo = "https://github.com/passy/purescript-errors.git"
602603
, version = "670485beb1e026f77d52ca58ce10c145d96c11ba"
603604
}
604-
, hydra-sdk =
605-
{ dependencies =
606-
[ "aff"
607-
, "affjax"
608-
, "argonaut"
609-
, "arrays"
610-
, "avar"
611-
, "bifunctors"
612-
, "bytearrays"
613-
, "cardano-transaction-lib"
614-
, "cardano-types"
615-
, "codec-argonaut"
616-
, "control"
617-
, "datetime"
618-
, "effect"
619-
, "either"
620-
, "errors"
621-
, "exceptions"
622-
, "foldable-traversable"
623-
, "foreign-object"
624-
, "formatters"
625-
, "http-methods"
626-
, "integers"
627-
, "js-bigints"
628-
, "js-date"
629-
, "maybe"
630-
, "monad-logger"
631-
, "newtype"
632-
, "node-buffer"
633-
, "node-child-process"
634-
, "node-path"
635-
, "node-streams"
636-
, "optparse"
637-
, "ordered-collections"
638-
, "parsing"
639-
, "partial"
640-
, "plutus-types"
641-
, "prelude"
642-
, "profunctor"
643-
, "quickcheck"
644-
, "safely"
645-
, "strings"
646-
, "tailrec"
647-
, "transformers"
648-
, "tuples"
649-
, "uint"
650-
, "uri"
651-
, "uuid"
652-
, "variant"
653-
]
654-
, repo = "https://github.com/mlabs-haskell/purescript-hydra-sdk"
655-
, version = "fde44498050dda20af5541ce7b9d6970be541a86"
656-
}
657605
}
658606

659-
in (upstream // additions)
607+
in (upstream // additions)

example/minimal/spago.dhall

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
, "posix-types"
2323
, "prelude"
2424
, "profunctor-lenses"
25+
, "quickcheck"
2526
, "refs"
2627
, "transformers"
2728
, "tuples"

example/minimal/src/App.purs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module HydraSdk.Example.Minimal.App
55
, appLogger
66
, initApp
77
, readHeadStatus
8+
, readUtxoSnapshot
89
, runApp
910
, runAppEff
1011
, runContractInApp
@@ -14,7 +15,7 @@ module HydraSdk.Example.Minimal.App
1415

1516
import Prelude
1617

17-
import Cardano.Types (TransactionInput, TransactionOutput, UtxoMap)
18+
import Cardano.Types (TransactionInput, TransactionOutput)
1819
import Contract.Config
1920
( ContractParams
2021
, PrivatePaymentKeySource(PrivatePaymentKeyFile)
@@ -37,7 +38,6 @@ import Control.Monad.Reader (ReaderT, ask, asks, runReaderT)
3738
import Ctl.Internal.ServerConfig (blockfrostPublicSanchonetServerConfig)
3839
import Data.Log.Formatter.Pretty (prettyFormatter)
3940
import Data.Log.Message (Message)
40-
import Data.Map (empty) as Map
4141
import Data.Maybe (Maybe(Just, Nothing), maybe)
4242
import Data.Tuple (Tuple(Tuple))
4343
import Effect (Effect)
@@ -100,6 +100,9 @@ readHeadStatus = (liftAff <<< AVar.read) =<< asks _.headStatus
100100
setHeadStatus :: HydraHeadStatus -> AppM Unit
101101
setHeadStatus status = (void <<< AVar.modify (const (pure status))) =<< asks _.headStatus
102102

103+
readUtxoSnapshot :: AppM HydraSnapshot
104+
readUtxoSnapshot = (liftAff <<< AVar.read) =<< asks _.utxoSnapshot
105+
103106
setUtxoSnapshot :: HydraSnapshot -> AppM Unit
104107
setUtxoSnapshot snapshot =
105108
(void <<< AVar.modify (const (pure snapshot)))
@@ -154,7 +157,7 @@ initApp config@{ hydraNodeStartupParams: { network, cardanoSigningKey }, commitO
154157
contractParams backendParams =
155158
{ backendParams
156159
, networkId: networkToNetworkId network
157-
, logLevel: config.logLevel
160+
, logLevel: config.ctlLogLevel
158161
, walletSpec: Just $ UseKeys (PrivatePaymentKeyFile cardanoSigningKey) Nothing Nothing
159162
, customLogger: Nothing
160163
, suppressLogs: false

0 commit comments

Comments
 (0)