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

Incremental decommit #1057

Closed
16 tasks done
ch1bo opened this issue Sep 5, 2023 · 5 comments · Fixed by #1344
Closed
16 tasks done

Incremental decommit #1057

ch1bo opened this issue Sep 5, 2023 · 5 comments · Fixed by #1344
Labels
amber ⚠️ Medium complexity or partly unclear feature L1 Affects the on-chain protocol of Hydra L2 Affect off-chain part of the Head protocol/network 💬 feature A feature on our roadmap
Milestone

Comments

@ch1bo
Copy link
Collaborator

ch1bo commented Sep 5, 2023

Why

Hydra Heads should not need to be closed to remove funds. This will make Hydra Heads more flexible in enables use cases where long-living Heads are beneficial.

Also, the current protocol may result in "non-finalizable" heads when some UTxO can't be represented on the Cardano mainchain. It would be desirable to recover at least compatible outputs back on L1.

What

Implement the protocol extension for de-committing only part of the Head state (without closing the Head) as already briefly described in the original Hydra Head paper.

"As user, I want to remove my funds from the head to make them available on the Cardano L1"

  • When the head is open, a hydra client can request an incremental decommit using the Decommit websocket command or http request POST /decommit
    • The payload / request body is a "decommit transaction" Tx is just a list of transaction output references (aka. transaction inputs), in cardano-api: [TxIn]
    • A decommit tx is spending inputs from the confirmed UTxO in the head, but will produce UTxO which are to be decommitted into the L1
    • All head participants agree on the decommit tx by validating it against the L2 ledger state.
    • With this agreement, the hydra-node does create and submit a decrementTx onto the L1
  • Submitting the decrementTx will make the requested outputs available on the Cardano L1
  • A client output informs about the requested, approved and completed decommit

Properties

  • Closing the head with a same snapshot as a previous decrement must not produce the UTxO again.
  • Funds must be returned even if decrementTx was never submitted and the head gets closed instead.
  • The head should be live while decommitting, i.e. process transactions of independent UTxOs.

Security

  • The specification is updated and checked with researchers whether it is consistent with the properties above (walk-through)
  • All validator changes are tested using the mutation testing framework, covering all constraints from the specification and we saw each test "fail for the right reason", i.e. no specification change without a corresponding mutation and (at least) one mutation per constraint

Out of scope

  • Multiple decommits should be issuable irrespective whether they are "settled" yet or not. i.e. there can be times when no decommit is possible (yet)
  • Incremental decommit when head is closed (= partial fanout)
  • Validator changes are audited by the internal audit team at IO

How

Idea: Re-use the ReqSn and snapshots in off-chain consensus to request exclusion of UTxO. With that "granted", on-chain open state is updated in a new decrementTx. We need to make sure off-chain snapshots can only be used to close specific open heads (replay protection).

  1. Head is open, $\eta_0$ locked, off-chain busy transacting
  2. Client requests decommit by submitting a decommit transaction $\mathsf{tx_{dec}}$ which translates into a $ReqDec(\mathsf{tx_{dec}})$ network request
  3. Each participant validates $\mathsf{tx_{dec}}$ against the confirmed ledger state $\bar{U}$ and if valid, stores outputs of $\mathsf{tx_{dec}}$ as $U_\omega$
  4. Snapshot leader requests exclusion of UTxO $U_\omega$: $ReqSn(sn, txids, U_\omega)$ (TBD: only submit out-refs?)
  5. All participants acknowledge $\bar{U}$ excludes $U_\omega$ by signing the corresponding snapshot's number, $\eta = \mathsf{Digest}(\bar{U})$ and $\eta_\omega = \mathsf{Digest}(U_\omega))$, where $\mathsf{Digest}$ is the same function we use today to create a "combine" of some UTxO set into a "digest" (see specification section 5.3)
  6. decrementTx
    • evolves head state $(open, sn_i, \eta_i)$ by spending head output,
    • into head state $(open, sn_{i+1}, \eta_{i+1})$ + outputs equivalent to $U_\omega$
    • given a multi-signed $\xi$ of $\eta_i$, $\eta_{i+1}$, and $\eta_\omega$ as redeemer.
  7. closeTx
    • evolves head state $(open, sn_i, \eta_i)$
    • into head state $(closed, sn_c, \eta_c, \eta_\omega^?)$,
    • given a multi-signed certificate "referring" $\eta_i$ of snapshotted $\eta_c$ (corresponding to a confirmed $\bar{U}$) and, if a decommit is in-flight the $\eta_\omega$, which must be present in the output head state
  8. fanoutTx
    • ensures outputs correspond to both, $\eta_c$ and $\eta_{omega}$ (if present), in sequence
