24. Persist state changes incrementally
Status
Accepted
Context
- The state of a Hydra Head is currently persisted as a whole upon each
NewStateoutcome from theupdatefunction: The new state is serialised and thestatefile is overwritten with the corresponding bytes. While this is a straightforward strategy to implement, it has a huge impact on the performance of a Hydra Head as serialising a large data structure like theHeadStateand completely overwriting a file is costly- We revisited our benchmarks and found that persistence was the major bottleneck when measuring roundtrip confirmation time,e g. the time it takes from a client's perspective to submit a transaction and observe in a
ConfirmedSnapshot
- We revisited our benchmarks and found that persistence was the major bottleneck when measuring roundtrip confirmation time,e g. the time it takes from a client's perspective to submit a transaction and observe in a
- Furthermore, the way we currently handle changes to the
HeadStatein the hydra-node, while conceptually being anEffectis handled differently from otherEffects: The state is updated transactionally through a dedicatedmodifyHeadStatefunction in the core loop of processing events, and then effects are processed.
Decision
Implement state persistence using Event Sourcing. Practically, this means:
- Replace the
NewStateoutcome with aStateChangedevent which can be part of theOutcomeofHeadLogic'supdatefunction, representing the change to be applied to the current state. - Add an
aggregatefunction to manage applyingStateChangedevents on top of the currentHeadStateto keep it updated in-memory. - Persist
StateChangeds in an append-only log using a dedicated handle. - Upon node startup, reread
StateChangedevents log and reapply those to reset theHeadState.
The following sequence diagram illustrates new event handling in the HeadLogic:
Consequences
-
🐎 The main expected consequence of this change is an increase of the overall performance of Hydra Head network.
-
Need to pattern match twice on the
HeadState, once inupdateand once inaggregate. -
Terms from the specification are distributed over
updateandaggregatefunction. For example, the statements about updating all seen transactions would now be inaggregateand not anymore inupdate. -
New possibilities this change introduces with respect to
ServerOutputhandling and client's access to a head's state:- Instead of having the
HeadLogicemits directly aClientEffect, the latter could be the result of a client-centric interpretation of aStateChanged. - Pushing this a little further, we could maintain a Query Model for clients with a dedicated Query API to ease implementation of stateless clients.
- Instead of having the
-
Calling
StateChangedan event while treating it in the code alongside effects might introduce some confusion as we already use the word Event to designate the inputs (a.k.a. commands) to the Head logic state machine. We might want at some later point to unify the terminology.


