Skip to main content

30. Use CBOR in external representation of Cardano transactions

· 3 min read
Arnaud Bailly

Status

Accepted

Context

  • The Hydra.Ledger.Cardano module provides ToJSON/FromJSON instances for Tx and AlonzoTx
    • We have specified this format as part of Hydra API
  • These instances appear in a few places as part of Hydra API:
    • In the ServerOutput sent by the node to clients
    • In the HydraNodeLog as part of Hydra's logging output
    • In the StateChanged events which are persisted and allow hydra-node to restart gracefully after stopping
  • In other places the hydra-node produces, expects, or accepts a CBOR-encoded transaction:
  • Note that in the latter 2 cases, the hydra-node accepts a hex-CBOR-encoded JSON string to represent a transaction and this particular case is handled directly in the FromJSON instance for transactions where 3 different representations are even accepted:
    • JSON object detailing the transaction
    • A JSON string representing CBOR-encoding of a transaction
    • Or a TextEnvelope which wraps the CBOR transaction in a simple JSON object
  • Using JSON-based representation of Cardano transactions is problematic because:
    • The representation we are providing is not canonical nor widely used, and therefore require maintenance when the underlying cardano-ledger API changes
    • More importantly the JSON representation contains a txId field which is computed from the CBOR encoding of the transaction. When this encoding changes, the transaction id changes even though no other part of the transaction has changed. This implies that we could send and receive transactions with incorrect or inconsistent identifiers.
  • This is true for any content-addressable piece of data, eg. any piece of data whose unique identifier is derived from the data itself, but not of say UTxO which is just data.

Decision

  • Drop support of "structured" JSON encoding of transactions in log messages, external APIs, and local storage of a node state
  • Require JSON encoding for transactions that consists in:
    • A cborHex string field containing the base16 CBOR-encoded transaction
    • An optional txId string field containing the Cardano transaction id, i.e. the base16 encoded Blake2b256 hash of the transaction body bytes
    • When present, the txId MUST be consistent with the cborHex. This will be guaranteed for data produced by Hydra, but input data (eg. through a NewTx message) that does not respect this constraint will be rejected

Consequences

  • This is a breaking change and client applications must decode the full transaction CBOR before accessing any part of it
    • Hydra clients like hydraw, hydra-auction, hydra-pay, hydra-poll and hydra-chess` need to be updated
  • By providing a txId field alongside the CBOR encoding, we still allow clients to observe the lifecycle of a transaction inside a Head as it gets validated and confirmed without requiring from them to be able to decode the CBOR body and compute the txId themselves
    • This is particularly important for monitoring which usually does not care about the details of transactions
  • We should point users to existing tools for decoding transactions' content in a human-readable format as this can be useful for troubleshooting:
    • cardano-cli transaction view --tx-file <path to tx envelope file> is one example
  • We need to version the data that's persisted and exchanged, e.g the Head state and network messages, in order to ensure nodes can either gracefully migrate stored data or detect explicitly versions inconsistency
  • We should use the cardanonical schemas should the need arise to represent transaction in JSON again