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

Support the withdraw zero trick #1909

Merged
merged 10 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ changes.
- **BREAKING** Enable multi-party, networked "offline" heads by providing an `--offline-head-seed` option to `hydra-node`.
- Drop `hydra-node offline` as a sub-command. Use `--offline-head-seed` and `--initial-utxo` options to switch to offline mode.
- Add support for "withdraw zero trick" transactions:
- Any transaction with a `Rewarding` redeemer for a `Withdrawal` of `0 lovelace`, will be validated as if there would be a corresponding stake `RewardAccount` already registered.
- No need to register the script's stake address before.
- Stream historical data from disk in the hydra-node API server.
- Record used and free memory when running `bench-e2e` benchmark.
Expand Down
10 changes: 5 additions & 5 deletions docs/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,25 +200,25 @@ As an offline head will not connect to any chain, we need to provide an `--offli

To initialize UTxO state available on the L2 ledger, offline mode takes an obligatory `--initial-utxo` parameter, which points to a JSON-encoded UTxO file. See the [API reference](https://hydra.family/head-protocol/api-reference/#schema-UTxO) for the schema.

Using this example UTxO:
For example, the following UTxO contains 100 ADA owned by test key [alice-funds.sk](https://github.com/cardano-scaling/hydra/tree/master/hydra-cluster/config/credentials/alice-funds.sk):
```json utxo.json
{
"0000000000000000000000000000000000000000000000000000000000000000#0": {
"address": "addr_test1vqg9ywrpx6e50uam03nlu0ewunh3yrscxmjayurmkp52lfskgkq5k",
"address": "addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z",
"value": {
"lovelace": 100000000
}
}
}
```

A (single participant) offline Hydra head can be started with:
A single participant offline Hydra head can be started with our demo keys and protocol parameters:
```shell
hydra-node \
--offline-head-seed 0001 \
--initial-utxo utxo.json \
--hydra-signing-key hydra.sk \
--ledger-protocol-parameters protocol-parameters.json
--hydra-signing-key demo/alice.sk \
--ledger-protocol-parameters hydra-cluster/config/protocol-parameters.json
```

As the node is not connected to a real network, genesis parameters that normally influence things like time-based transaction validation cannot be fetched and are set to defaults. To configure block times, set `--ledger-genesis` to a Shelley genesis file similar to the [shelley-genesis.json](https://book.world.dev.cardano.org/environments/mainnet/shelley-genesis.json).
Expand Down
59 changes: 0 additions & 59 deletions docs/docs/how-to/etcd.md

This file was deleted.

2 changes: 1 addition & 1 deletion docs/docs/how-to/event-sinks-and-sources.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 5
sidebar_position: 99
---

# Extend the node with event source and sinks
Expand Down
4 changes: 4 additions & 0 deletions docs/docs/how-to/incremental-commit.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
sidebar_position: 4
---

# Commit funds to an open Head

Assuming we already have an open Head and some funds on the L1 we would like to commit.
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/how-to/incremental-decommit.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 3
sidebar_position: 5
---

# Decommit funds
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/how-to/operating-hydra.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 4
sidebar_position: 6
---

# Operate a Hydra node
Expand Down
108 changes: 108 additions & 0 deletions docs/docs/how-to/withdraw-zero.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
sidebar_position: 3
---

# Use withdraw zero trick

In this how-to we want to show how you can use the "wihtdraw zero trick" in Hydra. Until [CIP-112](https://cips.cardano.org/cip/CIP-0112) is implemented, there is only one way to run a script once per transaction - the so-called withdraw zero trick. Refer to the CIP or [this design pattern document](https://github.com/Anastasia-Labs/design-patterns/blob/main/stake-validator/STAKE-VALIDATOR.md) for more details about the general approach.

The Hydra L2 ledger is mostly _isomorphic_ to the L1 Cardano ledger. This means that it honors all the same ledger rules and transactions use the exact same format. However, some things related to the Cardano Proof-of-Stake consensus are represented different because they would not make much sense on an L2. For exapmle, transactions that [register stake certificates](https://docs.cardano.org/developer-resources/transaction-tutorials/stake-transaction) or [withdraw rewards](https://docs.cardano.org/developer-resources/transaction-tutorials/withdraw-transaction) don't work as-is on Hydra. However, for the purpose of "transaction-level validation", the withdraw zero trick can still be used as the Hydra L2 ledger **mocks script reward accounts** on the fly.

## Rewarding script

We are going to use the [dummyRewardingScript](https://github.com/cardano-scaling/hydra/blob/master/hydra-plutus/src/Hydra/Contract/Dummy.hs#L42-L53) as an example, which only validates the fact that we are in a `RewardingScript` context. Using GHCI we can determine the stake address and write the `rewarding.plutus` text envelope file for `cardano-cli`:

```haskell
cabal repl hydra-plutus
> import Prelude
> import Hydra.Contract.Dummy
> import Hydra.Cardano.Api
> script = PlutusScript dummyRewardingScript
> serialiseAddress $ makeStakeAddress (Testnet $ NetworkMagic 42) (StakeCredentialByScript $ hashScript script)
"stake_test17rekjamvnjyn3c3tcjpxe7ea20g7aek9vdqkaa3jefknz3gc066pt"
> writeFileTextEnvelope (File "../rewarding.plutus") Nothing script
Right ()
```

## Withdraw zero transaction

We can construct a transaction that withdraws zero lovelace from the rewarding script's "account". Usually, other purposes like spending a UTxO would require the reward script to run, but here we just assume there exists such a UTxO in the L2 state. You can initialize an [offline head](../configuration#offline-mode) for an easy demo set-up:

<details>
<summary>Setup with offline head</summary>
```
cat > utxo.json <<EOF
{
"0000000000000000000000000000000000000000000000000000000000000000#0": {
"address": "addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z",
"value": {
"lovelace": 100000000
}
}
}
EOF
```

```shell
cabal run hydra-node:exe:hydra-node -- \
--offline-head-seed 0001 \
--initial-utxo utxo.json \
--ledger-protocol-parameters hydra-cluster/config/protocol-parameters.json \
--hydra-signing-key demo/alice.sk
```
</details>

Then, build, sign and submit the transaction that runs the rewarding script:

```shell title="Withdraw zero transaction"
cardano-cli latest transaction build-raw \
--tx-in 0000000000000000000000000000000000000000000000000000000000000000#0 \
--tx-in-collateral 0000000000000000000000000000000000000000000000000000000000000000#0 \
--tx-out addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z+100000000 \
--withdrawal stake_test17zadf9dcekqn9cxkg3q68y56f4d6ujxsv8l6kq4kz2cuduc3gm35e+0 \
--withdrawal-script-file rewarding.plutus \
--withdrawal-redeemer-value "{}" \
--withdrawal-execution-units "(10000000000, 14000000)" \
--protocol-params-file hydra-cluster/config/protocol-parameters.json \
--fee 0 \
--out-file tx.json

