Skip to content

Technical Architecture

Arnaud Bailly edited this page Jun 5, 2021 · 7 revisions

Technical Architecture

This document is constant work-in-progress which serves as raw material for more formal documents that would be published as part of the release lifecycle of Hydra node.

Principles

TODO: This should really be ADRs?

Reactive core

At its heart the hydra-node is a reactive loop that:

  1. Consumes input events sequentially from an internal queue,
  2. Applies each event to the current state yielding potentially an updated state and a sequence of effects,
  3. Execute each effect sequentially.

This design is basically identical to React's redux behaviour which in turn is inspired by The Elm Architecture which itself is a simplification of Functional Reactive Programming principles.

Asynchronous Duplex Client API

The reactive nature of the Hydra node means Request-response paradigm is not a good fit to provide a Client API: Clients input a stream of commands to a node which in turns issues a stream of responses representing the observable outcome of previous commands and interaction with peers in the network.

Therefore, the main API is exposed using the Websocket protocol with inputs and outputs conforming to some textual representation of Commands and Results.

TODO: Rename ClientRequest -> Command and ClientResponse -> Result to be consistent?

This implies client software should be implemented accordingly and most notably cannot rely on any kind of synchronous response to give feedback to potential users or higher-level clients.

COMMENT(SN): These responses might also be sent unfacilitated by a client, e.g. when some other hydra-node initializes a Head and "your" hydra-node sees that init transactions on chain, it would send a response indicating such without an explicit request

Effects

  • Effects pertaining to the Hydra domain are implemented using the Handle pattern
  • System-level effects and general IO are used via the io-sim-classes package which provides typeclasses abstracting over basic IO operations.
  • Instantiation to concrete IO is pushed at the outermost layers

With-pattern for Duplex Channels

  • With pattern or bracket pattern is a functional programming idiom, a particular instance of Continuation-Passing Style, whereby one component that controls some resource that is consumed by another component of the system, is created via a function that takes as argument a function consuming the resource, instead of returning it.
  • We use this pattern to provide implementations of various interfaces to components of the system with which the Node exchanges messages:
    
    
    

Hydra Node

The following diagram represents the internal structure of the HydraNode and the interactions between its components.

Legend:

  • Grayed boxes represent components which are not developed yet
  • Black boxes represent components which are expected to be used as black box, eg. without any knowledge of their inner workings.
  • Arrows depict the flow of data (Requests, messages, responses...)
  • We represent some components that are not part of the Hydra node proper for legibility's sake

Hydra Node

  • The HydraNode is a handle to all other components' handles
  • This handle is used by the main loop to processNextEvent and processEffect

Head Logic

  • It implements the Head Protocol's state machine as a pure function.
  • The protocol is described in two parts in the Hydra paper:
    • One part detailing how the Head deals with clients input, eg. ClientRequest:
    • Another part detailing how the Head reacts to peers input provided by the network, eg. HydraMessage:

OnChain Client

  • The OnChain client implements the Head-Chain Interaction part of the protocol:
  • Incoming and outgoing on-chain transactions are modelled as an OnChainTx data type that abstracts away the details of the structure of the transaction.
  • The ChainEffect produced by the Head Logic's state machine contains representing a transaction to be posted on-chain. The node delegates the actual posting of the transaction to a OnChain handle wrapping a single postTx function.
  • Incoming transactions from the chain are handled using a similar Callback function which is passed to the actual chain client upon initialisation of the node.
    • Typically, this function wraps incoming OnChainTx as ChainEvent and put them into the Event queue

Network

Head State

  • The main component of the Head is an interface to the Ledger which allows the head to maintain and update the state of Seen or confirmed transactions and UTxOs according to its protocol.

Logging

  • Structured logging is implemented using IOHK monitoring framework which provides backend for contra-tracer generic logging
  • Each component defines its own tracing messages as a datatype and they are aggregated in the HydraLog datatype. Specialized Tracers can be passed around from the top-level one using contramap to peel one layer of the onion
  • Configuration of the main tracer is done via the withTracer wrapper function

Monitoring

  • Metrics and monitoring are piggy-backed on tracing events:
    • Monitoring collection is configured at start of the hydra-node
    • Traced events can be interpreted as contributing to some specific metric value without trace producers needing to be aware of how this process happens
  • Metrics are exposed using Prometheus format over URI /metrics from an HTTP server started on a configurable port.

Chain Client & Smart Contracts

Hydra Plutus Smart Contracts

Mock Chain

Clone this wiki locally