Skip to content

Commit aa8f6bb

Browse files
authored
Merge pull request #7 from mlabs-haskell/dshuiski/v1
Hydra SDK V1
2 parents 173a8a6 + ad61c4e commit aa8f6bb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+10030
-23278
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/example/minimal/output/
44
/example/minimal/.psa-stash
55
/example/minimal/.spago/
6+
/example/minimal/.spago2nix/
67
/generated-docs/
78
/node_modules
89
/output/

.prettierrc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"arrowParens": "always",
3+
"bracketSpacing": true,
4+
"printWidth": 95,
5+
"quoteProps": "as-needed",
6+
"semi": true,
7+
"singleQuote": false,
8+
"tabWidth": 2,
9+
"trailingComma": "none",
10+
"useTabs": false
11+
}

.purs-repl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import Prelude
2+
import Aeson as A
3+
import Data.Codec.Argonaut as CA
24
import HydraSdk.Extra.AppManager
35
import HydraSdk.Lib
46
import HydraSdk.NodeApi

Makefile

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
.PHONY: build, format, repl, docs, build-example, run-example, docker-cleanup, gen-keys
1+
.PHONY: build, test, format, repl, docs, build-example, run-example, docker-cleanup, gen-keys
22

33
ps-sources := $(shell fd --no-ignore-parent -epurs)
4+
js-sources := $(shell fd --no-ignore-parent -ejs)
45
nix-sources := $(shell fd --no-ignore-parent -enix --exclude='spago*')
56
purs-args := "--stash --censor-lib --censor-codes=ImplicitImport,ImplicitQualifiedImport,ImplicitQualifiedImportReExport,UserDefinedWarning"
67
example-docker := example/minimal/docker/cluster/docker-compose.yaml
@@ -15,9 +16,17 @@ requires-nix-shell:
1516
build: requires-nix-shell
1617
spago build --purs-args ${purs-args}
1718

19+
test: requires-nix-shell
20+
spago run --main Test.Main
21+
1822
format: requires-nix-shell
19-
@purs-tidy format-in-place ${ps-sources}
20-
@nixpkgs-fmt ${nix-sources}
23+
@echo '1. Formatting PureScript sources:'
24+
purs-tidy format-in-place ${ps-sources}
25+
@echo -e '\n2. Formatting JavaScript sources:'
26+
prettier -w ${js-sources}
27+
@echo -e '\n3. Formatting Nix sources:'
28+
nixpkgs-fmt ${nix-sources}
29+
@echo -e '\n4. Generating table of contents for Markdown files:'
2130
doctoc README.md --github --notitle
2231

2332
repl: requires-nix-shell

example/minimal/app/Main.purs

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,36 @@ module HydraSdk.Example.Minimal.Main
44

55
import Prelude
66