flowchart LR
  open0([open η0])

  open0 -- "Cert(η0,η1) + ηω" --> decrementTx
  decrementTx --> open1([open η0 η1])
  decrementTx --> decommit1([decommitted o1])
  decrementTx --> decommit2([decommitted o2])

  open1 -- "Cert(η1,ηc)"  --> closeTx
  closeTx --> closed1([closed ηc])
Loading

Possible tasks

Latest task breakdown

To be discussed

  • How can any participant request removal if not snapshot leader?
    • Add a new message $ReqDec(U_\omega)$ to request a decrement in the next snapshot (even the snapshot leader, like ReqTx)
  • What happens if the incremental decommit is requested and acknowledged on the L2, but the decrementTx is never submitted to L1?
    • The removed UTxO $U_\omega$ must remain part of the off-chain state and is used to fanout the full state, i.e. the closed state $\eta ~ \widehat{=} ~ \bar{U} \cup U_\omega$. For example, assuming the decrementTx above never happens, $\eta_0$ must correspond to $\bar{U} \cup U_\omega$ and fanoutTx produce all corresponding outputs
    • SMT proofs where only some UTxO are realized would make this more flexible.
    • (S)MT could allow verify $\eta \cup \eta_\omega$ in closeTx and lead to a normal closed state with a single $\eta$
    • Any participant can post the decrementTx to avoid stalling.
  • What if the agreed to remove state is not "fitting" into a single decrementTx?
    • Only agree "small enough" decrements off-chain (maybe complicated, but should be possible), or
    • Split off decremented state from $\eta$ and allow one or more withdrawTx (= partial fanout)?
    • This can be seen as an orthogonal issue very related to the purpose of Support larger # of UTXO via split-fanout #190
  • Do we need a "fancy" state reference as outlined by @mfitzi or are snapshot numbers enough?
    • Not for incremental decrement alone. Because decrements on-chain never impact off-chain availability of UTxOs. Also, rollbacks would only affect semantics if participants agree "too early" (upon seeing a decrementTx) to clean-up the corresponding $U_\omega$ from the off-chain state.
    • The state reference is the same meachanism as explained in Sign snapshots including the initial UTxO set #688, but generalized for multiple open states. A state reference is basically just the $\eta$ of the previous open state and needs to be used to decide on whether an off-chain snapshot is valid against the current state or the previous state. Detailed case separation TBD here (available as draft slides).
  • Why are SMT roots and non-inclusion proofs needed on the decrementTx instead of just multi-signing $\bar{U}$ and $U_\omega$?
    • They not needed and we can stick with the hand-rolled concat + hash approach, iff we extend the closed state with the "to-be-decommitted" $\eta_\omega$ derived from $U_\omega$ next to the normal $eta$ and the fanoutTx needs to recreate outputs satisfying both $\eta$ and $\eta_omega$ (related to point 2)
  • Is having [TxIn] on the endpoints convenient?
    • If not, change it to UTxO
    • Change it to Tx as we need to authorize a decommit (see comments)
  • Shall we add decrements (partial fanout) from a closed head?
    • Out of scope (see What)
@ch1bo ch1bo added the 💭 idea An idea or feature request label Sep 5, 2023
@ch1bo ch1bo mentioned this issue Sep 5, 2023
10 tasks
@ch1bo ch1bo self-assigned this Sep 5, 2023
@ch1bo ch1bo added L1 Affects the on-chain protocol of Hydra L2 Affect off-chain part of the Head protocol/network labels Sep 5, 2023
@ch1bo ch1bo added 💬 feature A feature on our roadmap amber ⚠️ Medium complexity or partly unclear feature and removed 💭 idea An idea or feature request labels Sep 20, 2023
@ch1bo
Copy link
Collaborator Author

ch1bo commented Nov 8, 2023

Drawn a transaction trace with the current design using our old-school notation:

Transaction traces - Incremental decommits (decrement) 2023-11-08

@ch1bo
Copy link
Collaborator Author

ch1bo commented Nov 16, 2023

Discussed the approach with researchers and here are today's notes also reflected in the TBD section above, while the main body of the issues requires some updating now:

Notes on decrements <2023-11-16 Thu>

  • We need the state reference also in decrement (rollback protection similar to η0)
    • state-ref = pid + η
    • consequence: to validate a close (that is allowed on the "previous open state") we need to carry the previous η in every open state (simliar like the η0 idea)
  • Can there be many decommits?
    • Sequential processing easier
    • Each participant can post the decrement transaction!
    • Δη could be also a collected MT root of all decrements requested / pending -> that would complicate on-chain proofs
  • What to fanout when closed with a Δη
    • Careful: depends which state was referenced -> close decides
    • Be able to check on chain that η u Δη !!
    • Or track two etas in close and fanout needs to realize both
  • Increment commits specified as TxIn
    • simple on-chain check, but enough!
    • could make off-chain complicated (need to lookup before signing)

