Status
Accepted
Context
- The state of a Hydra Head is currently persisted as a whole upon each
NewState
outcome from theupdate
function: The new state is serialised and thestate
file 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 theHeadState
and 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
HeadState
in the hydra-node, while conceptually being anEffect
is handled differently from otherEffect
s: The state is updated transactionally through a dedicatedmodifyHeadState
function in the core loop of processing events, and then effects are processed.
Decision
Implement state persistence using Event Sourcing. Practically, this means:
- Replace the
NewState
outcome with aStateChanged
event which can be part of theOutcome
ofHeadLogic
'supdate
function, representing the change to be applied to the current state. - Add an
aggregate
function to manage applyingStateChanged
events on top of the currentHeadState
to keep it updated in-memory. - Persist
StateChanged
s in an append-only log using a dedicated handle. - Upon node startup, reread
StateChanged
events 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 inupdate
and once inaggregate
.Terms from the specification are distributed over
update
andaggregate
function. For example, the statements about updating all seen transactions would now be inaggregate
and not anymore inupdate
.New possibilities this change introduces with respect to
ServerOutput
handling and client's access to a head's state:- Instead of having the
HeadLogic
emits 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
StateChanged
an 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.