29. EventSource & EventSink abstractions
Status
Accepted
Context
-
The Hydra node represents a significant engineering asset, providing layer 1 monitoring, peer to peer consensus, durable persistence, and an isomorphic Cardano ledger. Because of this, it is being eyed as a key building block not just in Hydra based applications, but other protocols as well.
-
Currently the
hydra-nodeuses a very basic persistence mechanism for it's internalHeadState, that is savingStateChangedevents to file on disk and reading them back to load and re-aggregate theHeadStateupon startup.- Some production setups would benefit from storing these events to a service like Amazon Kinesis data stream instead of local files.
-
The
hydra-nodewebsocket-based API is the only available event stream right now and might not fit all purposes.- See also ADR 3 and 25
- Internally, this is realized as a single
Serverhandle which cansendOutput :: ServerOutput tx -> m () - These
ServerOutputs closely relate toStateChangedevents andClientEffects are yielded by the logic layer often together with theStateChanged. For example:
onInitialChainAbortTx newChainState committed headId =
StateChanged HeadAborted{chainState = newChainState}
<> Effects [ClientEffect $ ServerOutput.HeadIsAborted{headId, utxo = fold committed}] -
Users of
hydra-nodeare interested to add alternative implementations for storing, loading and consuming events of the Hydra protocol.
Decision
-
We create two new interfaces in the
hydra-nodearchitecture:data EventSource e m = EventSource { getEvents :: m [e] }data EventSink e m = EventSink { putEvent :: e -> m () }
-
We realize our current
PersistenceIncrementalused for persistingStateChangedevents is both anEventSourceand anEventSink -
We drop the
persistencefrom the main handleHydraNode tx m, add oneEventSourceand allow manyEventSinks
data HydraNode tx m = HydraNode
{ -- ...
, eventSource :: EventSource (StateEvent tx) m
, eventSinks :: [EventSink (StateEvent tx) m]
}
-
The
hydra-nodewill load events andhydrateitsHeadStateusinggetEventsof the singleeventSource. -
The
stepHydraNodemain loop does callputEventon alleventSinksin sequence. Any failure will make thehydra-nodeprocess terminate and require a restart. -
When loading events from
eventSourceonhydra-nodestartup, it will also re-submit events viaputEventto alleventSinks. -
The default
hydra-nodemain loop does use the file-basedEventSourceand a single file-basedEventSink(using the same file). -
We realize that the
EventSourceandEventSinkhandles, as well as their aggregation inHydraNodeare used as an API by forks of thehydra-nodeand try to minimize changes to it.
Consequences
-
The default operation of the
hyda-noderemains unchanged. -
There are other things called
EventandEventQueue(putEvent)right now in thehydra-node. This is getting confusing and when we implement this, we should also rename several things first (tidying). -
Interface first: Implementations of
EventSinkshould specify their format in a non-ambiguous and versioned way, especially when a correspondingEventSourceexists. -
The API
Servercan be modelled and refactored as anEventSink. -
Projects forking the hydra node have dedicated extension points for producing and consuming events.
-
Sundae Labs can build a "Save transaction batches to S3" proof of concept
EventSink. -
Sundae Labs can build a "Scrolls source"
EventSink. -
Sundae Labs can build a "Amazon Kinesis"
EventSourceandEventSink.
Out of scope / future work
-
Available implementations for
EventSourceandEventSinkcould be- configured upon
hydra-nodestartup using for example URIs:--event-source file://stateor--event-sink s3://some-bucket - dynamically loaded as plugins without having to fork
hydra-node.
- configured upon
-
The
NetworkandChainparts qualify asEventSinks as well or shall those be triggered byEffects still?




