hydra-node
Safe HaskellSafe-Inferred
LanguageGHC2021

Hydra.Chain.Direct.Handlers

Description

Provide infrastructure-independent "handlers" for posting transactions and following the chain.

This module encapsulates the transformation logic between cardano transactions and HydraNode abstractions PostChainTx and OnChainTx, and maintenance of on-chain relevant state.

Synopsis

Documentation

data LocalChainState m tx Source #

Handle of a mutable local chain state that is kept in the direct chain layer.

Constructors

LocalChainState 

Fields

newLocalChainState :: forall m tx. (IsChainState tx, MonadLabelledSTM m) => ChainStateHistory tx -> m (LocalChainState m tx) Source #

Initialize a new local chain state from a given chain state history.

Posting Transactions

type SubmitTx m = Tx -> m () Source #

A callback used to actually submit a transaction to the chain.

type GetTimeHandle m = m TimeHandle Source #

A way to acquire a TimeHandle

mkChain Source #

Arguments

:: (MonadSTM m, MonadThrow (STM m)) 
=> Tracer m CardanoChainLog 
-> GetTimeHandle m

Means to acquire a new TimeHandle.

-> TinyWallet m 
-> ChainContext 
-> LocalChainState m Tx 
-> SubmitTx m 
-> Chain Tx m 

Create a Chain component for posting "real" cardano transactions.

This component does not actually interact with a cardano-node, but creates cardano transactions from PostChainTx transactions emitted by a HydraNode, balancing and signing them using given TinyWallet, before handing it off to the given SubmitTx callback. There is also a draftTx option for drafting a commit tx on behalf of the user using their selected utxo.

NOTE: Given the constraints on m this function should work within IOSim and does not require any actual IO to happen which makes it highly suitable for simulations and testing.

rejectLowDeposits :: PParams LedgerEra -> UTxO -> Either (PostTxError Tx) () Source #

rejectByronAddresses :: UTxO -> Either (PostTxError Tx) () Source #

Reject any UTxO containing a Byron address, which cannot be represented in the Hydra head protocol.

rejectOversizedDeposit Source #

Arguments

:: PParams LedgerEra

Layer 1 protocol parameters (from $sel:getPParams:TinyWallet of the wallet, NOT the L2 ledger parameters passed to the draft endpoint).

-> ChainContext 
-> UTxO

Spendable UTxO containing the current head output.

-> HeadId 
-> ConfirmedSnapshot Tx

Current confirmed snapshot, basis for the dry-run increment.

-> Tx

Drafted (unbalanced) deposit transaction.

-> SlotNo

Upper validity slot for the dry-run increment.

-> Either (PostTxError Tx) () 

Reject deposits which could never be claimed: builds a dry-run increment transaction for the drafted deposit and rejects with DepositTooLarge when it would violate layer 1 ledger limits - the maximum transaction size, or the maximum serialized value size of the merged head output.

serializedValueSize :: PParams LedgerEra -> Value -> Natural Source #

Serialized size of a value, computed exactly like the ledger's OutputTooBigUTxO check. NOTE: Keep in sync with validateOutputTooBigUTxO.

incrementTxBalancingMargin :: Natural Source #

Byte headroom added to the unbalanced dry-run increment transaction when comparing against the maximum transaction size, covering what $sel:coverFee:TinyWallet and $sel:sign:TinyWallet add to the real increment: a fee input (~40 bytes), a collateral input (~40 bytes), an ada-only change output (~70 bytes), the script integrity hash (~37 bytes), the fee field (~5 bytes), one key witness (~102 bytes), and wider integer encodings for the estimated execution units, snapshot number and validity slot (~40 bytes) - around 334 bytes in total. We add some overhead and use 512 just to be more safe.

finalizeTx :: MonadThrow m => TinyWallet m -> ChainContext -> UTxO -> UTxO -> Tx -> m Tx Source #

Balance and sign the given partial transaction.

Following the Chain

data ChainSyncHandler m Source #

A handler that takes care of following the chain.

Constructors

ChainSyncHandler 

Fields

data TimeConversionException Source #

Conversion of a slot number to a time failed. This can be usually be considered an internal error and may be happening because the used era history is too old.

Constructors

TimeConversionException 

Fields

