Skip to content

Commit 4bbbe28

Browse files
authored
Merge pull request #1380 from input-output-hk/commit-blueprint-tx
Commit blueprint tx
2 parents 120ff1b + 62371ed commit 4bbbe28

34 files changed

+1934
-1307
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@ changes.
1515

1616
- _DEPRECATED_ the `GetUTxO` client input and `GetUTxOResponse` server output. Use `GET /snapshot/utxo` instead.
1717

18+
## [0.17.0] - UNRELEASED
19+
20+
- **BREAKING** `hydra-node` `/commit` enpoint now also accepts a _blueprint/draft_
21+
transaction together with the `UTxO` which is spent in this transaction. `hydra-node` can
22+
still be used like before if the provided `UTxO` is at public key address. In order to spend
23+
from a script `UTxO`, and also unlock more involved use-cases, users need to provide additional
24+
unsigned transaction that correctly specifies required data (like redeemers, validity ranges etc.)
25+
1826
## [0.16.0] - 2024-04-03
1927

2028
- Tested with `cardano-node 8.9.0`, `cardano-cli 8.20.3.0` and `mithril 2412.0`.

docs/docs/blueprint_transaction.md

+184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
---
2+
sidebar_position: 99
3+
---
4+
5+
# Commit using blueprint transaction
6+
7+
This is a small walk-through on how to use `cardano-cli` to assemble everything needed to commit funds to a `Head` using blueprint transaction.
8+
9+
Example assumes you have the hydra-node repo at your disposal together with `hydra-node`, `hydra-tui`, `cardano-cli` and `curl` binaries.
10+
11+
We can use `cardano-cli` to create a _blueprint_ transaction from some `UTxO` we own.
12+
13+
First we need a running cardano-node so let's spin one on the preprod network:
14+
15+
16+
```shell
17+
./testnets/cardano-node.sh ~/code/hydra/testnets/preprod
18+
```
19+
20+
Now we need to find the `UTxO` you want to commit to the `Head`
21+
22+
In this example we will use Alice and her external wallet key so first let's find out the address:
23+
24+
```shell
25+
cardano-cli address build \
26+
--payment-verification-key-file hydra-cluster/config/credentials/alice-funds.vk \
27+
--testnet-magic 1
28+
29+
addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z
30+
```
31+
32+
and query to see what `UTxO` Alice has:
33+
34+
```shell
35+
cardano-cli query utxo \
36+
--socket-path testnets/preprod/node.socket \
37+
--address addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z \
38+
--testnet-magic 1 \
39+
--output-json
40+
41+
{
42+
"14ab373afb1112d925b0f6a84518ac26d4a8cfcc99231e1f47e6996182e843a9#0": {
43+
"address": "addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z",
44+
"datum": null,
45+
"datumhash": null,
46+
"inlineDatum": null,
47+
"referenceScript": null,
48+
"value": {
49+
"lovelace": 8000000
50+
}
51+
},
52+
"14ab373afb1112d925b0f6a84518ac26d4a8cfcc99231e1f47e6996182e843a9#1": {
53+
"address": "addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z",
54+
"datum": null,
55+
"datumhash": null,
56+
"inlineDatum": null,
57+
"referenceScript": null,
58+
"value": {
59+
"lovelace": 1828427
60+
}
61+
},
62+
}
63+
```
64+
65+
Let's pick the first `UTxO` which has total of 8 ADA available. Let's use 5 ADA to commit and rely on `hydra-node` to balance the commit transaction.
66+
67+
```shell
68+
cardano-cli transaction build-raw \
69+
--babbage-era \
70+
--tx-in 14ab373afb1112d925b0f6a84518ac26d4a8cfcc99231e1f47e6996182e843a9#0 \
71+
--tx-out addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z+5000000 \
72+
--fee 0 \
73+
--out-file tx.json
74+
```
75+
76+
So now we have the _blueprint_ transaction present in the `tx.json` file.
77+
78+
In order to have `hydra-node` give us a draft commit transaction we need to:
79+
80+
- Obtain protocol-parameters needed to run the `hydra-node`
81+
- Have the `hydra-node` up and running
82+
- Have the `Head` in the initializing state
83+
- Submit the http request to the `hydra-node` api server using the _blueprint_ transaction we just created and the `UTxO` used for it's input.
84+
85+
86+
Query the preview protocol-parameters:
87+
88+
```shell
89+
cardano-cli query protocol-parameters \
90+
--testnet-magic 1 \
91+
--socket-path testnets/preprod/node.socket \
92+
--out-file pp-preprod.json
93+
94+
```
95+
96+
Start the `hydra-node` in as a _single_ party Head instance.
97+
98+
Note: The value `6264cee4d5eab3fb58ab67f3899ecbcc0d7e72732a2d9c1c5d638115db6ca711` comes from `hydra-node` release [0.16.0](https://github.com/input-output-hk/hydra/releases/tag/0.16.0)
99+
100+
```shell
101+
hydra-node \
102+
--node-id 1 --port 5001 --api-port 4001 \
103+
--hydra-signing-key demo/alice.sk \
104+
--hydra-scripts-tx-id 6264cee4d5eab3fb58ab67f3899ecbcc0d7e72732a2d9c1c5d638115db6ca711 \
105+
--cardano-signing-key hydra-cluster/config/credentials/alice.sk \
106+
--ledger-protocol-parameters pp-preprod.json \
107+
--testnet-magic 1 \
108+
--node-socket testnets/preprod/node.socket \
109+
--persistence-dir .
110+
```
111+
112+
Now we can start `hydra-tui` and initialize the `Head`:
113+
114+
```shell
115+
hydra-tui \
116+
--connect 0.0.0.0:4001 \
117+
--cardano-signing-key hydra-cluster/config/credentials/alice-funds.sk \
118+
--testnet-magic 1 \
119+
--node-socket testnets/preprod/node.socket
120+
```
121+
122+
Now press `i` to initialize the `Head`.
123+
124+
Once we see that the head is in the `Initializing` state we are ready to send the HTTP request to the `/commit` API path.
125+
126+
To assemble the request body we will use the `cborHex` field from the tx-body file `tx.json`.
127+
128+
To get the json representation of the `UTxO` we used as the input we can just copy/paste the output we got from cardano-cli when we did a `UTxO` query:
129+
130+
This is the valid json request:
131+
132+
```shell
133+
{
134+
"blueprintTx": {
135+
"cborHex": "84a3008182582014ab373afb1112d925b0f6a84518ac26d4a8cfcc99231e1f47e6996182e843a900018182581d6069830961c6af9095b0f2648dff31fa9545d8f0b6623db865eb78fde81a007a12000200a0f5f6",
136+
"description": "",
137+
"type": "Tx BabbageEra"
138+
},
139+
"utxo": {
140+
"14ab373afb1112d925b0f6a84518ac26d4a8cfcc99231e1f47e6996182e843a9#0": {
141+
"address": "addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z",
142+
"datum": null,
143+
"datumhash": null,
144+
"inlineDatum": null,
145+
"referenceScript": null,
146+
"value": {
147+
"lovelace": 8000000
148+
}
149+
}
150+
}
151+
}
152+
```
153+
154+
Let's save this json to commit-request.json file.
155+
156+
Now, it is time to ask the running `hydra-node` to draft a commit transaction for us:
157+
158+
159+
```
160+
curl -X POST 127.0.0.1:4001/commit \
161+
--data @commit-request.json
162+
163+
```
164+
165+
This yields a large cbor blob which we can save to `commit-tx.json` file.
166+
167+
Now we need to sign and submit the draft commit transaction.
168+
169+
```shell
170+
171+
cardano-cli transaction sign \
172+
--tx-file commit-tx.json \
173+
--signing-key-file hydra-cluster/config/credentials/alice-funds.sk \
174+
--out-file signed-tx.json
175+
176+
177+
cardano-cli transaction submit \
178+
--tx-file signed-tx.json \
179+
--socket-path testnets/preprod/node.socket \
180+
--testnet-magic 1
181+
```
182+
183+
If we start the `hydra-tui` and wait a bit until the transaction we just sent is re-observed by the `hydra-node` we should see that the `Head` is now open.
184+

docs/docs/getting-started/quickstart.md

+15-1
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,21 @@ cardano-cli address build --verification-key-file cardano.vk --mainnet
250250

251251
## External commits
252252

253-
While the `hydra-node` holds funds to fuel protocol transactions, any wallet can be used to commit funds into an `initializing` Hydra head. The `hydra-node` provides an HTTP endpoint at `/commit`, which allows to specify multiple UTxO (belonging to public key or script address) and returns a draft transaction. This transaction is already balanced and all fees are paid by the funds held by the `hydra-node`, but is missing witnesses for the public key outputs to commit. Hence, an integrated wallet would need to sign this transaction and submit it to the Cardano network. See the [api documentation](pathname:///api-reference/#operation-publish-/commit) for details.
253+
While the `hydra-node` holds funds to fuel protocol transactions, any wallet can be used to commit funds into an `initializing` Hydra head. The `hydra-node` provides an HTTP endpoint at `/commit`, which allows to specify either:
254+
- a `UTxO` set of outputs to commit (belonging to public keys) or
255+
- a _blueprint_ transaction together with the `UTxO` which resolves it.
256+
257+
and eventually returns a commit transaction.
258+
259+
This transaction is already balanced and all fees are paid by the funds held by the `hydra-node`. Hence, an integrated wallet would need to sign this transaction and submit it to the Cardano network. See the [api documentation](pathname:///api-reference/#operation-publish-/commit) for details.
260+
261+
If the user wants to use some `UTxO` they own and commit it to a `Head` then they need to send the appropriate JSON representation of said `UTxO` to the `/commit` API endpoint.
262+
263+
Using a _blueprint_ transaction with `/commit` allows for more flexibility since `hydra-node` only adds needed commit transaction data without removing any additional information specified in the _blueprint_ transaction. For example, any present reference inputs, redeemers or validity ranges will be kept.
264+
265+
> Note: It is important to note that any **outputs** of a blueprint transaction will not be considered, only inputs are used to commit funds to the `Head`. `hydra-node` will also **ignore** any minting or burning specified in the blueprint transaction.
266+
267+
You can take a look at the small example on how to commit to a `Head` using blueprint transaction [here](/docs/blueprint_transaction.md)
254268

255269
## Generating transactions for the WebSocket API
256270

hydra-cardano-api/src/Hydra/Cardano/Api/ScriptData.hs

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ fromLedgerData =
7777
fromAlonzoData
7878

7979
-- | Convert a cardano-api script data into a cardano-ledger script 'Data'.
80+
-- XXX: This is a partial function. Ideally it would fall back to the
81+
-- 'Plutus.Data' portion in 'HashableScriptData'.
8082
toLedgerData :: Ledger.Era era => HashableScriptData -> Ledger.Data era
8183
toLedgerData =
8284
toAlonzoData

hydra-cardano-api/src/Hydra/Cardano/Api/Tx.hs

+13-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ import Data.Bifunctor (bimap)
6767
import Data.Functor ((<&>))
6868
import Data.Map qualified as Map
6969
import Data.Maybe (mapMaybe)
70-
import Hydra.Cardano.Api.TxIn (mkTxIn)
70+
import Data.Set qualified as Set
71+
import Hydra.Cardano.Api.TxIn (mkTxIn, toLedgerTxIn)
7172

7273
-- * Extras
7374

@@ -174,6 +175,17 @@ signTx signingKey (Tx body wits) =
174175
where
175176
witness = makeShelleyKeyWitness shelleyBasedEra body (WitnessPaymentKey signingKey)
176177

178+
-- | Create a transaction spending all given `UTxO`.
179+
txSpendingUTxO :: UTxO -> Tx Era
180+
txSpendingUTxO utxo =
181+
fromLedgerTx $
182+
mkBasicTx
183+
( mkBasicTxBody
184+
& inputsTxBodyL .~ (toLedgerTxIn `Set.map` inputs)
185+
)
186+
where
187+
inputs = UTxO.inputSet utxo
188+
177189
-- | Get the UTxO that are produced by some transaction.
178190
-- XXX: Defined here to avoid cyclic module dependency
179191
utxoProducedByTx :: Tx Era -> UTxO

0 commit comments

Comments
 (0)