cardano-cli latest transaction sign \
--tx-body-file tx.json \
--signing-key-file hydra-cluster/config/credentials/alice-funds.sk \
--out-file tx-signed.json

cat tx-signed.json | jq -c '{tag: "NewTx", transaction: .}' | websocat ws://localhost:4001
```

## Registering script - not needed!

You might have noticed that registering the stake address was not needed - this is different than on the Cardano L1!

While you don't need to do it, you can still submit a transaction that registers the stake address and the L2 ledger will just ignore it:

```shell title="Register stake transaction"
cardano-cli latest stake-address registration-certificate \
--stake-address stake_test17zadf9dcekqn9cxkg3q68y56f4d6ujxsv8l6kq4kz2cuduc3gm35e \
--key-reg-deposit-amt 2000000 \
--out-file reg.cert

cardano-cli latest transaction build-raw \
--tx-in 0000000000000000000000000000000000000000000000000000000000000000#0 \
--tx-in-collateral 0000000000000000000000000000000000000000000000000000000000000000#0 \
--tx-out addr_test1vp5cxztpc6hep9ds7fjgmle3l225tk8ske3rmwr9adu0m6qchmx5z+98000000 \
--certificate reg.cert \
--certificate-script-file rewarding.plutus \
--certificate-redeemer-value "{}" \
--certificate-execution-units "(10000000000, 14000000)" \
--protocol-params-file hydra-cluster/config/protocol-parameters.json \
--fee 0 \
--out-file tx.json

cardano-cli latest transaction sign \
--tx-body-file tx.json \
--signing-key-file hydra-cluster/config/credentials/alice-funds.sk \
--out-file tx-signed.json

cat tx-signed.json | jq -c '{tag: "NewTx", transaction: .}' | websocat ws://localhost:4001
```
1 change: 1 addition & 0 deletions hydra-cardano-api/src/Hydra/Cardano/Api.hs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ import Cardano.Api.Shelley as X (
ShelleyGenesis (..),
ShelleyLedgerEra,
SigningKey (..),
StakeCredential (..),
VerificationKey (..),
fromAlonzoCostModels,
fromAlonzoPrices,
Expand Down
Loading