Skip to content

Ecosystem adjustments

Giovanni Garufi edited this page Jul 19, 2022 · 7 revisions

Issue we faced

Lack of Contract Monad

One of the first hurdles, for a Cardano L1 DApp developer, is to get used to the lack of Contract monad to handle the off-chain code.

Transactions can be built through Cardano-api, which is not too hard to do, but definitely something that might be unfamiliar at first. The Tx module can serve as a reference on how to build these transactions, in there we have gathered some utility functions that we use to build our transactions.

However, while lack of familiarity with Cardano-api is somewhat of a secondary concern, a deeper issue arises when trying to write tests for a Contract that is meant to exist inside a head. While there are tools that allow you to easily run tests inside the head, they are not yet well documented and don't provide the same ease and flexibility as something like Emulator.Trace, this might lead to a situation where we still end up writing Off-chain code in the Contract monad, just to have an easy way of testing and debugging our contracts.

Another consideration to make here is that we may want to implement our contracts differently if we only mean them to run in a head. A simple example of this has to do with accounting for fees. In the RPS game we implemented, our contract checks that the user that is trying to claim a pair of UTxOs representing a round, is paying the ada to the correct user. On L1 the contract might have to account for the fees being deducted from the total amount of ada that is being claimed, but inside a hydra head there would be no such fees. In this example, a contract that is only meant to run inside a hydra head could disregard fees completely, while a contract for L1 might want to account for them.

Lack of tools to interact with the head

Another potential blocker is the lack of tools like chain-index or oura inside a head. Because of this DApp developers might have to re-implement some functionalities they have taken for granted before. One example of this, deriving from the lack of chain-index, is the fact that a DApp should keep its DatumCache around, by maintaining a map of DatumHash to Datum around that it updates every time it sees a transaction appear in the head, and that transaction is then confirmed in the snapshot. This adds quite a bit of extra complexity, however, this functionality could relatively easily be implemented in a separate module that is then shared between DApps.

No PAB Simulator

This is another issue that a developer coming from the Cardano ecosystem will face, tools like the PAB simulator allow for rapid testing and spinning up a test environment.

Hydra-cluster can be used inside the head for similar purposes, however, there is no documentation around it, and it looks like it is a tool that is intended to be used internally rather than made available for DApps developers. We had the privilege of being in close contact with the Hydra team, and through their guidance setting up hydra-cluster we managed to develop a test suite for our CLI tool, but this would have been considerably harder with no external guidance.

Validation errors inside the head are encoded

This is a minor pain point, as there is an available workaround, but errors thrown by a validator or minting policy inside the head, currently need to be manually decoded (this can be done by using debugPlutus from Cardano.Ledger.Alonzo.TxInfo). Having the errors reported in human-readable form would greatly improve the experience of developing the contract inside the head.

Lack of common SDK

At the moment, every DApp must manage the head lifecycle independently. On one hand this makes sense, as different use cases might require different setups. However, it would be useful to aggregate some of this functionality into an SDK or common library that can be shared across applications.

One other consideration, which is somewhat tied to this, is that having to implement head lifecycle management leads at the application level forces the application to deal with the inherent statefulness of managing the head (is it open, closed, etc). This is something that should be explored, and as more apps are built on hydra will become clear, but it would be interesting to start thinking about ways to either: hide this statefulness away from the developers, or provide them tools to deal with it correctly.

In the RPS game we ended up having a handful of functions, one for each state of the head, and each one of them has to deal with messages coming from the hydra nodes, or user inputs in a different way. The end result is similar to a state machine, where the legal and available transitions depend on the current state the head is in.

It is unclear if the state-machine model is inherent in applications building on hydra, or if through abstracting away some of the head management, developers could focus only on the behaviour of their application once the head is open and properly initialised. Either way, some common tools could help developers in dealing with this kind of issue.

Issues

This is a list of issues that were opened against the main hydra repo during the development of this project:

Opened the following issues:

Clone this wiki locally