Skip to content

Commit 875ed7a

Browse files
authored
Merge pull request #3 from mlabs-haskell/dshuiski/minimal-example
Add minimal example
2 parents 52a000a + 7d08a64 commit 875ed7a

Some content is hidden

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

57 files changed

+13577
-18860
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1+
/example/minimal/docker/cluster/keys/*.sk
2+
/example/minimal/docker/cluster/keys/*.vk
3+
/example/minimal/output/
4+
/example/minimal/.psa-stash
5+
/example/minimal/.spago/
6+
/example/minimal/.spago2nix/
7+
/generated-docs/
18
/node_modules
29
/output/
310
/result
411
/.psa-stash
512
/.psci_modules/
613
/.spago/
714
/.spago2nix/
15+
.psc-ide-port

.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: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
1-
.PHONY: build, format, repl, docs
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"
6-
7-
system := $(shell uname -s)
8-
ifeq (${system},Linux)
9-
open-in-browser := xdg-open
10-
else
11-
open-in-browser := open
12-
endif
7+
example-docker := example/minimal/docker/cluster/docker-compose.yaml
8+
example-keys := example/minimal/docker/cluster/keys/
139

1410
requires-nix-shell:
1511
@[ "$(IN_NIX_SHELL)" ] || \
@@ -20,14 +16,53 @@ requires-nix-shell:
2016
build: requires-nix-shell
2117
spago build --purs-args ${purs-args}
2218

19+
test: requires-nix-shell
20+
spago run --main Test.Main
21+
2322
format: requires-nix-shell
24-
@purs-tidy format-in-place ${ps-sources}
25-
@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:'
2630
doctoc README.md --github --notitle
2731

2832
repl: requires-nix-shell
2933
spago repl
3034

31-
docs:
32-
nix build .#docs
33-
${open-in-browser} result/generated-docs/html/index.html
35+
docs: requires-nix-shell
36+
mv package.json package.json.old
37+
jq 'del(.type)' package.json.old > package.json
38+
spago docs --open
39+
mv -f package.json.old package.json
40+
41+
build-example: requires-nix-shell
42+
cd example/minimal && \
43+
spago build --purs-args ${purs-args}
44+
45+
run-example: docker-cleanup
46+
docker compose -f ${example-docker} up --build --no-attach cardano-node
47+
48+
docker-cleanup:
49+
docker compose -f ${example-docker} rm --force --stop
50+
docker volume rm -f cluster_hydra-persist-a cluster_hydra-persist-b
51+
52+
gen-keys: requires-nix-shell
53+
@hydra-node gen-hydra-key --output-file ${example-keys}/hydra-a
54+
@hydra-node gen-hydra-key --output-file ${example-keys}/hydra-b
55+
@cardano-cli address key-gen \
56+
--signing-key-file ${example-keys}/cardano-a.sk \
57+
--verification-key-file ${example-keys}/cardano-a.vk
58+
@cardano-cli address build \
59+
--payment-verification-key-file ${example-keys}/cardano-a.vk \
60+
--testnet-magic 1
61+
@echo
62+
@cardano-cli address key-gen \
63+
--signing-key-file ${example-keys}/cardano-b.sk \
64+
--verification-key-file ${example-keys}/cardano-b.vk
65+
@cardano-cli address build \
66+
--payment-verification-key-file ${example-keys}/cardano-b.vk \
67+
--testnet-magic 1
68+
@echo

README.md

Lines changed: 136 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,102 @@
22

33
[Cardano Hydra](https://hydra.family/head-protocol/)
44
SDK (Software Development Kit) for PureScript. This library offers
5-
various interfaces to facilitate rapid development of Hydra-based
6-
applications.
5+
various interfaces to facilitate the rapid development
6+
of Hydra-based applications.
77

88
**Table of Contents**
99

1010
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
1111
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
1212

13-
- [Applications](#applications)
14-
- [Functionality](#functionality)
13+
- [Compatibility](#compatibility)
14+
- [Preliminaries](#preliminaries)
1515
- [Development Workflows](#development-workflows)
16+
- [Getting Started with Example](#getting-started-with-example)
17+
- [SDK Core Functionality](#sdk-core-functionality)
18+
- [SDK Additionals: AppManager](#sdk-additionals-appmanager)
19+
- [Applications](#applications)
1620

1721
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
1822

19-
### Applications
23+
## Compatibility
2024

21-
Please refer to [hydra-auction-offchain](https://github.com/mlabs-haskell/hydra-auction-offchain)
22-
for a full-fledged example that utilizes this SDK.
25+
| hydra-sdk | hydra-node | cardano-node |
26+
| ----------- | ------------ | ------------ |
27+
| **`0.1.0`** | **`0.19.0`** | **`10.1.2`** |
28+
29+
30+
## Preliminaries
31+
32+
Since using this SDK implies a certain degree of understanding of the Hydra
33+
protocol, it is advisable to get familiar with the ["Hydra: Fast Isomorphic State Channels" paper](https://iohk.io/en/research/library/papers/hydra-fast-isomorphic-state-channels/)
34+
and the [Hydra Head protocol documentation](https://hydra.family/head-protocol/docs/)
35+
before proceeding with the **Getting Started** guide below.
36+
37+
## Development Workflows
38+
39+
Before executing most of the commands listed below, first enter the Nix
40+
development shell by running `nix develop`.
41+
42+
* **Build docs and open them in the browser**: `make docs`
43+
* **Build the project**: `make build`
44+
* **Format code**: `make format`
45+
46+
## Getting Started with Example
47+
48+
The simplest way to get a sense of how this SDK can help build Hydra-based
49+
applications is to run our minimal example and then adapt or extend it to suit
50+
your specific requirements.
51+
52+
Go to `example/minimal` and follow the step-by-step guide below to spin up
53+
a cluster of two nodes, with each node running the minimal example logic.
54+
55+
1. Enter the Nix development environment by running `nix develop` from the root
56+
directory of this repository. This will put you in the shell with all the
57+
necessary executables required to continue with the setup procedure.
2358

24-
### Functionality
59+
2. In [example/minimal/docker/cluster/](example/minimal/docker/cluster/) you
60+
can find configuration files for both nodes. The only field that needs to be
61+
updated here is the `blockfrostApiKey`, which should be set to a valid
62+
Blockfrost API key **for preprod**.
63+
Visit the [Blockfrost website](https://blockfrost.io/) to generate a fresh API key.
2564

26-
The `HydraSdk.Process` module provides an interface for spinning up a hydra-node
65+
3. Execute `make gen-keys` to generate the necessary Cardano and Hydra keys
66+
required by the underlying Hydra nodes. Cardano keys are used to authenticate
67+
on-chain transactions, while the Hydra keys are used for multi-signing snapshots
68+
within a Hydra Head. This command will output two Cardano preprod addresses
69+
that must be pre-funded with sufficient tADA to run properly functioning Hydra
70+
nodes.
71+
Use the [Testnets faucet](https://docs.cardano.org/cardano-testnets/tools/faucet/)
72+
to request tADA.
73+
74+
4. Finally, execute `make run-example` to launch a Hydra Head
75+
with two participants both running the minimal example logic.
76+
77+
NOTE: Hydra nodes require a fully synchronized Cardano node to operate
78+
correctly. No additional setup actions need to be performed to
79+
configure the Cardano node as it is already included in the Docker
80+
Compose configuration.
81+
However, node synchronization may take several hours on the first run.
82+
Keep in mind that Hydra nodes are configured to run only once
83+
the Cardano node is fully synchronized,
84+
and the `cardano-node` output is suppressed to not
85+
interfere with useful Hydra Head logs.
86+
As a result, there will be no output during synchronization.
87+
Instead, use `docker logs` or run `cardano-cli query tip`
88+
from within the `cardano-node` Docker container
89+
to track the synchronization progress.
90+
91+
## SDK Core Functionality
92+
93+
The SDK exposes the following top-level modules which constitus it API which
94+
is considered to be relatvely stable. You also can use `Internal` modules
95+
at yor own risk.
96+
97+
* `HydraSdk.Process` module provides an interface for spinning up a hydra-node
2798
as a Node.js subprocess.
2899

29-
The `HydraSdk.NodeApi` module exports functions for connecting to the Hydra Node
100+
* `HydraSdk.NodeApi` module exports functions for connecting to the Hydra Node
30101
WebSocket API and sending HTTP requests. The primary function provided by this
31102
module is `mkHydraNodeApiWebSocket`, which establishes a WebSocket connection to
32103
the hydra-node, attaches specified handlers for incoming messages, and returns a
@@ -35,21 +106,65 @@ Hydra Node API. It also allows to specify retry strategies for Hydra
35106
transactions that may be silently dropped by cardano-node, particularly for
36107
Close and Contest transactions.
37108

38-
The `HydraSdk.Types` module re-exports various Hydra domain-specific types
109+
* `HydraSdk.Types` module re-exports various Hydra domain-specific types
39110
(such as `HydraHeadStatus` and `HydraNodeApi_InMessage`), along with other
40111
utility types (e.g., `HostPort` and `Network`) used by the components of this
41112
library.
42113

43-
`HydraSdk.Extra.AppManager` provides an opinionated interface for managing
44-
multiple Hydra application instances, with each instance running a separate
45-
hydra-node process, as implemented in [hydra-auction-offchain](https://github.com/mlabs-haskell/hydra-auction-offchain).
46-
For more information, refer to the [AppManager README](src/Extra/README.md).
114+
* Lastly, `HydraSdk.Lib` module contains useful helpers like codecs for many types,
115+
logging action and some others.
47116

48-
### Development Workflows
117+
## SDK Additionals: AppManager
49118

50-
Before executing most of the commands listed below, first enter the Nix
51-
development shell by running `nix develop`.
119+
Under `Extra` folder, modules with additional functionality are located,
120+
currently being the only one for managing multiple app instances.
52121

53-
**Build the project** (requires Nix shell): `make build`
54-
**Format code** (requires Nix shell): `make format`
55-
**Build docs and open them in the browser**: `make docs`
122+
Originally the SDK was designed for Hydra applications, where Hydra Heads were
123+
operated by designated delegates. In that model a delegate can be anyone who wants
124+
to participate as a provider of computational resources to host Hydra
125+
nodes. Delegates must form a group upfront to maintain Hydra
126+
consensus. Upon forming a group, all members need to specify
127+
information about their peers - such as Hydra node addresses, public
128+
keys, etc. That way there exists a strict correspondence between
129+
delegate configurations to start a functioning Hydra Head.
130+
131+
Each application instance should monitor its underlying Hydra node and
132+
have access to information about other Hydra Head participants.
133+
AppManager is an opinionated interface for managing multiple app
134+
instances within a delegate group. This interface is utilized by
135+
applications like `hydra-auction-offchain`, enabling delegates to host
136+
multiple Layer-2 auctions simultaneously.
137+
138+
At the core of AppManager is the concept of slots. When delegates
139+
decide to form a group, they agree on the configurations for their
140+
future Hydra nodes. Since each delegate have to specify information
141+
about their peers (hydra-node address, public keys, etc.), there must
142+
be strict correspondence between delegate configurations to start
143+
a working Hydra Head. This is where slots come into play. Each slot
144+
represents a set of delegate configurations sufficient to spin up a
145+
properly configured Hydra Head. In hydra-auction-offchain, slot
146+
numbers are implicitly derived from the configurations provided to
147+
the delegate-server, with the first configuration corresponding to
148+
slot 0, the second to slot 1, and so forth. Users are expected to
149+
reserve slots before making an initial Layer-1 commitment, such as
150+
announcing an auction. Upon reservation, they receive secrets from
151+
each delegate, which can later be provided to host a Layer-2
152+
application in the reserved slot.
153+
154+
One clear drawback of this approach is the potential for malicious
155+
actors to reserve all available slots within a delegate group,
156+
effectively paralyzing its operations. In real-world applications, a
157+
flooding detection mechanism should be implemented to prevent this
158+
scenario, although there seems to be no obvious incentive for anyone
159+
to carry out such an attack.
160+
161+
Coming with the limitations mentioned, this approach simplifies things
162+
since it neither requires communication and synchronization between
163+
delegates during runtime nor does it rely on a central server to
164+
orchestrate the initialization of Hydra Heads, making it a great fit
165+
for hydra-auction-offchain and hopefully other Hydra applications.
166+
167+
## Applications
168+
169+
Please refer to [hydra-auction-offchain](https://github.com/mlabs-haskell/hydra-auction-offchain)
170+
for a full-fledged example that utilizes this SDK.

0 commit comments

Comments
 (0)