Status
Draft
Context
ADR 18 merged both
headState
andchainState
into one single state in the Hydra node, giving the chain layer a way to fetch and update thechainState
when observing a chain event.ADR 23 outlined the need for a local chain state in the chain layer again to correctly handle correct observation of multiple relevant transactions and the resulting
chainState
updates.The
ChainStateType tx
for our "actual" Cardano chain layer is currently:data ChainStateAt = ChainStateAt
{ chainState :: ChainState
, recordedAt :: Maybe ChainPoint
}
data ChainState
= Idle
| Initial InitialState
| Open OpenState
| Closed ClosedStatewhere
InitialState
,OpenState
andClosedState
hold elaborate information about the currently tracked Hydra head.We face difficulties to provide sufficient user feedback when an
initTx
was observed but (for example) keys do not match our expectation.- Core problem is, that
observeInit
is required to take a decision whether it wants to "adopt" the Head by returning anInitialState
or not. - This makes it impossible to provide user feedback through the
HeadLogic
andAPI
layers.
- Core problem is, that
We want to build a Hydra head explorer, which should be able to keep track and discover Hydra heads and their state changes even when the heads were initialized before starting the explorer.
Decision
- We supersede ADR 18 with the current ADR.
Changes internal to Direct chain layer
Introduce a
ResolvedTx
type that has its inputs resolved. Where a normalTx
will only containTxIn
information of its inputs, aResolvedTx
also includes theTxOut
for each input.Change
ChainSyncHandler
signature toonRollForward :: BlockHeader -> [ResolvedTx] -> m ()
Change observing function signature to
observeSomeTx :: ChainContext -> ResolvedTx -> Maybe (OnChainTx Tx)
. Notably there is noChainState
involved.Do not guard observation by
HeadId
in the chain layer and instead do it in theHeadLogic
layer.Define a
SpendableUTxO
type that is aUTxO
with potentially needed datums included.- TBD: instead we could decide to use inline datums and rely on
UTxO
containing them
- TBD: instead we could decide to use inline datums and rely on
Change transaction creation functions
initialize
,commit
,abort
,collect
,close
,contest
andfanout
inHydra.Direct.Chain.State
to takeSpendableUTxO
andHeadId
/HeadParameters
as needed.Extend
IsChainState
type class to enforce that it can be updated by concurrent transactionsupdate :: ChainStateType tx -> [tx] -> ChainStateType tx
.- While this is not strictly needed "outside" of the chain layer, it will have us not fall into the same pit again.
Change
ChainStateAt
to only hold aspendableUTxO
and therecordedAt
.Update the
LocalChainState
inonRollForward
by usingupdate
and pushing a newChainStateAt
generically.
TBD:
- Impact on generators
Chain interface changes
Add
HeadId
andHeadParameters
toPostChainTx
.Add
HeadId
to allOnChainTx
constructors.Extend
OnInitTx
with observed chain participants.- TBD: How are cardano verification keys generically represented in
HeadLogic
?
- TBD: How are cardano verification keys generically represented in
Extend
OnContestTx
with new deadline and a list of contesters.Move off-chain checks for what makes a "proper head" to
HeadLogic
TBD:
- Merge
HeadSeed
andHeadId
? How to abstract?
Consequences
All logic is kept in the logic layer and no protocol decisions (i.e. whether to adopt or ignore a head initialization) are taken in the chain layer.
- The
HeadLogic
gets informed of any properinitTx
and can log that it is ignored and for what reason.
- The
The transaction observation and construction functions can be moved into a dedicated package that is cardano-specific, but not requires special state knowledge of the "direct chain following" and can be re-used as a library.
All transaction observation functions used by
observeSomeTx
will need to be able to identify a Hydra Head transaction from only theResolvedTx
and theChainContext
Any
Chain Tx
implementation wanting to re-use existing transaction observation functions must be able to resolve transaction inputs (against some ledger state) and produceResolvedTx
.- A chain-following implementation (as
Hydra.Chain.Direct
) can keep previous transactions around. - A chain indexer on "interesting" protocol addresses can be used to efficiently query most inputs.
- A chain-following implementation (as
We can get rid of the
Hydra.Chain.Direct.State
glue code altogether.While this does not directly supersede ADR23, it paves the way to remove
LocalChainState
again as theChainStateAt
is now combinable from multiple transactions (seeupdate
above) and we can keep the state (again) only in theHeadState
aggregate. Note that this would shift the rollback handling back into the logic layer.