7-
import Cardano.AsCbor (encodeCbor)
7+
import Aeson (stringifyAeson)
8+
import Cardano.AsCbor (decodeCbor, encodeCbor)
89
import Cardano.Types (Language(PlutusV2), Transaction)
10+
import Cardano.Types.AuxiliaryData (hashAuxiliaryData)
11+
import Cardano.Types.Transaction (_body, _witnessSet)
12+
import Cardano.Types.TransactionBody (_auxiliaryDataHash)
13+
import Cardano.Types.TransactionWitnessSet (_vkeys)
914
import Contract.CborBytes (cborBytesToHex)
1015
import Contract.Log (logError', logInfo', logTrace', logWarn')
1116
import Contract.Monad (Contract, ContractEnv, stopContractEnv)
1217
import Contract.ProtocolParameters (getProtocolParameters)
13-
import Contract.Transaction (submit)
18+
import Contract.Transaction (signTransaction, submit)
1419
import Control.Monad.Error.Class (throwError)
1520
import Control.Monad.Reader (ask)
1621
import Ctl.Internal.Transaction (setScriptDataHash)
17-
import Data.Argonaut (stringifyWithIndent)
1822
import Data.Array (length) as Array
1923
import Data.Codec.Argonaut (encode) as CA
2024
import Data.Either (Either(Left, Right))
25+
import Data.Lens ((.~))
2126
import Data.Log.Level (LogLevel(Info, Error))
2227
import Data.Map (empty, filterKeys, fromFoldable) as Map
23-
import Data.Maybe (Maybe(Just, Nothing))
28+
import Data.Maybe (Maybe(Just, Nothing), maybe)
2429
import Data.Newtype (unwrap)
2530
import Data.Posix.Signal (Signal(SIGINT, SIGTERM))
2631
import Data.Traversable (traverse_)
27-
import Data.UInt (fromInt) as UInt
2832
import Effect (Effect)
2933
import Effect.Aff (Aff, launchAff_, runAff_)
3034
import Effect.Aff.Class (liftAff)
3135
import Effect.Class (liftEffect)
32-
import Effect.Exception (error, message)
36+
import Effect.Exception (error, message, name, stack) as Error
3337
import Effect.Ref (Ref)
3438
import Effect.Ref (new, read, write) as Ref
3539
import HydraSdk.Example.Minimal.App
@@ -46,7 +50,7 @@ import HydraSdk.Example.Minimal.App
4650
import HydraSdk.Example.Minimal.App (setHeadStatus, setUtxoSnapshot) as App
4751
import HydraSdk.Example.Minimal.Config (configFromArgv)
4852
import HydraSdk.Example.Minimal.Contract.L2 (placeArbitraryDatumL2)
49-
import HydraSdk.Lib (log', reSignTransaction, setAuxDataHash)
53+
import HydraSdk.Lib (log')
5054
import HydraSdk.NodeApi
5155
( HydraNodeApiWebSocket
5256
, HydraTxRetryStrategy(RetryTxWithParams, DontRetryTx)
@@ -55,14 +59,7 @@ import HydraSdk.NodeApi
5559
)
5660
import HydraSdk.Process (spawnHydraNode)
5761
import HydraSdk.Types
58-
( HydraHeadStatus
59-
( HeadStatus_Idle
60-
, HeadStatus_Initializing
61-
, HeadStatus_Open
62-
, HeadStatus_Closed
63-
, HeadStatus_FanoutPossible
64-
, HeadStatus_Final
65-
)
62+
( HydraHeadStatus(HeadStatus_Idle, HeadStatus_Closed)
6663
, HydraNodeApi_InMessage
6764
( Greetings
6865
, HeadIsInitializing
@@ -76,14 +73,11 @@ import HydraSdk.Types
7673
, HydraSnapshot(HydraSnapshot)
7774
, hydraSnapshotCodec
7875
, mkSimpleCommitRequest
79-
, printHeadStatus
80-
, printHost
8176
, printHostPort
8277
, toUtxoMap
8378
)
8479
import Node.ChildProcess (ChildProcess, kill)
8580
import Node.Process (onSignal, onUncaughtException)
86-
import URI.Port (toInt) as Port
8781

8882
type AppHandle =
8983
{ cleanupHandler :: Effect Unit
@@ -99,7 +93,12 @@ main =
9993
appHandle <- startDelegateServer appState logger
10094
liftEffect do
10195
onUncaughtException \err -> do
102-
runAppEff appState logger $ logError' $ "UNCAUGHT EXCEPTION: " <> message err
96+
runAppEff appState logger $ logError' $
97+
"UNCAUGHT "
98+
<> Error.name err
99+
<> ": "
100+
<> Error.message err
101+
<> maybe mempty (append ", STACK: ") (Error.stack err)
103102
appHandle.cleanupHandler
104103
onSignal SIGINT appHandle.cleanupHandler
105104
onSignal SIGTERM appHandle.cleanupHandler
@@ -119,6 +118,7 @@ startDelegateServer state logger = do
119118
, handlers:
120119
{ connectHandler: const (pure unit)
121120
, messageHandler: \ws -> messageHandler ws
121+
, headStatusHandler: Just App.setHeadStatus
122122
, errorHandler: \_ws err ->
123123
logError' $ "hydra-node API WebSocket error: " <> show err
124124
}
@@ -160,34 +160,32 @@ messageHandler ws =
160160
Left _rawMessage -> pure unit
161161
Right message ->
162162
case message of
163-
Greetings { headStatus } -> do
164-
setHeadStatus headStatus
165-
when (headStatus == HeadStatus_Idle) $ liftEffect ws.initHead
163+
Greetings { headStatus } ->
164+
when (headStatus == HeadStatus_Idle) $
165+
liftEffect ws.initHead
166166
HeadIsInitializing _ -> do
167-
setHeadStatus HeadStatus_Initializing
168167
{ commitUtxo, config: { hydraNodeStartupParams: { hydraNodeApiAddress } } } <- ask
169168
let
170169
payload = mkSimpleCommitRequest $ Map.fromFoldable [ commitUtxo ]
171-
serverConfig =
172-
{ port: UInt.fromInt $ Port.toInt hydraNodeApiAddress.port
173-
, host: printHost hydraNodeApiAddress
174-
, secure: false
175-
, path: Nothing
176-
}
177-
liftAff (commitRequest serverConfig payload) >>= case _ of
170+
hydraNodeHttpUrl = "http://" <> printHostPort hydraNodeApiAddress
171+
liftAff (commitRequest hydraNodeHttpUrl payload) >>= case _ of
178172
Left httpErr ->
179-
throwError $ error $ "Commit request failed with error: "
173+
throwError $ Error.error $ "Commit request failed with error: "
180174
<> show httpErr
181-
Right { cborHex: commitTx } -> do
182-
txHash <- runContractInApp $ submit =<< fixCommitTx commitTx
183-
logInfo' $ "Submitted Commit transaction: " <> cborBytesToHex
184-
(encodeCbor txHash)
175+
Right { cborHex } -> do
176+
case decodeCbor cborHex of
177+
Just commitTx -> do
178+
txHash <- runContractInApp $ submit =<< fixCommitTx commitTx
179+
logInfo' $ "Submitted Commit transaction: " <> cborBytesToHex
180+
(encodeCbor txHash)
181+
Nothing ->
182+
throwError $ Error.error "Could not decode CommitTx CBOR"
185183
HeadIsOpen { headId, utxo } -> do
186-
setHeadStatus HeadStatus_Open
187-
logInfo' $ "Head ID: " <> cborBytesToHex (encodeCbor headId)
184+
logInfo' $ "Head ID: " <> headId
188185
setUtxoSnapshot $ HydraSnapshot
189186
{ snapshotNumber: zero
190187
, utxo
188+
, confirmedTransactions: mempty
191189
}
192190
tx <- runContractInApp $ placeArbitraryDatumL2 $ toUtxoMap utxo
193191
liftEffect $ ws.submitTxL2 tx
@@ -197,24 +195,31 @@ messageHandler ws =
197195
when ((unwrap snapshot).snapshotNumber > Array.length peers) do
198196
logInfo' "All Head participants must have advanced the L2 state. Closing Head..."
199197
liftEffect ws.closeHead
200-
HeadIsClosed { snapshotNumber } -> do
201-
-- TODO: set head status implicitly
202-
setHeadStatus HeadStatus_Closed
198+
HeadIsClosed { snapshotNumber } ->
203199
contestClosureIfNeeded ws snapshotNumber
204200
HeadIsContested { snapshotNumber } ->
205201
contestClosureIfNeeded ws snapshotNumber
206-
ReadyToFanout _ -> do
207-
setHeadStatus HeadStatus_FanoutPossible
202+
ReadyToFanout _ ->
208203
liftEffect ws.fanout
209-
HeadIsFinalized _ -> do
210-
setHeadStatus HeadStatus_Final
204+
HeadIsFinalized _ ->
211205
-- TODO: output fanout tx hash
212-
throwError $ error "SUCCESS: Head finalized, Funds transfered to L1 - Exiting..."
206+
throwError $ Error.error
207+
"SUCCESS: Head finalized, Funds transfered to L1 - Exiting..."
213208
_ -> pure unit
214209

215210
fixCommitTx :: Transaction -> Contract Transaction
216211
fixCommitTx = reSignTransaction <=< fixScriptIntegrityHash <<< setAuxDataHash
217212
where
213+
-- | Computes and sets the transaction auxiliary data hash.
214+
setAuxDataHash :: Transaction -> Transaction
215+
setAuxDataHash tx =
216+
tx # _body <<< _auxiliaryDataHash .~
217+
(hashAuxiliaryData <$> (unwrap tx).auxiliaryData)
218+
219+
-- | Removes existing vkey witnesses and signs the transaction.
220+
reSignTransaction :: Transaction -> Contract Transaction
221+
reSignTransaction tx = signTransaction (tx # _witnessSet <<< _vkeys .~ mempty)
222+
218223
fixScriptIntegrityHash :: Transaction -> Contract Transaction
219224
fixScriptIntegrityHash tx = do
220225
pparams <- unwrap <$> getProtocolParameters
@@ -235,15 +240,10 @@ contestClosureIfNeeded ws closeSnapshot = do
235240
<> ". Contesting Head closure..."
236241
liftEffect ws.challengeSnapshot
237242

238-
setHeadStatus :: HydraHeadStatus -> AppM Unit
239-
setHeadStatus status = do
240-
App.setHeadStatus status
241-
logInfo' $ "New Head status: " <> printHeadStatus status
242-
243243
setUtxoSnapshot :: HydraSnapshot -> AppM Unit
244244
setUtxoSnapshot snapshot = do
245245
App.setUtxoSnapshot snapshot
246-
let snapshotFormatted = stringifyWithIndent 2 $ CA.encode hydraSnapshotCodec snapshot
246+
let snapshotFormatted = stringifyAeson $ CA.encode hydraSnapshotCodec snapshot
247247
logInfo' $ "New confirmed snapshot: " <> snapshotFormatted
248248

249249
cleanupHandler
@@ -264,7 +264,7 @@ cleanupHandler logger { hydraNodeProcess, hydraNodeApiWsRef, contractEnv } = do
264264
( case _ of
265265
Left err ->
266266
logger Error $ "stopContractEnv failed with error: "
267-
<> message err
267+
<> Error.message err
268268
Right _ ->
269269
logger Info "Successfully completed all cleanup actions -> exiting."
270270
)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"hydraSigningKey": "keys/hydra-a.sk",
88
"cardanoSigningKey": "keys/cardano-a.sk",
99
"network": {
10-
"tag": "testnet",
10+
"tag": "Testnet",
1111
"magic": 1
1212
},
1313
"nodeSocket": "node-ipc/node.socket",

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"hydraSigningKey": "keys/hydra-b.sk",
88
"cardanoSigningKey": "keys/cardano-b.sk",
99
"network": {
10-
"tag": "testnet",
10+
"tag": "Testnet",
1111
"magic": 1
1212
},
1313
"nodeSocket": "node-ipc/node.socket",
@@ -23,7 +23,7 @@
2323
]
2424
},
2525
"blockfrostApiKey": null,
26-
"logLevel": "info",
26+
"logLevel": "trace",
2727
"ctlLogLevel": "warn",
2828
"commitOutRef": null
2929
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
services:
22
cardano-node:
3-
image: ghcr.io/intersectmbo/cardano-node:10.1.2
3+
image: ghcr.io/intersectmbo/cardano-node:10.1.3
44
environment:
55
- NETWORK=preprod
66
volumes:

0 commit comments

Comments
 (0)