Skip to content

Delete hydra-cardano-api and use cardano-api directly. #2497

@locallycompact

Description

@locallycompact

hydra-cardano-api as it exists is counter-productive. It's README claims to be an "anti-corruption layer" but this term is meaningless - such a description does not provide any laws, properties or guarantees that indicate what a consumer of this library expects to benefit from, nor what the maintainers of the library should be interested in including or providing in on-going maintenance on it. Vaguely, it acts as a kitchen sink prelude that provides the type application monomorphisms forall era. era ~ ConwayEra type parameters for the types in cardano-api, and reducing the need for passing witness tokens as arguments to every function. This is speciously similar in intent to a shim library like, just to pick one random example, haskell-src-exts-simple, that rebinds the entire haskell-src-exts api surface to ignore the source location type by fixing it as unit, but in fact it isn't and in any case it is not possible for us to do this with cardano-api, nor is it desirable for several reasons.

  1. We can not avoid importing cardano-api anyway due to qualified interfaces.

cardano-api contains a collections interface under Cardano.Api.UTxO.hs containing map/list-like functions intended to be imported qualified. We use this throughout our codebase. This interface is parametrically polymorphic and pointless for us to shim. Rebinding the interface in this way does not save us anything.

  1. Cross-package module re-exports.

hydra-cardano-api is full of cross-package module re-exports that constantly cause symbol clashes. That has been described here: #2351

  1. The use of monomorphism is causing more work than simply leaving it as parametric.

For some reason unclear to me, there is an implicit assumption made by hydra-cardano-api that monomorphic code is simpler to maintain than polymorphic code. This is obviously untrue with no exceptions. Polymorphic code is harder to get wrong and less likely to break as a result of future ident changes. I refer to this article for a longer explanation.

  1. hydra-cardano-api obscures the difference between our use of transaction types on the L1 and the L2.

For any given hydra head, cross-era upgrade support is not particularly relevant. However for our interaction with the L1, our code should work just fine with BabbageEraOnwards. Our functions should simply say that. Also, as described above, functions that work with BabbageEraOnwards will continue to work transparently in the face of extensions to the witnesses.

  1. hydra-cardano-api obfuscates when code can be safely upstreamed.

Also mentioned in the cross-package module re-export issue, overly concerned function signatures obscure when a function can be safely marked for migration upstream. Adhering to a principle of least concern would ensure that when a function is defined locally, that its function signature and implementation would be the same /as if/ it had been defined upstream. Then it can be ported verbatim and mutualised.

  1. cardano-api updates very frequently and this breaks extremely regularly

It has been argued that cardano-api "only needs to be fixed once" and then we can forget about it. This is extremely far from the truth. cardano-api updates minor versions on average more than once a month and in most cases this causes very involved breaking changes. It is clear to me from working on all of these that without the monomorphism there in the first place, and in addition with properly qualified imports, /most/ of these upgrades would have been transparent or minimal.

Summary

hydra-cardano-api is optimising for an brevity of type signatures and argument passing at the cost of a heavy imposition of monomorphic code - the cost of maintaining which is enormous. Whatever the intent of this library was - it has failed. In terms of wall clock time spent fixing issues with it and in terms of clarity and accuracy of the type signatures, this approach is not worth keeping. Leaning into cardano-api, fixing and contributing to it, and qualifying our use of it versus cardano-ledger using haskell's qualified statements properly would substantially reduce ambiguity in any given function definition, while at the same time reducing our code volume as much of it does not need to be here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Triage 🏥

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions