| Safe Haskell | Safe-Inferred |
|---|---|
| Language | GHC2021 |
Hydra.HeadLogic
Description
Implements the Head Protocol's state machine as pure functions in an event sourced manner.
More specifically, the update will handle Inputs (or rather "commands" in
event sourcing speak) and convert that into a list of side-Effects and
StateChanged events, which in turn are applied via aggregateNodeState into
a single NodeState.
As the specification is using a more imperative way of specifying the protocol
behavior, one would find the decision logic in update while state updates
can be found in the corresponding applyEvent branch.
Synopsis
- data OnChainFanoutDatum
- update :: IsChainState tx => Environment -> Ledger tx -> UTCTime -> NodeState tx -> Input tx -> Outcome tx
- aggregateNodeState :: IsChainState tx => NodeState tx -> StateChanged tx -> NodeState tx
- maxTxsPerSnapshot :: Int
- aggregateChainStateHistory :: IsChainState tx => ChainStateHistory tx -> StateChanged tx -> ChainStateHistory tx
- aggregateState :: IsChainState tx => NodeState tx -> Outcome tx -> NodeState tx
- isLeader :: HeadParameters -> Party -> SnapshotNumber -> Bool
- onIdleClientInit :: Environment -> Outcome tx
- onIdleChainInitTx :: Environment -> ChainStateType tx -> HeadId -> HeadSeed -> HeadParameters -> [OnChainId] -> Outcome tx
- onOpenClientNewTx :: tx -> Outcome tx
- onOpenNetworkReqTx :: IsTx tx => Environment -> Ledger tx -> ChainSlot -> OpenState tx -> TTL -> PendingDeposits tx -> tx -> Outcome tx
- selectNextIncrementalAction :: IsTx tx => PendingDeposits tx -> Maybe (TxIdType tx) -> Maybe tx -> Maybe (UTxOType tx) -> (Maybe tx, Maybe (TxIdType tx))
- onOpenNetworkReqSn :: IsTx tx => Environment -> Ledger tx -> PendingDeposits tx -> ChainSlot -> OpenState tx -> Party -> SnapshotVersion -> SnapshotNumber -> [TxIdType tx] -> Maybe tx -> Maybe (TxIdType tx) -> Outcome tx
- onOpenNetworkAckSn :: IsTx tx => Environment -> PendingDeposits tx -> OpenState tx -> Party -> Signature (Snapshot tx) -> SnapshotNumber -> Outcome tx
- onClientRecover :: IsTx tx => ChainSlot -> PendingDeposits tx -> TxIdType tx -> Outcome tx
- onOpenClientDecommit :: IsTx tx => HeadId -> Ledger tx -> ChainSlot -> CoordinatedHeadState tx -> tx -> Outcome tx
- requireDecommitOutputs :: IsTx tx => HeadId -> UTxOType tx -> tx -> Outcome tx -> Outcome tx
- onOpenNetworkReqDec :: IsTx tx => Environment -> Ledger tx -> TTL -> ChainSlot -> PendingDeposits tx -> OpenState tx -> tx -> Outcome tx
- existingDeposit :: IsTx tx => PendingDeposits tx -> Maybe (TxIdType tx) -> Maybe (TxIdType tx, Deposit tx)
- determineNextDepositStatus :: Ord (TxIdType tx) => Environment -> PendingDeposits tx -> UTCTime -> PendingDeposits tx
- onChainTick :: IsTx tx => Environment -> PendingDeposits tx -> UTCTime -> Outcome tx
- onOpenChainTick :: IsTx tx => Environment -> UTCTime -> PendingDeposits tx -> OpenState tx -> Outcome tx
- maybeRequestSnapshotAfterVersionBump :: IsTx tx => HeadParameters -> Party -> SnapshotNumber -> Seq tx -> SnapshotVersion -> SnapshotVersion -> SeenSnapshot tx -> Maybe (TxIdType tx) -> Outcome tx
- onOpenChainIncrementTx :: IsTx tx => Environment -> OpenState tx -> ChainStateType tx -> SnapshotVersion -> TxIdType tx -> Outcome tx
- onOpenChainDecrementTx :: IsTx tx => Environment -> PendingDeposits tx -> OpenState tx -> ChainStateType tx -> SnapshotVersion -> UTxOType tx -> Outcome tx
- setExistingDeposit :: IsTx tx => PendingDeposits tx -> Maybe (TxIdType tx) -> Maybe (TxIdType tx)
- maybeRepostIncrementTx :: IsTx tx => HeadSeed -> HeadId -> HeadParameters -> PendingDeposits tx -> ConfirmedSnapshot tx -> Outcome tx
- maybeRepostDecrementTx :: HeadSeed -> HeadId -> HeadParameters -> Maybe tx -> ConfirmedSnapshot tx -> Outcome tx
- onOpenClientClose :: OpenState tx -> Outcome tx
- onOpenChainCloseTx :: IsTx tx => OpenState tx -> ChainStateType tx -> SnapshotNumber -> UTCTime -> Outcome tx
- onOpenClientSideLoadSnapshot :: IsTx tx => OpenState tx -> ConfirmedSnapshot tx -> Outcome tx
- onClosedChainContestTx :: IsTx tx => ClosedState tx -> ChainStateType tx -> SnapshotNumber -> UTCTime -> Outcome tx
- onClosedClientFanout :: IsTx tx => ClosedState tx -> Outcome tx
- computeFullFanoutUTxO :: IsTx tx => ClosedState tx -> UTxOType tx
- mkFullFanoutTx :: IsTx tx => ConfirmedSnapshot tx -> SnapshotVersion -> HeadSeed -> UTCTime -> PostChainTx tx
- effectiveCommitDecommit :: SnapshotVersion -> SnapshotVersion -> Maybe (UTxOType tx) -> Maybe (UTxOType tx) -> (Maybe (UTxOType tx), Maybe (UTxOType tx))
- onClosedClientPartialFanout :: IsTx tx => ClosedState tx -> UTxOType tx -> Outcome tx
- nullOutputs :: IsTx tx => UTxOType tx -> Bool
- isSubMultisetOf :: IsTx tx => UTxOType tx -> UTxOType tx -> Bool
- sameOutputs :: IsTx tx => UTxOType tx -> UTxOType tx -> Bool
- emitPartialFanoutStep :: IsTx tx => UTxOType tx -> UTxOType tx -> OnChainFanoutDatum -> ConfirmedSnapshot tx -> SnapshotVersion -> HeadSeed -> UTCTime -> Outcome tx
- onPartialFanoutClientPartialFanout :: IsTx tx => PartialFanoutState tx -> UTxOType tx -> Outcome tx
- onChainFanoutDatum :: IsTx tx => UTxOType tx -> OnChainFanoutDatum
- onClosedChainFanoutTx :: ClosedState tx -> ChainStateType tx -> UTxOType tx -> Outcome tx
- onClosedChainPartialFanoutTx :: IsTx tx => ClosedState tx -> ChainStateType tx -> UTxOType tx -> Outcome tx
- removeDistributedOutputs :: IsTx tx => [TxOutType tx] -> UTxOType tx -> UTxOType tx
- onPartialFanoutChainPartialFanoutTx :: IsTx tx => PartialFanoutState tx -> ChainStateType tx -> UTxOType tx -> Outcome tx
- onPartialFanoutChainFanoutTx :: IsTx tx => PartialFanoutState tx -> ChainStateType tx -> UTxOType tx -> Outcome tx
- fanoutUTxOFromSnapshot :: IsTx tx => ConfirmedSnapshot tx -> SnapshotVersion -> UTxOType tx
- closedToFanoutProgress :: ClosedState tx -> ChainStateType tx -> UTxOType tx -> UTxOType tx -> FanoutMode tx -> HeadState tx
- fanoutProgressToClosed :: PartialFanoutState tx -> ClosedState tx
- isFanoutPostChainTx :: PostChainTx tx -> Bool
- repostFanoutStep :: IsTx tx => PartialFanoutState tx -> Outcome tx
- handleOutOfSync :: IsChainState tx => Environment -> UTCTime -> ChainPointType tx -> UTCTime -> SyncedStatus -> Outcome tx
- nextActiveDepositId :: IsTx tx => PendingDeposits tx -> Maybe (TxIdType tx)
- selectNextDeposit :: IsTx tx => PendingDeposits tx -> Maybe (TxIdType tx) -> Maybe tx -> Maybe (UTxOType tx) -> Maybe (TxIdType tx)
- updateCatchingUpHead :: IsChainState tx => Environment -> Ledger tx -> UTCTime -> ChainPointTime -> PendingDeposits tx -> HeadState tx -> Input tx -> SyncedStatus -> Outcome tx
- updateInSyncHead :: IsChainState tx => Environment -> Ledger tx -> UTCTime -> ChainPointTime -> PendingDeposits tx -> HeadState tx -> Input tx -> SyncedStatus -> Outcome tx
- handleChainInput :: IsChainState tx => Environment -> Ledger tx -> UTCTime -> ChainPointTime -> PendingDeposits tx -> HeadState tx -> Input tx -> SyncedStatus -> Outcome tx
- handleClientInput :: IsChainState tx => Environment -> Ledger tx -> ChainPointTime -> PendingDeposits tx -> HeadState tx -> Input tx -> Outcome tx
- handleNetworkInput :: IsChainState tx => Environment -> Ledger tx -> ChainPointTime -> PendingDeposits tx -> HeadState tx -> Input tx -> Outcome tx
- onConnectionEvent :: Text -> Connectivity -> Outcome tx
- headIdOf :: HeadState tx -> Maybe HeadId
- eventHeadId :: StateChanged tx -> Maybe HeadId
- applyEvent :: IsChainState tx => HeadState tx -> StateChanged tx -> HeadState tx
- data Input tx
- = ClientInput {
- clientInput :: ClientInput tx
- | NetworkInput {
- ttl :: TTL
- networkEvent :: NetworkEvent (Message tx)
- | ChainInput {
- chainEvent :: ChainEvent tx
- = ClientInput {
- type TTL = Natural
- data SideLoadRequirementFailure tx
- = SideLoadInitialSnapshotMismatch
- | SideLoadSnNumberInvalid {
- requestedSn :: SnapshotNumber
- lastSeenSn :: SnapshotNumber
- | SideLoadSvNumberInvalid {
- requestedSv :: SnapshotVersion
- lastSeenSv :: SnapshotVersion
- | SideLoadUTxOToCommitInvalid {
- requestedSc :: Maybe (UTxOType tx)
- lastSeenSc :: Maybe (UTxOType tx)
- | SideLoadDepositTxIdInvalid {
- requestedDeposit :: Maybe (TxIdType tx)
- lastSeenDeposit :: Maybe (TxIdType tx)
- | SideLoadUTxOToDecommitInvalid {
- requestedSd :: Maybe (UTxOType tx)
- lastSeenSd :: Maybe (UTxOType tx)
- | SideLoadInvalidMultisignature { }
- data LogicError tx
- = UnhandledInput {
- input :: Input tx
- currentHeadState :: HeadState tx
- | RequireFailed { }
- | AssertionFailed {
- message :: Text
- | NotOurHead {
- ourHeadId :: HeadId
- otherHeadId :: HeadId
- | SideLoadSnapshotFailed { }
- = UnhandledInput {
- data RequirementFailure tx
- = ReqSnNumberInvalid {
- requestedSn :: SnapshotNumber
- lastSeenSn :: SnapshotNumber
- | ReqSvNumberInvalid {
- requestedSv :: SnapshotVersion
- lastSeenSv :: SnapshotVersion
- | ReqSnNotLeader {
- requestedSn :: SnapshotNumber
- leader :: Party
- | ReqSnDecommitNotSettled
- | ReqSnCommitNotSettled
- | ReqSnBothCommitAndDecommit {
- depositTxId :: TxIdType tx
- decommitTxId :: TxIdType tx
- | ReqSnDecommitNoOutputs {
- decommitTxId :: TxIdType tx
- | InvalidMultisignature { }
- | SnapshotAlreadySigned {
- knownSignatures :: [Party]
- receivedSignature :: Party
- | AckSnNumberInvalid {
- requestedSn :: SnapshotNumber
- lastSeenSn :: SnapshotNumber
- | SnapshotDoesNotApply {
- requestedSn :: SnapshotNumber
- txid :: TxIdType tx
- error :: ValidationError
- | NoMatchingDeposit
- | RequestedDepositExpired {
- depositTxId :: TxIdType tx
- | RequestedDepositNotFoundLocally {
- depositTxId :: TxIdType tx
- | ReqSnUTxOSetTooLarge {
- utxoCount :: Int
- maxAllowed :: Int
- = ReqSnNumberInvalid {
- data CoordinatedHeadState tx = CoordinatedHeadState {
- localUTxO :: UTxOType tx
- localTxs :: Seq tx
- allTxs :: !(Map (TxIdType tx) tx)
- confirmedSnapshot :: ConfirmedSnapshot tx
- seenSnapshot :: SeenSnapshot tx
- currentDepositTxId :: Maybe (TxIdType tx)
- decommitTx :: Maybe tx
- version :: SnapshotVersion
- data HeadState tx
- = Idle (IdleState tx)
- | Open (OpenState tx)
- | Closed (ClosedState tx)
- | FanoutProgress (PartialFanoutState tx)
- data OpenState tx = OpenState {
- parameters :: HeadParameters
- coordinatedHeadState :: CoordinatedHeadState tx
- chainState :: ChainStateType tx
- headId :: HeadId
- headSeed :: HeadSeed
- data SeenSnapshot tx
- = NoSeenSnapshot
- | LastSeenSnapshot {
- lastSeen :: SnapshotNumber
- | RequestedSnapshot { }
- | SeenSnapshot {
- snapshot :: Snapshot tx
- signatories :: Map Party (Signature (Snapshot tx))
- signableBytes :: ~ByteString
- data ClosedState tx = ClosedState {
- parameters :: HeadParameters
- confirmedSnapshot :: ConfirmedSnapshot tx
- contestationDeadline :: UTCTime
- readyToFanoutSent :: Bool
- chainState :: ChainStateType tx
- headId :: HeadId
- headSeed :: HeadSeed
- version :: SnapshotVersion
- data FanoutMode tx
- = AutoDrain
- | DistributingSelection (UTxOType tx)
- | AwaitingSelection
- data PartialFanoutState tx = PartialFanoutState {
- parameters :: HeadParameters
- confirmedSnapshot :: ConfirmedSnapshot tx
- contestationDeadline :: UTCTime
- chainState :: ChainStateType tx
- headId :: HeadId
- headSeed :: HeadSeed
- version :: SnapshotVersion
- remainingOutputs :: UTxOType tx
- distributedOutputs :: UTxOType tx
- mode :: FanoutMode tx
- newtype IdleState tx = IdleState {
- chainState :: ChainStateType tx
- getChainState :: HeadState tx -> ChainStateType tx
- isCollectingAcks :: SeenSnapshot tx -> Bool
- mkSeenSnapshot :: IsTx tx => Snapshot tx -> Map Party (Signature (Snapshot tx)) -> SeenSnapshot tx
- seenSnapshotNumber :: SeenSnapshot tx -> SnapshotNumber
- setChainState :: ChainStateType tx -> HeadState tx -> HeadState tx
- snapshotInFlight :: SeenSnapshot tx -> Bool
- data Effect tx
- = ClientEffect {
- clientMessage :: ClientMessage tx
- | NetworkEffect { }
- | OnChainEffect {
- postChainTx :: PostChainTx tx
- = ClientEffect {
- data Outcome tx
- = Continue {
- stateChanges :: [StateChanged tx]
- effects :: [Effect tx]
- | Wait {
- reason :: WaitReason tx
- stateChanges :: [StateChanged tx]
- | Error {
- error :: LogicError tx
- = Continue {
- data StateChanged tx
- = NetworkConnected
- | NetworkDisconnected
- | PeerConnected { }
- | PeerDisconnected { }
- | NetworkVersionMismatch { }
- | NetworkClusterIDMismatch {
- clusterPeers :: Text
- misconfiguredPeers :: Text
- | HeadOpened {
- parameters :: HeadParameters
- chainState :: ChainStateType tx
- headId :: HeadId
- headSeed :: HeadSeed
- parties :: [Party]
- | TransactionReceived {
- tx :: tx
- | TransactionAppliedToLocalUTxO { }
- | SnapshotRequestDecided {
- snapshotNumber :: SnapshotNumber
- | SnapshotRequested {
- requestedSnapshot :: Snapshot tx
- newLocalTxs :: Seq tx
- newCurrentDepositTxId :: Maybe (TxIdType tx)
- | PartySignedSnapshot {
- snapshotNumber :: SnapshotNumber
- party :: Party
- signature :: Signature (Snapshot tx)
- | SnapshotConfirmed {
- headId :: HeadId
- snapshot :: Maybe (Snapshot tx)
- signatures :: MultiSignature (Snapshot tx)
- | DepositRecorded {
- chainState :: ChainStateType tx
- headId :: HeadId
- depositTxId :: TxIdType tx
- deposited :: UTxOType tx
- created :: UTCTime
- deadline :: UTCTime
- | DepositActivated {
- depositTxId :: TxIdType tx
- chainTime :: UTCTime
- deposit :: Deposit tx
- | DepositExpired {
- depositTxId :: TxIdType tx
- chainTime :: UTCTime
- deposit :: Deposit tx
- | DepositRecovered {
- chainState :: ChainStateType tx
- headId :: HeadId
- depositTxId :: TxIdType tx
- recovered :: UTxOType tx
- | CommitApproved {
- headId :: HeadId
- utxoToCommit :: UTxOType tx
- | CommitFinalized {
- chainState :: ChainStateType tx
- headId :: HeadId
- newVersion :: SnapshotVersion
- depositTxId :: TxIdType tx
- | DecommitRecorded {
- headId :: HeadId
- decommitTx :: tx
- | DecommitApproved {
- headId :: HeadId
- decommitTxId :: TxIdType tx
- utxoToDecommit :: UTxOType tx
- | DecommitInvalid {
- headId :: HeadId
- decommitTx :: tx
- decommitInvalidReason :: DecommitInvalidReason tx
- | DecommitFinalized {
- chainState :: ChainStateType tx
- headId :: HeadId
- distributedUTxO :: UTxOType tx
- newVersion :: SnapshotVersion
- | HeadClosed {
- headId :: HeadId
- snapshotNumber :: SnapshotNumber
- chainState :: ChainStateType tx
- contestationDeadline :: UTCTime
- | HeadContested {
- headId :: HeadId
- chainState :: ChainStateType tx
- contestationDeadline :: UTCTime
- snapshotNumber :: SnapshotNumber
- | HeadIsReadyToFanout {
- headId :: HeadId
- | HeadFanoutInitiated {
- headId :: HeadId
- remainingOutputs :: UTxOType tx
- | HeadPartialFanoutSelected {
- headId :: HeadId
- remainingOutputs :: UTxOType tx
- selection :: UTxOType tx
- | HeadFanoutReverted {
- headId :: HeadId
- | HeadFannedOut {
- headId :: HeadId
- finalizedOutputs :: UTxOType tx
- chainState :: ChainStateType tx
- | HeadPartialFannedOut {
- headId :: HeadId
- distributedOutputs :: UTxOType tx
- remainingOutputs :: UTxOType tx
- chainState :: ChainStateType tx
- mode :: FanoutMode tx
- | ChainRolledBack {
- chainState :: ChainStateType tx
- | TickObserved {
- chainPoint :: ChainPointType tx
- chainTime :: UTCTime
- | IgnoredHeadInitializing {
- headId :: HeadId
- contestationPeriod :: ContestationPeriod
- parties :: [Party]
- participants :: [OnChainId]
- | TxInvalid {
- headId :: HeadId
- utxo :: UTxOType tx
- transaction :: tx
- validationError :: ValidationError
- | LocalStateCleared {
- headId :: HeadId
- snapshotNumber :: SnapshotNumber
- | Checkpoint { }
- | NodeUnsynced {
- chainSlot :: ChainSlot
- chainTime :: UTCTime
- drift :: NominalDiffTime
- | NodeSynced {
- chainSlot :: ChainSlot
- chainTime :: UTCTime
- drift :: NominalDiffTime
- data WaitReason tx
- = WaitOnNotApplicableTx { }
- | WaitOnSnapshotNumber {
- waitingForNumber :: SnapshotNumber
- | WaitOnSnapshotVersion {
- waitingForVersion :: SnapshotVersion
- | WaitOnSeenSnapshot
- | WaitOnTxs {
- waitingForTxIds :: [TxIdType tx]
- | WaitOnContestationDeadline
- | WaitOnNotApplicableDecommitTx { }
- | WaitOnUnresolvedCommit {
- commitUTxO :: UTxOType tx
- | WaitOnUnresolvedDecommit {
- decommitTx :: tx
- | WaitOnDepositObserved {
- depositTxId :: TxIdType tx
- | WaitOnDepositActivation {
- depositTxId :: TxIdType tx
- | WaitOnNodeInSync {
- currentSlot :: ChainSlot
- cause :: Effect tx -> Outcome tx
- causes :: [Effect tx] -> Outcome tx
- changes :: [StateChanged tx] -> Outcome tx
- newState :: StateChanged tx -> Outcome tx
- noop :: Outcome tx
- wait :: WaitReason tx -> Outcome tx
Documentation
data OnChainFanoutDatum Source #
Which on-chain head datum the next fanout step will be posted against:
still Closed (no partial fanout has landed yet) or already FanoutProgress.
A FinalPartialFanoutTx (which burns the head tokens) is only valid once the
datum is DatumFanoutProgress.
Constructors
| DatumClosed | |
| DatumFanoutProgress |
Instances
| Eq OnChainFanoutDatum Source # | |
Defined in Hydra.HeadLogic Methods (==) :: OnChainFanoutDatum -> OnChainFanoutDatum -> Bool Source # (/=) :: OnChainFanoutDatum -> OnChainFanoutDatum -> Bool Source # | |
Arguments
| :: IsChainState tx | |
| => Environment | |
| -> Ledger tx | |
| -> UTCTime | Current system time. |
| -> NodeState tx | Current NodeState to validate the command against. |
| -> Input tx | Input to be processed. |
| -> Outcome tx |
Handles inputs and converts them into StateChanged events along with
Effects, in case it is processed successfully. Later, the Node will
apply the events via aggregateNodeState, resulting in a new NodeState.
aggregateNodeState :: IsChainState tx => NodeState tx -> StateChanged tx -> NodeState tx Source #
Reflect StateChanged events onto the NodeState aggregateNodeState.
Events carrying a HeadId that does not match the current state are silently
ignored, preventing cross-head state contamination during event replay.
Events without a HeadId are always applied.
maxTxsPerSnapshot :: Int Source #
Maximum number of transaction ids per snapshot. This effectively limits our "block size" and ensures it does not grow arbitrarily with the backlog of pending transactions (localTxs). Only applied when requesting snapshots as a leader; followers accept larger requests, so this can change without a coordinated upgrade.
1000 was chosen from a sweep against 100/250 on sustained-load benchmarks (see hydra-clusterbenchBASELINES.md): per-round costs that scale with the backlog dominate at small caps (4.6-5.7x lower throughput at 100 with a deep backlog), while peak node memory was flat across the sweep.
aggregateChainStateHistory :: IsChainState tx => ChainStateHistory tx -> StateChanged tx -> ChainStateHistory tx Source #
onIdleClientInit :: Environment -> Outcome tx Source #
Arguments
| :: Environment | |
| -> ChainStateType tx | New chain state. |
| -> HeadId | |
| -> HeadSeed | |
| -> HeadParameters | |
| -> [OnChainId] | |
| -> Outcome tx |
Arguments
| :: tx | The transaction to be submitted to the head. |
| -> Outcome tx |
Arguments
| :: IsTx tx | |
| => Environment | |
| -> Ledger tx | |
| -> ChainSlot | |
| -> OpenState tx | |
| -> TTL | |
| -> PendingDeposits tx | |
| -> 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.
selectNextIncrementalAction Source #
Arguments
| :: IsTx tx | |
| => PendingDeposits tx | |
| -> Maybe (TxIdType tx) | |
| -> Maybe tx | Pending decommit tx |
| -> Maybe (UTxOType tx) | utxoToCommit of the last relevant confirmed snapshot |
| -> (Maybe tx, Maybe (TxIdType tx)) |
The incremental action to put in the next ReqSn: a commit or a decommit,
never both. A snapshot carrying both cannot be closed, since close and fanout
express a single incremental action (setIncrementalActionMaybe).
A commit wins: its deposit expires on-chain, while a decommit only waits. This
cannot starve the decommit, because selectNextDeposit refuses to start a
*new* commit while a decommit is pending — only one already in flight can win,
and that one stops being selected once it settles and leaves $sel:pendingDeposits:NodeInSync.
Arguments
| :: IsTx tx | |
| => Environment | |
| -> Ledger tx | |
| -> PendingDeposits tx | |
| -> ChainSlot | |
| -> OpenState tx | |
| -> Party | Party which sent the ReqSn. |
| -> SnapshotVersion | Requested snapshot version. |
| -> SnapshotNumber | Requested snapshot number. |
| -> [TxIdType tx] | List of transactions to snapshot. |
| -> Maybe tx | Optional decommit transaction of removing funds from the head. |
| -> Maybe (TxIdType tx) | Optional commit of additional funds into the head. |
| -> 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 | |
| -> PendingDeposits tx | |
| -> 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.
onClientRecover :: IsTx tx => ChainSlot -> PendingDeposits tx -> TxIdType tx -> Outcome tx Source #
Client request to recover deposited UTxO.
Transition: OpenState → OpenState
Client request to recover a deposit by posting a recover transaction on-chain.
Works in any head state (Open, Closed, or Idle after fanout). Deposits from a
previous head are never cleared from $sel:pendingDeposits:NodeInSync on fanout, so recovery
remains available after a head closes. A new head only sees its own deposits via
depositsForHead, so old deposits are never accidentally ingested into L2.
On-chain, the deposit validator only enforces that the deadline has passed and
that the recovered outputs match the originals — it does not require the head to
still be active.
Arguments
| :: IsTx tx | |
| => HeadId | |
| -> Ledger tx | |
| -> ChainSlot | |
| -> CoordinatedHeadState tx | |
| -> tx | Decommit transaction. |
| -> Outcome tx |
requireDecommitOutputs :: IsTx tx => HeadId -> UTxOType tx -> tx -> Outcome tx -> Outcome tx Source #
Reject a decommit that materializes no output.
checkDecrement requires at least one, so such a decommit
can never settle on-chain, and recording it would block every later snapshot
(which cannot carry a different one).
Belongs after the applicability check at every call site: a transaction that does not apply is reported with the ledger's own, more precise reason.
onOpenNetworkReqDec :: IsTx tx => Environment -> Ledger tx -> TTL -> ChainSlot -> PendingDeposits tx -> OpenState tx -> tx -> Outcome tx Source #
Process the request ReqDec to decommit something from the Open head.
Transition: OpenState → OpenState
When node receives ReqDec network message it should:
- Check there is no decommit in flight:
- Alter it's state to record what is to be decommitted
- Issue a server output DecommitRequested with the relevant utxo
- Issue a ReqSn since all parties need to agree in order for decommit to
be taken out of a Head.
- Check if we are the leader
existingDeposit :: IsTx tx => PendingDeposits tx -> Maybe (TxIdType tx) -> Maybe (TxIdType tx, Deposit tx) Source #
The pending deposit that a local $sel:currentDepositTxId:CoordinatedHeadState still refers to, if any: the deposit must
be registered in $sel:pendingDeposits:NodeInSync and not Expired.
Being registered and unexpired is what makes a recorded deposit id something the head may still
act on, and nothing else should be treated as a commit in flight. Neither of the two ways a
deposit stops being pending clears $sel:currentDepositTxId:CoordinatedHeadState: DepositExpired deliberately keeps the
deposit in the map so it can still be recovered, and DepositRecovered only deletes the map
entry. So a caller that reads $sel:currentDepositTxId:CoordinatedHeadState on its own can end up waiting on a deposit
that is unclaimable, or already gone, and that wait never resolves.
determineNextDepositStatus :: Ord (TxIdType tx) => Environment -> PendingDeposits tx -> UTCTime -> PendingDeposits tx Source #
onChainTick :: IsTx tx => Environment -> PendingDeposits tx -> UTCTime -> Outcome tx Source #
Process the chain (and time) advancing in any head state.
Transition: AnyState → AnyState
This is primarily used to track deposits status changes.
onOpenChainTick :: IsTx tx => Environment -> UTCTime -> PendingDeposits tx -> OpenState tx -> Outcome tx Source #
maybeRequestSnapshotAfterVersionBump :: IsTx tx => HeadParameters -> Party -> SnapshotNumber -> Seq tx -> SnapshotVersion -> SnapshotVersion -> SeenSnapshot tx -> Maybe (TxIdType tx) -> Outcome tx Source #
If this node is the snapshot leader and there are pending local transactions, request the next snapshot with the bumped version after a commit or decommit finalises on-chain.
Guards:
* Only fires when 'version /= newVersion' to avoid duplicate
SnapshotRequestDecided events when multiple parties post the same
on-chain tx and each posting produces a separate finalisation observation.
* Skips when AckSns are already being collected (SeenSnapshot): the
in-flight snapshot will complete and maybeRequestNextSnapshot will chain
the next one with the bumped version. Firing here would use stale
$sel:localTxs:CoordinatedHeadState and cause BadInputsUTxO on other parties.
* Allows RequestedSnapshot: the in-flight ReqSn carries the old version
and will be parked by waitOnSnapshotVersion until TTL drops it, so we
re-request immediately with the new version to make progress without
waiting for the stale request's retries to exhaust.
The optional StateChanged argument is forwarded into ReqSn: commit
finalisation passes Nothing (deposit already included), while decommit
finalisation passes the next queued deposit if one is pending.
onOpenChainIncrementTx Source #
Arguments
| :: IsTx tx | |
| => Environment | |
| -> OpenState tx | |
| -> ChainStateType tx | |
| -> SnapshotVersion | New open state version |
| -> TxIdType tx | Deposit TxId |
| -> Outcome tx |
Observe a increment transaction. If the outputs match the ones of the
pending commit UTxO, then we consider the deposit/increment finalized, and remove the
increment UTxO from $sel:pendingDeposits:NodeInSync from the local state.
Finally, if the client observing happens to be the leader, then a new ReqSn is broadcasted.
onOpenChainDecrementTx Source #
Arguments
| :: IsTx tx | |
| => Environment | |
| -> PendingDeposits tx | |
| -> OpenState tx | |
| -> ChainStateType tx | |
| -> SnapshotVersion | New open state version |
| -> UTxOType tx | Outputs removed by the decrement |
| -> Outcome tx |
setExistingDeposit :: IsTx tx => PendingDeposits tx -> Maybe (TxIdType tx) -> Maybe (TxIdType tx) Source #
Validate whether a current deposit in the local state actually exists in the map of pending deposits.
- If
currentDepositisNothing, returnsNothing. - If
currentDepositisandJusttxIdtxIdis present in$sel:pendingDeposits:NodeInSyncand notExpired, returns the originalcurrentDeposit. - Otherwise, returns
Nothing.
This is typically used to confirm that a local deposit that is to be
requested in ReqSn is indeed still pending and has not been processed or
removed.
Expired deposits are dropped rather than carried: requesting one makes every
receiving party hard-error with RequestedDepositExpired, so a deposit that
somehow became unclaimable would stall snapshots for the whole head instead of
just being abandoned by its depositor.
maybeRepostIncrementTx :: IsTx tx => HeadSeed -> HeadId -> HeadParameters -> PendingDeposits tx -> ConfirmedSnapshot tx -> Outcome tx Source #
On rollback, re-post the IncrementTx if there is a pending deposit whose confirmed snapshot contains a matching utxoToCommit. The rollback may have erased the original on-chain IncrementTx observation.
maybeRepostDecrementTx :: HeadSeed -> HeadId -> HeadParameters -> Maybe tx -> ConfirmedSnapshot tx -> Outcome tx Source #
On rollback, re-post the DecrementTx if there is a pending decommit whose confirmed snapshot contains a matching utxoToDecommit. The rollback may have erased the original on-chain DecrementTx observation.
onOpenClientClose :: OpenState tx -> Outcome tx Source #
Arguments
| :: IsTx tx | |
| => 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
onOpenClientSideLoadSnapshot :: IsTx tx => OpenState tx -> ConfirmedSnapshot tx -> Outcome tx Source #
Client request to side load confirmed snapshot.
Note this is not covered by the spec as it is not reachable from an organic use of the protocol.
It must not have any effects outside of a neutral modification of the state to: * something it was before (in the case of the initial snapshot). * something it would be using side communication (in the case of a confirmed snapshot).
Besides the above, it is expected to work very much like the confirmed snapshot.
onClosedChainContestTx Source #
Arguments
| :: IsTx tx | |
| => ClosedState tx | |
| -> ChainStateType tx | New chain state. |
| -> SnapshotNumber | |
| -> UTCTime | Contestation deadline. |
| -> Outcome tx |
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 :: IsTx tx => ClosedState tx -> Outcome tx Source #
Client request to fanout the whole closed head automatically. Emits a
FanoutTx; the chain layer either lands a single full fanout (→ IdleState)
or falls back to dynamically-chunked partial fanouts. The first observed
partial fanout transitions the head to PartialFanout in AutoDrain mode,
which keeps draining the rest automatically until the final (burning) step.
This node becomes the fanout driver: it transitions into PartialFanout in
AutoDrain mode so that, as the chain layer chunks the fanout, this node
auto-continues to completion. Other parties that merely observe the resulting
partial fanout do not auto-drive (see onClosedChainPartialFanoutTx).
Transition: ClosedState → PartialFanoutState (then → IdleState once
the final fanout is observed).
computeFullFanoutUTxO :: IsTx tx => ClosedState tx -> UTxOType tx Source #
Compute the full UTxO set to be fanned out, combining snapshot utxo with utxoToCommit/utxoToDecommit based on version.
mkFullFanoutTx :: IsTx tx => ConfirmedSnapshot tx -> SnapshotVersion -> HeadSeed -> UTCTime -> PostChainTx tx Source #
Build the full automatic FanoutTx from a confirmed snapshot at the given
on-chain version. Shared by onClosedClientFanout and the rollback re-post in
FanoutProgress (repostFanoutStep).
effectiveCommitDecommit Source #
Arguments
| :: SnapshotVersion | On-chain version |
| -> SnapshotVersion | Snapshot version |
| -> Maybe (UTxOType tx) | Pending commit |
| -> Maybe (UTxOType tx) | Pending decommit |
| -> (Maybe (UTxOType tx), Maybe (UTxOType tx)) |
Given the on-chain version and a snapshot's own version, decide which of a
pending commit / decommit is still to be distributed on fanout. When the
increment has landed on chain (versions match) the commit was already applied
(drop it) while a pending decommit still applies; otherwise the commit still
applies and the decommit was already paid out. Centralises the version check
shared by mkFullFanoutTx and fanoutUTxOFromSnapshot.
onClosedClientPartialFanout :: IsTx tx => ClosedState tx -> UTxOType tx -> Outcome tx Source #
Client request to fan out a user-selected subset of a freshly closed head.
Validates the selection is a non-empty sub-multiset (by content) of the
fan-out-able UTxO, transitions the head into PartialFanout (in
DistributingSelection mode) and emits the first PartialFanoutTx.
Transition: ClosedState → PartialFanoutState
nullOutputs :: IsTx tx => UTxOType tx -> Bool Source #
Whether a UTxO has no outputs.
isSubMultisetOf :: IsTx tx => UTxOType tx -> UTxOType tx -> Bool Source #
Whether the outputs of sub are a sub-multiset (by content) of sup. This
mirrors how partial fanout tracks distributed UTxO by content rather than by
TxIn, so a user-provided selection is validated against what is actually
still in the head.
sameOutputs :: IsTx tx => UTxOType tx -> UTxOType tx -> Bool Source #
Whether two UTxO sets have the same outputs (by content, as a multiset).
The a == b short-circuit avoids the O(n²) multiset comparison in the common
case where both arguments are the same tracked set (e.g. the auto-drain
sameOutputs remaining remaining check on every observed chunk), which is
exactly the large-UTxO heads partial fanout targets.
emitPartialFanoutStep Source #
Arguments
| :: IsTx tx | |
| => UTxOType tx | Chunk source for the next step (the user selection remainder, or the whole remaining set when auto-draining) |
| -> UTxOType tx | The head's full remaining set |
| -> OnChainFanoutDatum | The on-chain datum the step is posted against. |
| -> ConfirmedSnapshot tx | |
| -> SnapshotVersion | |
| -> HeadSeed | |
| -> UTCTime | |
| -> Outcome tx |
Emit the next partial fanout on-chain effect.
- When the chunk source
targetcovers the entire remaining set and the head is already inFanoutProgresson chain, emit the finalFinalPartialFanoutTxthat distributes the rest and burns the head tokens. - Otherwise emit a non-final
PartialFanoutTxdrawing fromtarget. The chain layer sizes the actual on-chain chunk dynamically.
onPartialFanoutClientPartialFanout :: IsTx tx => PartialFanoutState tx -> UTxOType tx -> Outcome tx Source #
Client request to continue a selective partial fanout. Validates the
selection against the current StateChanged, records it as the active
selection and emits the next step.
Transition: PartialFanoutState → PartialFanoutState
onChainFanoutDatum :: IsTx tx => UTxOType tx -> OnChainFanoutDatum Source #
The on-chain datum implied by how much has been distributed so far: still
Closed while nothing has landed, FanoutProgress once some has.
onClosedChainFanoutTx Source #
Arguments
| :: ClosedState tx | |
| -> ChainStateType tx | New chain state |
| -> UTxOType tx | |
| -> Outcome tx |
Observe a (full or final) fanout transaction, finalizing the head.
Transition: ClosedState → IdleState
onClosedChainPartialFanoutTx Source #
Arguments
| :: IsTx tx | |
| => ClosedState tx | |
| -> ChainStateType tx | New chain state |
| -> UTxOType tx | UTxO distributed in this partial fanout (keyed by new TxIn; values preserve duplicates) |
| -> Outcome tx |
Observe a partial fanout while this node is still Closed — i.e. a partial
fanout this node did NOT initiate (another party did). The fanout driver moved
to PartialFanout when it issued its Fanout/PartialFanout command, so this
handler is only reached by passive observers.
The observer transitions into PartialFanout in AwaitingSelection mode and
does not auto-drive the rest: only the driver advances the fanout. This is
what makes selective partial fanout work in a multi-party head — observers must
not steamroll the remaining UTxO the driver deliberately left.
Transition: ClosedState → PartialFanoutState
removeDistributedOutputs :: IsTx tx => [TxOutType tx] -> UTxOType tx -> UTxOType tx Source #
onPartialFanoutChainPartialFanoutTx Source #
Arguments
| :: IsTx tx | |
| => PartialFanoutState tx | |
| -> ChainStateType tx | New chain state |
| -> UTxOType tx | UTxO distributed in this partial fanout |
| -> Outcome tx |
Observe a partial fanout while in PartialFanout. Updates the remaining and
distributed sets and, depending on the current FanoutMode, either continues
draining automatically (or within the active selection) or waits for the next
PartialFanout command.
Transition: PartialFanoutState → PartialFanoutState
onPartialFanoutChainFanoutTx Source #
Arguments
| :: IsTx tx | |
| => PartialFanoutState tx | |
| -> ChainStateType tx | New chain state |
| -> UTxOType tx | |
| -> Outcome tx |
Observe the final fanout while in PartialFanout, finalizing the head with
the accumulated distributed outputs plus this final batch.
Transition: PartialFanoutState → IdleState
fanoutUTxOFromSnapshot :: IsTx tx => ConfirmedSnapshot tx -> SnapshotVersion -> UTxOType tx Source #
The fan-out-able UTxO of a confirmed snapshot at the given on-chain version: the snapshot UTxO plus a pending commit (if the increment landed on chain) or a pending decommit (if the decrement has not landed yet).
closedToFanoutProgress :: ClosedState tx -> ChainStateType tx -> UTxOType tx -> UTxOType tx -> FanoutMode tx -> HeadState tx Source #
Build the PartialFanout (FanoutProgress) head state from a closed head,
carrying over the snapshot/parameters and using the given chain state, remaining
and distributed UTxO and fanout StateChanged. Shared by the three Closed →
FanoutProgress transitions in aggregateNodeState.
fanoutProgressToClosed :: PartialFanoutState tx -> ClosedState tx Source #
Rebuild the ClosedState from a PartialFanoutState when reverting an
optimistic Closed → PartialFanout transition (see HeadFanoutReverted).
$sel:readyToFanoutSent:ClosedState is restored to True because a fanout is only reachable
after the head was announced ReadyToFanout.
isFanoutPostChainTx :: PostChainTx tx -> Bool Source #
Whether a PostChainTx is one of the fanout-posting transactions (used to
scope the optimistic-fanout revert to genuine fanout post failures).
repostFanoutStep :: IsTx tx => PartialFanoutState tx -> Outcome tx Source #
Re-post the next fanout step after a chain rollback while in
FanoutProgress, so the fanout resumes instead of stalling with the
rolled-back transaction gone and nothing re-posted. This mirrors the
IncrementDecrement re-post on rollback (maybeRepostIncrementTx
maybeRepostDecrementTx): it uses the current best-effort bookkeeping and,
like those re-posts, assumes the rolled-back transactions re-appear — it does
not attempt to reconstruct fanout progress across a divergent rollback (the
same limitation the general rollback handling has).
distributedOutputs being empty means no partial fanout has landed on chain
yet (the head datum is still Closed); otherwise the datum is
FanoutProgress and a FinalPartialFanoutTx is possible.
Arguments
| :: IsChainState tx | |
| => Environment | |
| -> UTCTime | Current system time |
| -> ChainPointType tx | Latest Chain point observed |
| -> UTCTime | Latest Chain point time representation observed |
| -> SyncedStatus | |
| -> Outcome tx |
Detect our view of the chain going out of sync and issue a NodeUnsynced
event when this is the case.
nextActiveDepositId :: IsTx tx => PendingDeposits tx -> Maybe (TxIdType tx) Source #
Find the oldest non-empty active deposit, if any. Deposits are selected
in FIFO order by their StateChanged timestamp. This mirrors the selection
logic in withNextActive used by onOpenChainTick.
Arguments
| :: IsTx tx | |
| => PendingDeposits tx | |
| -> Maybe (TxIdType tx) | |
| -> Maybe tx | Pending decommit tx |
| -> Maybe (UTxOType tx) | utxoToCommit of the last relevant confirmed snapshot |
| -> Maybe (TxIdType tx) |
Select the deposit to include in the next snapshot.
Prefers a deposit already tracked in $sel:currentDepositTxId:CoordinatedHeadState (if still pending).
Falls back to the oldest active deposit from $sel:pendingDeposits:NodeInSync, but only
when neither a decommit is pending nor the last confirmed snapshot already
included a deposit (to avoid double-posting IncrementTx before
CommitFinalized removes the deposit).
Arguments
| :: IsChainState tx | |
| => Environment | |
| -> Ledger tx | |
| -> UTCTime | Current system time. |
| -> ChainPointTime | Last known chain point time |
| -> PendingDeposits tx | |
| -> HeadState tx | Current HeadState to validate the command against. |
| -> Input tx | Input to be processed. |
| -> SyncedStatus | |
| -> Outcome tx |
Arguments
| :: IsChainState tx | |
| => Environment | |
| -> Ledger tx | |
| -> UTCTime | Current system time. |
| -> ChainPointTime | Last known chain point time |
| -> PendingDeposits tx | |
| -> HeadState tx | Current HeadState to validate the command against. |
| -> Input tx | Input to be processed. |
| -> SyncedStatus | |
| -> Outcome tx |
Arguments
| :: IsChainState tx | |
| => Environment | |
| -> Ledger tx | |
| -> UTCTime | Current system time. |
| -> ChainPointTime | Last known chain point time |
| -> PendingDeposits tx | |
| -> HeadState tx | Current HeadState to validate the command against. |
| -> Input tx | Input to be processed. |
| -> SyncedStatus | |
| -> Outcome tx |
Arguments
| :: IsChainState tx | |
| => Environment | |
| -> Ledger tx | |
| -> ChainPointTime | Last known chain point time |
| -> PendingDeposits tx | |
| -> HeadState tx | Current NodeState to validate the command against. |
| -> Input tx | Input to be processed. |
| -> Outcome tx |
Arguments
| :: IsChainState tx | |
| => Environment | |
| -> Ledger tx | |
| -> ChainPointTime | Last known chain point time |
| -> PendingDeposits tx | |
| -> HeadState tx | Current NodeState to validate the command against. |
| -> Input tx | Input to be processed. |
| -> Outcome tx |
onConnectionEvent :: Text -> Connectivity -> Outcome tx Source #
headIdOf :: HeadState tx -> Maybe HeadId Source #
Extract the HeadId from the current HeadState, if any.
eventHeadId :: StateChanged tx -> Maybe HeadId Source #
Extract the HeadId from a StateChanged event, if the event carries one.
Events that do not carry a HeadId always pass through aggregateNodeState unchanged.
applyEvent :: IsChainState tx => HeadState tx -> StateChanged tx -> HeadState tx Source #
Inputs that are processed by the head logic (the "core"). Corresponding to each of the "shell" layers, we distinguish between inputs from the client, the network and the chain.
Constructors
| ClientInput | Input received from clients via the Hydra.API. |
Fields
| |
| NetworkInput | Input received from peers via a Hydra.Network.
|
Fields
| |
| ChainInput | Input received from the chain via a Hydra.Chain. |
Fields
| |
Instances
data SideLoadRequirementFailure tx Source #
Constructors
| SideLoadInitialSnapshotMismatch | |
| SideLoadSnNumberInvalid | |
Fields
| |
| SideLoadSvNumberInvalid | |
Fields
| |
| SideLoadUTxOToCommitInvalid | |
Fields
| |
| SideLoadDepositTxIdInvalid | The side-loaded snapshot commits the same UTxO as the confirmed one, but
from a different deposit. Since the deposit is what identifies a pending
commit, this is a distinct disagreement from |
Fields
| |
| SideLoadUTxOToDecommitInvalid | |
Fields
| |
| SideLoadInvalidMultisignature | |
Instances
data LogicError tx Source #
Constructors
| UnhandledInput | |
Fields
| |
| RequireFailed | |
Fields | |
| AssertionFailed | |
Fields
| |
| NotOurHead | |
Fields
| |
| SideLoadSnapshotFailed | |
Fields | |
Instances
data RequirementFailure tx Source #
Constructors
| ReqSnNumberInvalid | |
Fields
| |
| ReqSvNumberInvalid | |
Fields
| |
| ReqSnNotLeader | |
Fields
| |
| ReqSnDecommitNotSettled | |
| ReqSnCommitNotSettled | |
| ReqSnBothCommitAndDecommit | A snapshot may settle a commit or a decommit, never both: close and fanout carry a single incremental action, so a snapshot with both would leave the head unclosable. |
Fields
| |
| ReqSnDecommitNoOutputs | A decommit that materializes no output cannot be settled: the decrement validator requires at least one decommit output. |
Fields
| |
| InvalidMultisignature | |
| SnapshotAlreadySigned | |
Fields
| |
| AckSnNumberInvalid | |
Fields
| |
| SnapshotDoesNotApply | |
Fields
| |
| NoMatchingDeposit | |
| RequestedDepositExpired | |
Fields
| |
| RequestedDepositNotFoundLocally | |
Fields
| |
| ReqSnUTxOSetTooLarge | |
Fields
| |
Instances
data CoordinatedHeadState tx Source #
Off-chain state of the Coordinated Head protocol.
Constructors
| CoordinatedHeadState | |
Fields
| |
Instances
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 (OpenState, etc.) contain a black-box
IdleState corresponding to the ChainEvent 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.
TODO: chainState would actually not be needed in the HeadState anymore as we
do not persist the HeadState and not access it in the HeadLogic either.
Constructors
| Idle (IdleState tx) | |
| Open (OpenState tx) | |
| Closed (ClosedState tx) | |
| FanoutProgress (PartialFanoutState tx) | A closed head whose UTxO is being fanned out across multiple
transactions (on-chain in the |
Instances
An Open head with a CoordinatedHeadState tracking off-chain
transactions.
Constructors
| OpenState | |
Fields
| |
Instances
| (IsTx tx, FromJSON (ChainStateType tx)) => FromJSON (OpenState tx) Source # | |
Defined in Hydra.HeadLogic.State Methods parseJSON :: Value -> Parser (OpenState tx) parseJSONList :: Value -> Parser [OpenState tx] omittedField :: Maybe (OpenState tx) | |
| (IsTx tx, ToJSON (ChainStateType tx)) => ToJSON (OpenState tx) Source # | |
Defined in Hydra.HeadLogic.State Methods toJSON :: OpenState tx -> Value toEncoding :: OpenState tx -> Encoding toJSONList :: [OpenState tx] -> Value toEncodingList :: [OpenState tx] -> Encoding | |
| Generic (OpenState tx) Source # | |
| (IsTx tx, Show (ChainStateType tx)) => Show (OpenState tx) Source # | |
| IsChainState tx => FromCBOR (OpenState tx) Source # | |
| IsChainState tx => ToCBOR (OpenState tx) Source # | |
Defined in Hydra.HeadLogic.State Methods toCBOR :: OpenState tx -> Encoding encodedSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size) -> Proxy (OpenState tx) -> Size encodedListSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size) -> Proxy [OpenState tx] -> Size | |
| (IsTx tx, Eq (ChainStateType tx)) => Eq (OpenState tx) Source # | |
| type Rep (OpenState tx) Source # | |
Defined in Hydra.HeadLogic.State type Rep (OpenState tx) = D1 ('MetaData "OpenState" "Hydra.HeadLogic.State" "hydra-node-2.3.0-1cgalYNmLJQC1YXlYVq7mp" 'False) (C1 ('MetaCons "OpenState" 'PrefixI 'True) ((S1 ('MetaSel ('Just "parameters") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 HeadParameters) :*: S1 ('MetaSel ('Just "coordinatedHeadState") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 (CoordinatedHeadState tx))) :*: (S1 ('MetaSel ('Just "chainState") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 (ChainStateType tx)) :*: (S1 ('MetaSel ('Just "headId") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 HeadId) :*: S1 ('MetaSel ('Just "headSeed") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 HeadSeed))))) | |
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. |
| SeenSnapshot | ReqSn for given snapshot was received. |
Fields
| |
Instances
data ClosedState tx Source #
An Closed head with an current candidate ConfirmedSnapshot, which may
be contested before the ClosedState.
Constructors
| ClosedState | |
Fields
| |
Instances
data FanoutMode tx Source #
How the node decides which UTxOs to distribute in the next fanout step
while the head is in FanoutProgress.
Constructors
| AutoDrain | Entered only via the |
| DistributingSelection (UTxOType tx) | Manual mode: keep distributing this (content-tracked) user selection, dynamically chunked, until it is exhausted. |
| AwaitingSelection | Manual mode: the previous selection has been fully distributed. Wait for
the next |
Instances
data PartialFanoutState tx Source #
A closed head whose UTxO is being distributed across multiple fanout
transactions (on-chain FanoutProgress). Holds the partial-fanout bookkeeping
that used to live in ClosedState.
Constructors
| PartialFanoutState | |
Fields
| |
Instances
An Idle head only having a chain state with things seen on chain so far.
Constructors
| IdleState | |
Fields
| |
Instances
| FromJSON (ChainStateType tx) => FromJSON (IdleState tx) Source # | |
Defined in Hydra.HeadLogic.State Methods parseJSON :: Value -> Parser (IdleState tx) parseJSONList :: Value -> Parser [IdleState tx] omittedField :: Maybe (IdleState tx) | |
| 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 # | |
| IsChainState tx => FromCBOR (IdleState tx) Source # | |
| IsChainState tx => ToCBOR (IdleState tx) Source # | |
Defined in Hydra.HeadLogic.State Methods toCBOR :: IdleState tx -> Encoding encodedSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size) -> Proxy (IdleState tx) -> Size encodedListSizeExpr :: (forall t. ToCBOR t => Proxy t -> Size) -> Proxy [IdleState tx] -> Size | |
| Eq (ChainStateType tx) => Eq (IdleState tx) Source # | |
| type Rep (IdleState tx) Source # | |
Defined in Hydra.HeadLogic.State | |
getChainState :: HeadState tx -> ChainStateType tx Source #
Get the chain state in any HeadState.
isCollectingAcks :: SeenSnapshot tx -> Bool Source #
Whether AckSns are currently being collected for a snapshot.
Unlike snapshotInFlight, returns False for RequestedSnapshot — a
snapshot sent but not yet echoed is stale once the version bumps and should
not block a fresh request with the new version.
mkSeenSnapshot :: IsTx tx => Snapshot tx -> Map Party (Signature (Snapshot tx)) -> SeenSnapshot tx Source #
Smart constructor for SeenSnapshot that computes and caches
$sel:signableBytes:NoSeenSnapshot from $sel:snapshot:NoSeenSnapshot, enforcing the invariant that they stay in sync.
seenSnapshotNumber :: SeenSnapshot tx -> SnapshotNumber Source #
Get the last seen snapshot number given a SeenSnapshot.
setChainState :: ChainStateType tx -> HeadState tx -> HeadState tx Source #
Update the chain state in any HeadState.
snapshotInFlight :: SeenSnapshot tx -> Bool Source #
Whether a snapshot is currently in-flight (requested or being signed).
Analogous to inputs, the pure head logic "core" can have effects emitted 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
Constructors
| Continue | Continue with the given state updates and side effects. |
Fields
| |
| Wait | Wait for some condition to be met with optional state updates. |
Fields
| |
| Error | Processing resulted in an error. |
Fields
| |
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
| NetworkConnected | |
| NetworkDisconnected | |
| PeerConnected | |
| PeerDisconnected | |
| NetworkVersionMismatch | |
Fields | |
| NetworkClusterIDMismatch | |
Fields
| |
| HeadOpened | |
Fields
| |
| TransactionReceived | |
Fields
| |
| TransactionAppliedToLocalUTxO | |
| SnapshotRequestDecided | |
Fields
| |
| SnapshotRequested | |
Fields
| |
| PartySignedSnapshot | |
Fields
| |
| SnapshotConfirmed | |
Fields
| |
| DepositRecorded | |
Fields
| |
| DepositActivated | |
Fields
| |
| DepositExpired | |
Fields
| |
| DepositRecovered | |
Fields
| |
| CommitApproved | |
Fields
| |
| CommitFinalized | |
Fields
| |
| DecommitRecorded | |
Fields
| |
| DecommitApproved | |
Fields
| |
| DecommitInvalid | |
Fields
| |
| DecommitFinalized | |
Fields
| |
| HeadClosed | |
Fields
| |
| HeadContested | |
Fields
| |
| HeadIsReadyToFanout | |
Fields
| |
| HeadFanoutInitiated | This node initiated a full automatic fanout ( |
Fields
| |
| HeadPartialFanoutSelected | A user initiated or updated a selective partial fanout. From |
Fields
| |
| HeadFanoutReverted | Revert an optimistic |
Fields
| |
| HeadFannedOut | |
Fields
| |
| HeadPartialFannedOut | |
Fields
| |
| ChainRolledBack | |
Fields
| |
| TickObserved | |
Fields
| |
| IgnoredHeadInitializing | |
Fields
| |
| TxInvalid | |
Fields
| |
| LocalStateCleared | |
Fields
| |
| Checkpoint | |
| NodeUnsynced | |
Fields
| |
| NodeSynced | |
Fields
| |
Instances
data WaitReason tx Source #
Constructors
| WaitOnNotApplicableTx | |
Fields | |
| WaitOnSnapshotNumber | |
Fields
| |
| WaitOnSnapshotVersion | |
Fields
| |
| WaitOnSeenSnapshot | |
| WaitOnTxs | |
Fields
| |
| WaitOnContestationDeadline | |
| WaitOnNotApplicableDecommitTx | |
Fields | |
| WaitOnUnresolvedCommit | |
Fields
| |
| WaitOnUnresolvedDecommit | |
Fields
| |
| WaitOnDepositObserved | |
Fields
| |
| WaitOnDepositActivation | |
Fields
| |
| WaitOnNodeInSync | |
Fields
| |
Instances
changes :: [StateChanged tx] -> Outcome tx Source #
newState :: StateChanged tx -> Outcome tx Source #
wait :: WaitReason tx -> Outcome tx Source #