Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Hydra.HeadLogic
Description
Implements the Head Protocol's state machine as pure functions in an event sourced manner.
More specifically, the update
will handle incoming Event
(or rather
"commands" in event sourcing speak) and convert that into a set of
side-Effect
s and internal StateChanged
events, which in turn are
aggregate
d into a single HeadState
.
As the specification is using a more imperative way of specifying the protocl
behavior, one would find the decision logic in update
while state updates
can be found in the corresponding aggregate
branch.
Synopsis
- defaultTTL :: TTL
- onIdleClientInit :: Environment -> Outcome tx
- onIdleChainInitTx :: ChainStateType tx -> [Party] -> ContestationPeriod -> HeadId -> Outcome tx
- onInitialChainCommitTx :: Monoid (UTxOType tx) => InitialState tx -> ChainStateType tx -> Party -> UTxOType tx -> Outcome tx
- onInitialClientAbort :: Monoid (UTxOType tx) => InitialState tx -> Outcome tx
- onInitialChainAbortTx :: Monoid (UTxOType tx) => ChainStateType tx -> Committed tx -> HeadId -> Outcome tx
- onInitialChainCollectTx :: IsChainState tx => InitialState tx -> ChainStateType tx -> Outcome tx
- onOpenClientNewTx :: tx -> Outcome tx
- onOpenNetworkReqTx :: IsTx tx => Environment -> Ledger tx -> OpenState tx -> TTL -> tx -> Outcome tx
- onOpenNetworkReqSn :: IsTx tx => Environment -> Ledger tx -> OpenState tx -> Party -> SnapshotNumber -> [TxIdType tx] -> Outcome tx
- onOpenNetworkAckSn :: IsTx tx => Environment -> OpenState tx -> Party -> Signature (Snapshot tx) -> SnapshotNumber -> Outcome tx
- onOpenClientClose :: OpenState tx -> Outcome tx
- onOpenChainCloseTx :: OpenState tx -> ChainStateType tx -> SnapshotNumber -> UTCTime -> Outcome tx
- onClosedChainContestTx :: ClosedState tx -> SnapshotNumber -> Outcome tx
- onClosedClientFanout :: ClosedState tx -> Outcome tx
- onClosedChainFanoutTx :: ClosedState tx -> ChainStateType tx -> Outcome tx
- update :: IsChainState tx => Environment -> Ledger tx -> HeadState tx -> Event tx -> Outcome tx
- aggregate :: IsChainState tx => HeadState tx -> StateChanged tx -> HeadState tx
- aggregateState :: IsChainState tx => HeadState tx -> Outcome tx -> HeadState tx
- recoverState :: (Foldable t, IsChainState tx) => HeadState tx -> t (StateChanged tx) -> HeadState tx
- data Event tx
- = ClientEvent {
- clientInput :: ClientInput tx
- | NetworkEvent { }
- | OnChainEvent {
- chainEvent :: ChainEvent tx
- | PostTxError {
- postChainTx :: PostChainTx tx
- postTxError :: PostTxError tx
- = ClientEvent {
- type TTL = Natural
- data RequirementFailure tx
- = ReqSnNumberInvalid { }
- | ReqSnNotLeader { }
- | InvalidMultisignature {
- multisig :: Text
- vkeys :: [VerificationKey HydraKey]
- | SnapshotAlreadySigned { }
- | AckSnNumberInvalid { }
- | SnapshotDoesNotApply {
- requestedSn :: SnapshotNumber
- txid :: TxIdType tx
- error :: ValidationError
- data LogicError tx
- = InvalidEvent (Event tx) (HeadState tx)
- | RequireFailed (RequirementFailure tx)
- | NotOurHead {
- ourHeadId :: HeadId
- otherHeadId :: HeadId
- data ClosedState tx = ClosedState {
- parameters :: HeadParameters
- confirmedSnapshot :: ConfirmedSnapshot tx
- contestationDeadline :: UTCTime
- readyToFanoutSent :: Bool
- chainState :: ChainStateType tx
- headId :: HeadId
- data SeenSnapshot tx
- = NoSeenSnapshot
- | LastSeenSnapshot { }
- | RequestedSnapshot { }
- | SeenSnapshot { }
- data CoordinatedHeadState tx = CoordinatedHeadState {
- localUTxO :: UTxOType tx
- localTxs :: [tx]
- allTxs :: Map (TxIdType tx) tx
- confirmedSnapshot :: ConfirmedSnapshot tx
- seenSnapshot :: SeenSnapshot tx
- data OpenState tx = OpenState {}
- type Committed tx = Map Party (UTxOType tx)
- type PendingCommits = Set Party
- data InitialState tx = InitialState {}
- newtype IdleState tx = IdleState {
- chainState :: ChainStateType tx
- data HeadState tx
- = Idle (IdleState tx)
- | Initial (InitialState tx)
- | Open (OpenState tx)
- | Closed (ClosedState tx)
- data Environment = Environment {}
- getChainState :: HeadState tx -> ChainStateType tx
- setChainState :: ChainStateType tx -> HeadState tx -> HeadState tx
- seenSnapshotNumber :: SeenSnapshot tx -> SnapshotNumber
- data WaitReason tx
- data Outcome tx
- = Effects { }
- | StateChanged (StateChanged tx)
- | Wait {
- reason :: WaitReason tx
- | Error {
- error :: LogicError tx
- | Combined { }
- data StateChanged tx
- = HeadInitialized {
- parameters :: HeadParameters
- chainState :: ChainStateType tx
- headId :: HeadId
- | CommittedUTxO {
- party :: Party
- committedUTxO :: UTxOType tx
- chainState :: ChainStateType tx
- | HeadAborted {
- chainState :: ChainStateType tx
- | HeadOpened {
- chainState :: ChainStateType tx
- initialUTxO :: UTxOType tx
- | TransactionAppliedToLocalUTxO {
- tx :: tx
- newLocalUTxO :: UTxOType tx
- | SnapshotRequestDecided { }
- | SnapshotRequested {
- snapshot :: Snapshot tx
- requestedTxIds :: [TxIdType tx]
- newLocalUTxO :: UTxOType tx
- newLocalTxs :: [tx]
- | TransactionReceived {
- tx :: tx
- | PartySignedSnapshot { }
- | SnapshotConfirmed {
- snapshot :: Snapshot tx
- signatures :: MultiSignature (Snapshot tx)
- | HeadClosed {
- chainState :: ChainStateType tx
- contestationDeadline :: UTCTime
- | HeadIsReadyToFanout
- | HeadFannedOut {
- chainState :: ChainStateType tx
- | ChainRolledBack {
- chainState :: ChainStateType tx
- | TickObserved { }
- = HeadInitialized {
- data Effect tx
- = ClientEffect {
- serverOutput :: ServerOutput tx
- | NetworkEffect { }
- | OnChainEffect {
- postChainTx :: PostChainTx tx
- = ClientEffect {
- collectEffects :: Outcome tx -> [Effect tx]
- collectWaits :: Outcome tx -> [WaitReason tx]
- isLeader :: HeadParameters -> Party -> SnapshotNumber -> Bool
Documentation
defaultTTL :: TTL Source #
onIdleClientInit :: Environment -> Outcome tx Source #
Arguments
:: ChainStateType tx | New chain state. |
-> [Party] | |
-> ContestationPeriod | |
-> HeadId | |
-> Outcome tx |
Observe an init transaction, initialize parameters in an InitialState
and
notify clients that they can now commit.
Transition: IdleState
→ InitialState
onInitialChainCommitTx Source #
Arguments
:: Monoid (UTxOType tx) | |
=> InitialState tx | |
-> ChainStateType tx | New chain state |
-> Party | Comitting party |
-> UTxOType tx | Committed UTxO |
-> Outcome tx |
Observe a commit transaction and record the committed UTxO in the state. Also, if this is the last commit to be observed, post a collect-com transaction on-chain.
Transition: InitialState
→ InitialState
onInitialClientAbort :: Monoid (UTxOType tx) => InitialState tx -> Outcome tx Source #
Client request to abort the head. This leads to an abort transaction on chain, reimbursing already committed UTxOs.
Transition: InitialState
→ InitialState
onInitialChainAbortTx Source #
Arguments
:: Monoid (UTxOType tx) | |
=> ChainStateType tx | New chain state |
-> Committed tx | |
-> HeadId | |
-> Outcome tx |
Observe an abort transaction by switching the state and notifying clients about it.
Transition: InitialState
→ IdleState
onInitialChainCollectTx Source #
Arguments
:: IsChainState tx | |
=> InitialState tx | |
-> ChainStateType tx | New chain state |
-> Outcome tx |
Observe a collectCom transaction. We initialize the OpenState
using the
head parameters from IdleState
and construct an InitialSnapshot
holding
u0
from the committed UTxOs.
Transition: InitialState
→ OpenState
Arguments
:: tx | The transaction to be submitted to the head. |
-> Outcome tx |
Arguments
:: IsTx tx | |
=> Environment | |
-> Ledger tx | |
-> OpenState tx | |
-> TTL | |
-> tx | The transaction to be submitted to the head. |
-> Outcome tx |
Process a transaction request (ReqTx
) from a party.
We apply this transaction to the seen utxo (ledger state). If not applicable,
we wait and retry later. If it applies, this yields an updated seen ledger
state. Then, we check whether we are the leader for the next snapshot and
emit a snapshot request ReqSn
including this transaction if needed.
Arguments
:: IsTx tx | |
=> Environment | |
-> Ledger tx | |
-> OpenState tx | |
-> Party | Party which sent the ReqSn. |
-> SnapshotNumber | Requested snapshot number. |
-> [TxIdType tx] | List of transactions to snapshot. |
-> Outcome tx |
Process a snapshot request (ReqSn
) from party.
This checks that s is the next snapshot number and that the party is
responsible for leading that snapshot. Then, we potentially wait until the
previous snapshot is confirmed (no snapshot is in flight), before we apply
(or wait until applicable) the requested transactions to the last confirmed
snapshot. Only then, we start tracking this new "seen" snapshot, compute a
signature of it and send the corresponding AckSn
to all parties. Finally,
the pending transaction set gets pruned to only contain still applicable
transactions.
Arguments
:: IsTx tx | |
=> Environment | |
-> OpenState tx | |
-> Party | Party which sent the AckSn. |
-> Signature (Snapshot tx) | Signature from other party. |
-> SnapshotNumber | Snapshot number of this AckSn. |
-> Outcome tx |
Process a snapshot acknowledgement (AckSn
) from a party.
We do require that the is from the last seen or next expected snapshot, and
potentially wait wait for the corresponding ReqSn
before proceeding. If the
party hasn't sent us a signature yet, we store it. Once a signature from each
party has been collected, we aggregate a multi-signature and verify it is
correct. If everything is fine, the snapshot can be considered as the latest
confirmed one. Similar to processing a ReqTx
, we check whether we are
leading the next snapshot and craft a corresponding ReqSn
if needed.
onOpenClientClose :: OpenState tx -> Outcome tx Source #
Arguments
:: OpenState tx | |
-> ChainStateType tx | New chain state. |
-> SnapshotNumber | Closed snapshot number. |
-> UTCTime | Contestation deadline. |
-> Outcome tx |
Observe a close transaction. If the closed snapshot number is smaller than our last confirmed, we post a contest transaction. Also, we do schedule a notification for clients to fanout at the deadline.
Transition: OpenState
→ ClosedState
onClosedChainContestTx :: ClosedState tx -> SnapshotNumber -> Outcome tx Source #
Observe a contest transaction. If the contested snapshot number is smaller than our last confirmed snapshot, we post a contest transaction.
Transition: ClosedState
→ ClosedState
onClosedClientFanout :: ClosedState tx -> Outcome tx Source #
Client request to fanout leads to a fanout transaction on chain using the
latest confirmed snapshot from ClosedState
.
Transition: ClosedState
→ ClosedState
onClosedChainFanoutTx Source #
Arguments
:: ClosedState tx | |
-> ChainStateType tx | New chain state |
-> Outcome tx |
Observe a fanout transaction by finalize the head state and notifying clients about it.
Transition: ClosedState
→ IdleState
Arguments
:: IsChainState tx | |
=> Environment | |
-> Ledger tx | |
-> HeadState tx | Current HeadState to validate the command against. |
-> Event tx | Command sent to the HeadLogic to be processed. |
-> Outcome tx |
Handles commands and converts them into internal StateChanged
events
along with Effect
s, in case it is processed succesfully.
Later, the Node will aggregate
the events, resulting in a new HeadState
.
aggregate :: IsChainState tx => HeadState tx -> StateChanged tx -> HeadState tx Source #
Reflect StateChanged
events onto the HeadState
aggregate.
aggregateState :: IsChainState tx => HeadState tx -> Outcome tx -> HeadState tx Source #
recoverState :: (Foldable t, IsChainState tx) => HeadState tx -> t (StateChanged tx) -> HeadState tx Source #
The different events which are processed by the head logic (the "core"). Corresponding to each of the "shell" layers, we distinguish between events from the client, the network and the chain.
Constructors
ClientEvent | Event received from clients via the Hydra.API. |
Fields
| |
NetworkEvent | Event received from peers via a Hydra.Network.
|
OnChainEvent | Event received from the chain via a Hydra.Chain. |
Fields
| |
PostTxError | Event to re-ingest errors from |
Fields
|
Instances
data RequirementFailure tx Source #
Constructors
ReqSnNumberInvalid | |
Fields | |
ReqSnNotLeader | |
Fields
| |
InvalidMultisignature | |
Fields
| |
SnapshotAlreadySigned | |
Fields
| |
AckSnNumberInvalid | |
Fields | |
SnapshotDoesNotApply | |
Fields
|
Instances
data LogicError tx Source #
Preliminary type for collecting errors occurring during update
.
TODO: Try to merge this (back) into Outcome
.
Constructors
InvalidEvent (Event tx) (HeadState tx) | |
RequireFailed (RequirementFailure tx) | |
NotOurHead | |
Fields
|
Instances
data ClosedState tx Source #
An Closed
head with an current candidate ConfirmedSnapshot
, which may
be contested before the $sel:contestationDeadline:ClosedState
.
Constructors
ClosedState | |
Fields
|
Instances
data SeenSnapshot tx Source #
Data structure to help in tracking whether we have seen or requested a ReqSn already and if seen, the signatures we collected already.
Constructors
NoSeenSnapshot | Never saw a ReqSn. |
LastSeenSnapshot | No snapshot in flight with last seen snapshot number as given. |
Fields | |
RequestedSnapshot | ReqSn was sent out and it should be considered already in flight. |
Fields | |
SeenSnapshot | ReqSn for given snapshot was received. |
Instances
data CoordinatedHeadState tx Source #
Off-chain state of the Coordinated Head protocol.
Constructors
CoordinatedHeadState | |
Fields
|
Instances
An Open
head with a CoordinatedHeadState
tracking off-chain
transactions.
Constructors
OpenState | |
Fields
|
Instances
type PendingCommits = Set Party Source #
data InitialState tx Source #
An Initial
head which already has an identity and is collecting commits.
Constructors
InitialState | |
Fields
|
Instances
An Idle
head only having a chain state with things seen on chain so far.
Constructors
IdleState | |
Fields
|
Instances
Arbitrary (ChainStateType tx) => Arbitrary (IdleState tx) Source # | |
FromJSON (ChainStateType tx) => FromJSON (IdleState tx) Source # | |
Defined in Hydra.HeadLogic.State | |
ToJSON (ChainStateType tx) => ToJSON (IdleState tx) Source # | |
Defined in Hydra.HeadLogic.State Methods toJSON :: IdleState tx -> Value toEncoding :: IdleState tx -> Encoding toJSONList :: [IdleState tx] -> Value toEncodingList :: [IdleState tx] -> Encoding | |
Generic (IdleState tx) Source # | |
Show (ChainStateType tx) => Show (IdleState tx) Source # | |
Eq (ChainStateType tx) => Eq (IdleState tx) Source # | |
type Rep (IdleState tx) Source # | |
Defined in Hydra.HeadLogic.State type Rep (IdleState tx) = D1 ('MetaData "IdleState" "Hydra.HeadLogic.State" "hydra-node-0.13.0-HKlbaPrFKjs2dhEMwn7ono" 'True) (C1 ('MetaCons "IdleState" 'PrefixI 'True) (S1 ('MetaSel ('Just "chainState") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 (ChainStateType tx)))) |
The main state of the Hydra protocol state machine. It holds both, the
overall protocol state, but also the off-chain CoordinatedHeadState
.
Each of the sub-types (InitialState, OpenState, etc.) contain black-box
IdleState
corresponding to OnChainEvent
that has been observed leading
to the state.
Note that rollbacks are currently not fully handled in the head logic and only this internal chain state gets replaced with the "rolled back to" version.
Constructors
Idle (IdleState tx) | |
Initial (InitialState tx) | |
Open (OpenState tx) | |
Closed (ClosedState tx) |
Instances
data Environment Source #
Constructors
Environment | |
Fields
|
Instances
Arbitrary Environment Source # | |
Defined in Hydra.HeadLogic.State | |
Show Environment Source # | |
Defined in Hydra.HeadLogic.State |
getChainState :: HeadState tx -> ChainStateType tx Source #
Get the chain state in any HeadState
.
setChainState :: ChainStateType tx -> HeadState tx -> HeadState tx Source #
Update the chain state in any HeadState
.
seenSnapshotNumber :: SeenSnapshot tx -> SnapshotNumber Source #
Get the last seen snapshot number given a SeenSnapshot
.
data WaitReason tx Source #
Constructors
WaitOnNotApplicableTx | |
Fields | |
WaitOnSnapshotNumber | |
Fields | |
WaitOnSeenSnapshot | |
WaitOnTxs | |
Fields
| |
WaitOnContestationDeadline |
Instances
Constructors
Effects | |
StateChanged (StateChanged tx) | |
Wait | |
Fields
| |
Error | |
Fields
| |
Combined | |
Instances
data StateChanged tx Source #
Head state changed event. These events represent all the internal state changes, get persisted and processed in an event sourcing manner.
Constructors
Instances
Analogous to events, the pure head logic "core" can have effects emited to the "shell" layers and we distinguish the same: effects onto the client, the network and the chain.
Constructors
ClientEffect | Effect to be handled by the Hydra.API, results in sending this |
Fields
| |
NetworkEffect | Effect to be handled by a Hydra.Network, results in a |
OnChainEffect | Effect to be handled by a Hydra.Chain, results in a |
Fields
|
Instances
collectEffects :: Outcome tx -> [Effect tx] Source #
collectWaits :: Outcome tx -> [WaitReason tx] Source #
isLeader :: HeadParameters -> Party -> SnapshotNumber -> Bool Source #