23. Local chain state in chain layer
· 2 min read
Status
Accepted
Context
- ADR 18 merged both
headStateandchainStateinto one single state in the Hydra node, giving the chain layer a way to fetch and update thechainStatewhen observing a chain event. - Having the
headStatecontaining thechainStatemade persistency easier to deal with: we ensure that we always save cohesive states. - When opening our first head on mainnet we suffered from a commit/rollback
issue that was the
result of a race condition in the management of the
chainStateas implemented in the context of ADR 18. - Reproducing the issue by introducing rollbacks in the model based tests, we discovered that, as a client of a hydra-node, we had no idea how to deal with the rollback event as it is defined now.
- #185 plans to improve rollback management.
The following picture details the race condition through an example:
-
The DirectChain component fetch some
chainState 0from theheadState -
The DirectChain component observes a transaction and it
- publishes an event about this observation
- updates the
headStatewith somechainState 1
- The Node processes the event and emits a new
headStatewith apreviousRecoverableStatein case a rollback later happens
The problem is that HeadState 2 in the figure should point to a previous
recoverable head state containing chainState 0 and not chainState 1.

Updating the chain state only in the HeadLogic leads to problems when several
transactions are in the same block. This can be mitigated by keeping a volatile
chain state locally while analysing the block. But then it leads to race
conditions issues if, for some reason, blocks are produced faster than they are
processed by the HeadLogic. Low probability in production but higher when
testing.
Decision
- We supersede ADR 18 with the current ADR.
- A local chain state is re-introduced in the chain component, not shared with the head logic.
- A copy of the
chainStateis kept in theheadStateto keep the benefits of ADR 18 regarding persistency. - The
RolledBackoutput is removed from the API unless actionable by users or #185 implemented.
Consequences
- The rollback logic is removed from the HeadLogic and only maintained in the chain component.
- The Rollback event carries the ChainState.
- At the node startup, we initialize the chain layer with the persisted
chainState