@ch1bo ch1bo removed their assignment Nov 27, 2023
@ch1bo
Copy link
Collaborator Author

ch1bo commented Dec 13, 2023

We had a discussion today which led to the question:

How are decommits authenticated? How can we prevent "someone" to decommit funds of "someone" else?

Many use cases will mean a denial of service if any participant (or users "in proxy") can request decommitting arbitrary UTxO.

A simple example would be two actors Alice and Bob have both have a single UTxO in a head to do fast & cheap transactions to each other. Then Alice could request to decommit Bobs UTxO which will make him not able to send anything anymore.

Maybe this is a bit constructed, but certainly most use cases would be impacted by such an "attack" vector.

How is this different than close of a head?

Closing a head does "level the playing field" more as everyone is impacted the same.


For this feature to be useful, this needs to be handled and we should update the What requirements of this feature item!

Ideas we had to avoid/solve this:

  • Require witnesses for spending the UTxO and validate them in a ledger
  • Instead of requesting a UTxO to be decommitted, model that as a "special" Tx which needs to be applicable, but does not update the layer 2 ledger state

@ch1bo ch1bo added this to the 0.16.0 milestone Jan 23, 2024
@GeorgeFlerovsky
Copy link

GeorgeFlerovsky commented Jan 31, 2024

The person attempting to decommit must own the utxos in the hydra ledger.

In the hydrozoa paper, my approach was to include in the decommit request a transaction with no outputs and inputs consisting of the utxos to be decommitted. This transaction is invalid on L1 (which prevents it from being submitted there — an added benefit) but can be interpreted by a special ledger rule that disables the tx balancing check when handling decommit requests. Since the other ledger rules are still active, this means that:

  • Pubkey utxos can be decommitted only via tx signature from the pubkey.
  • Script utxos can be decommitted only by satisfying the scripts' validators' decommit redeemer.

Indeed, the above transaction precisely describes what should happen to the L2 ledger when the utxos are decommitted. On L1, such transactions are illegal because it must conserve tokens (modulo mint/burn); on L2, such transactions are necessary because utxos can enter/leave the system exogenously.

https://github.com/GeorgeFlerovsky/cardano-hydrozoa#decommit-on-l2

@ch1bo ch1bo linked a pull request Mar 8, 2024 that will close this issue
4 tasks
@ch1bo ch1bo removed this from the 0.16.0 milestone Apr 2, 2024
@ch1bo
Copy link
Collaborator Author

ch1bo commented Apr 8, 2024

Latest update of example transaction traces using signatures including $\eta_\omega$ (see #199 (comment) for more details)

Nominal decrement

Transaction traces - Incremental decommits 2024-04-08

Alternative: Close with U3 instead of decrement

Transaction traces - Close with U3 instead of decrement

Alternative: Close with U3 after decrement

Transaction traces - Close with U3 after decrement

@ch1bo ch1bo added this to the 0.18.0 milestone May 13, 2024
v0d1ch added a commit that referenced this issue Jul 1, 2024
Only specification changes for #1057 to get them merged first as
described in #1473.

:nail_care: Marked sections red that are about to change with
incremental decommits.

:nail_care: Adds `decrementTx` which removes UTxO from the head state to
protocol overview, on-chain and off-chain sections.

:nail_care: Updates close, contest and fanout steps accordingly.

:nail_care: Uses a "version counting" scheme to distinguish cases where
the same snapshot is used to decrement and close the head.

:nail_care: Removes $\mathcal{T}_{\mathsf{all}}$ book-keeping and makes
snapshots request full transactions. Adds a note that requesting only
transaction ids is possible if all parties keep an index. This
simplifies the specification (but departs from a 1:1 mapping to
implemented protocol logic in `Hydra.HeadLogic`)

:nail_care: (Re-)introduces snapshot objects to group confirmed
variables (e.g. $\bar{s}, \bar{v}$) which are just kept to refer to them
later on in `close`.

---

<!-- Consider each and tick it off one way or the other -->
* [ ] CHANGELOG updated or not needed
* [x] Documentation updated
* [x] Haddocks not needed
* [ ] No new TODOs introduced or explained herafter
   - [x] ~~Figures are not updated~~
- [ ] Some handwavy-ness when dealing with $tx_\omega$ and interface
between off-chain and on-chain in regards with $\mathsf{CloseType}$ is
unsharp

---------

Co-authored-by: Sasha Bogicevic <[email protected]>
@ch1bo ch1bo unassigned v0d1ch Jul 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
amber ⚠️ Medium complexity or partly unclear feature L1 Affects the on-chain protocol of Hydra L2 Affect off-chain part of the Head protocol/network 💬 feature A feature on our roadmap
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

3 participants