chainSyncHandler Source #

Arguments

:: forall m. (MonadSTM m, MonadThrow m) 
=> Tracer m CardanoChainLog

Tracer for logging

-> ChainCallback Tx m 
-> (SlotNo -> GetTimeHandle m)

Means to acquire a TimeHandle able to convert the given slot.

-> ChainContext

Contextual information about our chain connection.

-> LocalChainState m Tx 
-> ChainSyncHandler m

A chain-sync handler to use in a local-chain-sync client.

Creates a ChainSyncHandler that can notify the given callback of events happening on-chain.

This forms the other half of a ChainComponent along with mkChain but is decoupled from actual interactions with the chain.

A TimeHandle is needed to do `SlotNo -> POSIXTime` conversions for Tick events.

Throws TimeConversionException when a received block's SlotNo cannot be converted to a UTCTime with the given TimeHandle.

prepareTxToPost Source #

Arguments

:: forall m. (MonadSTM m, MonadThrow (STM m)) 
=> TimeHandle 
-> ChainContext 
-> UTxOType Tx

Spendable UTxO

-> PostChainTx Tx 
-> STM m Tx 

findLargestFitting Source #

Arguments

:: Monad m 
=> (Int -> m (Maybe tx))

Construct and check a transaction; Just tx = fits, Nothing = doesn't fit; may throw on structural failure

-> Int

Upper bound of chunk sizes to search (inclusive)

-> m (Either () tx) 

Binary search for the largest chunk size in [1..maxChunk] for which tryTx returns Just. Assumes the predicate is monotone: if size n fits, all sizes < n also fit. Uses upper-mid so the search terminates correctly when hi = lo + 1. Returns 'Left ()' if no size fits. tryTx may throw to abort the search early.

fitsTx :: Monad m => Tracer m CardanoChainLog -> (Tx -> m Bool) -> (Tx -> UTxO -> m (Either EvaluationError EvaluationReport)) -> UTxO -> Tx -> m Bool Source #

Check whether a transaction fits within protocol size and script execution limits. Size check is cheap so it short-circuits before the expensive UPLC evaluation. Structural errors (script failures, protocol parameter conversion errors) are traced via the provided tracer; transient misses (size exceeded, budget overrun) are silent.

findFittingFanoutTx Source #

Arguments

:: forall m. MonadThrow m 
=> Tracer m CardanoChainLog 
-> TinyWallet m 
-> ChainContext 
-> UTxO

Spendable UTxO containing head output

-> TxIn

Seed TxIn

-> Maybe Tx

Preferred tx to try first (FanoutTx or FinalPartialFanoutTx); Nothing skips straight to the fallback loop

-> UTxO

UTxO for the accumulator check in the partial-fanout fallback (matches the on-chain datum)

-> UTxO

UTxOs to distribute in the partial-fanout fallback

-> Int

Upper bound (inclusive) of chunk sizes to search in the fallback. For the final/full fanout fallback this is size - 1 (the preferred tx handles the full set; a partial fanout must leave at least one output). For an explicit non-final partial fanout this is the full size: the selection is always a strict subset of the head's remaining UTxO, so even distributing all of it leaves the unselected remainder in the accumulator and mustNotBeLastBatch holds.

-> SlotNo

Contestation deadline as SlotNo

-> m Tx 

Try the preferred transaction first; if it doesn't fit within the script execution budget or exceeds the maximum transaction size, fall back to a binary search over partial fanout chunk sizes. Returns the largest chunk that fits, minimising the number of fanout steps.

Error mapping: * StaleChainState from partialFanoutStalePartialFanoutTx (race condition; HeadLogic silently ignores it and the chain observation loop triggers the correct next step). * Any other PartialFanoutErrorFailedToConstructPartialFanoutTx (structural mismatch that will not resolve on retry). * No chunk fits within budget → FailedToConstructPartialFanoutTx (budget exhaustion; also not a race condition).

maxGraceTime :: NominalDiffTime Source #

Maximum delay we put on the upper bound of transactions to fit into a block. NOTE: This is highly depending on the network. If the security parameter and epoch length result in a short horizon, this is problematic.

data StartingDecision Source #

Constructors

FromProvided ChainPoint 
FromTip ChainPoint 
FromPersisted 

Fields

  • chainPoint :: ChainPoint
     
  • startChainFromSet :: Bool

    Whether the user-provided --start-chain-from point was set but ignored, because it was older than persisted points.

Instances

Instances details
ToJSON StartingDecision Source # 
Instance details

Defined in Hydra.Chain.Direct.Handlers

Generic StartingDecision Source # 
Instance details

Defined in Hydra.Chain.Direct.Handlers

Associated Types

type Rep StartingDecision :: Type -> Type Source #

Show StartingDecision Source # 
Instance details

Defined in Hydra.Chain.Direct.Handlers

Eq StartingDecision Source # 
Instance details

Defined in Hydra.Chain.Direct.Handlers

type Rep StartingDecision Source # 
Instance details

Defined in Hydra.Chain.Direct.Handlers

type Rep StartingDecision = D1 ('MetaData "StartingDecision" "Hydra.Chain.Direct.Handlers" "hydra-node-2.3.0-1cgalYNmLJQC1YXlYVq7mp" 'False) (C1 ('MetaCons "FromProvided" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 ChainPoint)) :+: (C1 ('MetaCons "FromTip" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 ChainPoint)) :+: C1 ('MetaCons "FromPersisted" 'PrefixI 'True) (S1 ('MetaSel ('Just "chainPoint") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 ChainPoint) :*: S1 ('MetaSel ('Just "startChainFromSet") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Bool))))

data CardanoChainLog Source #

Constructors

ToPost 

Fields

PostingTx 

Fields

PostedTx 

Fields

PostingFailed 

Fields

RolledForward 

Fields

RolledBackward 

Fields

Wallet TinyWalletLog 
StartingChainDecision StartingDecision 
BlockfrostTransientError 

Fields

PartialFanoutFailed 

Fields

Instances

Instances details
ToJSON CardanoChainLog Source # 
Instance details

Defined in Hydra.Chain.Direct.Handlers

Generic CardanoChainLog Source # 
Instance details

Defined in Hydra.Chain.Direct.Handlers

Associated Types

type Rep CardanoChainLog :: Type -> Type Source #

Show CardanoChainLog Source # 
Instance details

Defined in Hydra.Chain.Direct.Handlers

Eq CardanoChainLog Source # 
Instance details

Defined in Hydra.Chain.Direct.Handlers

type Rep CardanoChainLog Source # 
Instance details

Defined in Hydra.Chain.Direct.Handlers

type Rep CardanoChainLog = D1 ('MetaData "CardanoChainLog" "Hydra.Chain.Direct.Handlers" "hydra-node-2.3.0-1cgalYNmLJQC1YXlYVq7mp" 'False) (((C1 ('MetaCons "ToPost" 'PrefixI 'True) (S1 ('MetaSel ('Just "toPost") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 (PostChainTx Tx))) :+: C1 ('MetaCons "PostingTx" 'PrefixI 'True) (S1 ('MetaSel ('Just "txId") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 TxId))) :+: (C1 ('MetaCons "PostedTx" 'PrefixI 'True) (S1 ('MetaSel ('Just "txId") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 TxId)) :+: (C1 ('MetaCons "PostingFailed" 'PrefixI 'True) (S1 ('MetaSel ('Just "tx") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Tx) :*: S1 ('MetaSel ('Just "postTxError") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 (PostTxError Tx))) :+: C1 ('MetaCons "RolledForward" 'PrefixI 'True) (S1 ('MetaSel ('Just "point") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 ChainPoint) :*: S1 ('MetaSel ('Just "receivedTxIds") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 [TxId]))))) :+: ((C1 ('MetaCons "RolledBackward" 'PrefixI 'True) (S1 ('MetaSel ('Just "point") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 ChainPoint)) :+: C1 ('MetaCons "Wallet" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 TinyWalletLog))) :+: (C1 ('MetaCons "StartingChainDecision" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 StartingDecision)) :+: (C1 ('MetaCons "BlockfrostTransientError" 'PrefixI 'True) (S1 ('MetaSel ('Just "reason") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "retryDelay") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Int)) :+: C1 ('MetaCons "PartialFanoutFailed" 'PrefixI 'True) (S1 ('MetaSel ('Just "reason") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedStrict) (Rec0 Text))))))