Safe Haskell | None |
---|---|
Language | Haskell2010 |
Synopsis
-
newtype
ChainSyncClientPipelined
header point tip (m ::
Type
->
Type
) a =
ChainSyncClientPipelined
{
- runChainSyncClientPipelined :: m ( ClientPipelinedStIdle ' Z header point tip m a)
-
data
ClientPipelinedStIdle
(n ::
N
) header point tip (m ::
Type
->
Type
) a
where
- SendMsgRequestNext :: forall header point tip (m :: Type -> Type ) a. ClientStNext ' Z header point tip m a -> m ( ClientStNext ' Z header point tip m a) -> ClientPipelinedStIdle ' Z header point tip m a
- SendMsgRequestNextPipelined :: forall (n :: N ) header point tip (m :: Type -> Type ) a. ClientPipelinedStIdle (' S n) header point tip m a -> ClientPipelinedStIdle n header point tip m a
- SendMsgFindIntersect :: forall point header tip (m :: Type -> Type ) a. [point] -> ClientPipelinedStIntersect header point tip m a -> ClientPipelinedStIdle ' Z header point tip m a
- CollectResponse :: forall (m :: Type -> Type ) (n1 :: N ) header point tip a. Maybe (m ( ClientPipelinedStIdle (' S n1) header point tip m a)) -> ClientStNext n1 header point tip m a -> ClientPipelinedStIdle (' S n1) header point tip m a
- SendMsgDone :: forall a header point tip (m :: Type -> Type ). a -> ClientPipelinedStIdle ' Z header point tip m a
-
data
ClientStNext
(n ::
N
) header point tip (m ::
Type
->
Type
) a =
ClientStNext
{
- recvMsgRollForward :: header -> tip -> m ( ClientPipelinedStIdle n header point tip m a)
- recvMsgRollBackward :: point -> tip -> m ( ClientPipelinedStIdle n header point tip m a)
-
data
ClientPipelinedStIntersect
header point tip (m ::
Type
->
Type
) a =
ClientPipelinedStIntersect
{
- recvMsgIntersectFound :: point -> tip -> m ( ClientPipelinedStIdle ' Z header point tip m a)
- recvMsgIntersectNotFound :: tip -> m ( ClientPipelinedStIdle ' Z header point tip m a)
-
data
ChainSyncInstruction
header point tip
- = RollForward !header !tip
- | RollBackward !point !tip
-
data
PipelineDecision
(n ::
N
)
where
- Request :: PipelineDecision ' Z
- Pipeline :: forall (n :: N ). PipelineDecision n
- CollectOrPipeline :: forall (n1 :: N ). PipelineDecision (' S n1)
- Collect :: forall (n1 :: N ). PipelineDecision (' S n1)
-
data
MkPipelineDecision
where
- MkPipelineDecision :: ( forall (n :: N ). Nat n -> WithOrigin BlockNo -> WithOrigin BlockNo -> ( PipelineDecision n, MkPipelineDecision )) -> MkPipelineDecision
- runPipelineDecision :: forall (n :: N ). MkPipelineDecision -> Nat n -> WithOrigin BlockNo -> WithOrigin BlockNo -> ( PipelineDecision n, MkPipelineDecision )
- constantPipelineDecision :: ( forall (n :: N ). Nat n -> WithOrigin BlockNo -> WithOrigin BlockNo -> PipelineDecision n) -> MkPipelineDecision
- pipelineDecisionMax :: forall (n :: N ). Word32 -> Nat n -> WithOrigin BlockNo -> WithOrigin BlockNo -> PipelineDecision n
- pipelineDecisionMin :: forall (n :: N ). Word32 -> Nat n -> WithOrigin BlockNo -> WithOrigin BlockNo -> PipelineDecision n
- pipelineDecisionLowHighMark :: Word32 -> Word32 -> MkPipelineDecision
- data N
- data Nat (n :: N ) where
- natToInt :: forall (n :: N ). Nat n -> Int
- mapChainSyncClientPipelined :: forall header header' point point' tip tip' (m :: Type -> Type ) a. Functor m => (point -> point') -> (point' -> point) -> (header' -> header) -> (tip' -> tip) -> ChainSyncClientPipelined header point tip m a -> ChainSyncClientPipelined header' point' tip' m a
Pipelined protocol type for the client
The protocol states from the point of view of the client.
newtype ChainSyncClientPipelined header point tip (m :: Type -> Type ) a Source #
Pipelined chain sync client. It can only pipeline
MsgRequestNext
messages, while the
MsgFindIntersect
are non pipelined. This has a penalty
cost of an RTT, but they are send relatively seldom and their response might
impact how many messages one would like to pipeline. It also simplifies the
receiver callback.
ChainSyncClientPipelined | |
|
data ClientPipelinedStIdle (n :: N ) header point tip (m :: Type -> Type ) a where Source #
Pipelined sender which starts in
StIdle
state. It can either
-
Send
MsgRequestNext
(no pipelining), which might be useful when we are at the tip of the chain. It can only be send when there is no pipelined message in flight (all responses were collected); -
Pipeline
MsgRequestNext
; -
Send
MsgFindIntersect
(no pipelining); It can only be send when there is no pipelined message in flight (all responses were collected); - Collect responses of pipelined message;
-
Terminate the protocol with by sending
MsgDone
.
SendMsgRequestNext :: forall header point tip (m :: Type -> Type ) a. ClientStNext ' Z header point tip m a -> m ( ClientStNext ' Z header point tip m a) -> ClientPipelinedStIdle ' Z header point tip m a | |
SendMsgRequestNextPipelined :: forall (n :: N ) header point tip (m :: Type -> Type ) a. ClientPipelinedStIdle (' S n) header point tip m a -> ClientPipelinedStIdle n header point tip m a | |
SendMsgFindIntersect :: forall point header tip (m :: Type -> Type ) a. [point] -> ClientPipelinedStIntersect header point tip m a -> ClientPipelinedStIdle ' Z header point tip m a | |
CollectResponse :: forall (m :: Type -> Type ) (n1 :: N ) header point tip a. Maybe (m ( ClientPipelinedStIdle (' S n1) header point tip m a)) -> ClientStNext n1 header point tip m a -> ClientPipelinedStIdle (' S n1) header point tip m a | |
SendMsgDone :: forall a header point tip (m :: Type -> Type ). a -> ClientPipelinedStIdle ' Z header point tip m a |
data ClientStNext (n :: N ) header point tip (m :: Type -> Type ) a Source #
Callback for responses received after sending
MsgRequestNext
.
We could receive
MsgAwaitReply
. In this case we will wait for the next
message which must be
MsgRollForward
or
MsgRollBackward
; thus we need
only the two callbacks.
ClientStNext | |
|
data ClientPipelinedStIntersect header point tip (m :: Type -> Type ) a Source #
Callbacks for messages received after sending
MsgFindIntersect
.
We might receive either
MsgIntersectFound
or
MsgIntersectNotFound
.
ClientPipelinedStIntersect | |
|
data ChainSyncInstruction header point tip Source #
Data received through pipelining: either roll forward or roll backward
instruction. If the server replied with
MsgAwaitReply
the pipelined
receiver will await for the next message which must come with an instruction
how to update our chain.
Note: internal API, not exposed by this module.
RollForward !header !tip | |
RollBackward !point !tip |
Implementation Helpers
It's generally idiomatic to use these functions to implement your pipelined client. It aids in deciding when to make pipelined requests vs process received responses.
data PipelineDecision (n :: N ) where Source #
Pipeline decision: we can do either one of these:
- non-pipelined request
- pipeline a request
- collect or pipeline, but only when there are pipelined requests
- collect, as above, only when there are pipelined requests
There might be other useful pipelining scenarios: collect a given number of requests (which also can be used to collect all outstanding requests).
Request :: PipelineDecision ' Z | |
Pipeline :: forall (n :: N ). PipelineDecision n | |
CollectOrPipeline :: forall (n1 :: N ). PipelineDecision (' S n1) | |
Collect :: forall (n1 :: N ). PipelineDecision (' S n1) |
data MkPipelineDecision where Source #
The callback gets the following arguments:
- how many requests are not yet collected (in flight or already queued)
- block number of client's tip
- block number of server's tip
Client's tip block number and server's tip block number can only be equal
(from the client's perspective) when both the client's and the server's tip
headers agree. If they would not agree (server forked), then the server
sends
MsgRollBackward
, which rolls back one block and causes the client's
tip and the server's tip to differ.
In this module we implement three pipelining strategies:
MkPipelineDecision :: ( forall (n :: N ). Nat n -> WithOrigin BlockNo -> WithOrigin BlockNo -> ( PipelineDecision n, MkPipelineDecision )) -> MkPipelineDecision |
runPipelineDecision :: forall (n :: N ). MkPipelineDecision -> Nat n -> WithOrigin BlockNo -> WithOrigin BlockNo -> ( PipelineDecision n, MkPipelineDecision ) Source #
constantPipelineDecision :: ( forall (n :: N ). Nat n -> WithOrigin BlockNo -> WithOrigin BlockNo -> PipelineDecision n) -> MkPipelineDecision Source #
pipelineDecisionMax :: forall (n :: N ). Word32 -> Nat n -> WithOrigin BlockNo -> WithOrigin BlockNo -> PipelineDecision n Source #
Present maximal pipelining of at most
omax
requests. Collect responses
either when we are at the same block number as the server or when we sent
more than
omax
requests.
If
omax = 3
this pipelining strategy will generate a sequence:
Pipeline
Pipeline
Pipeline
Collect
Pipeline
Collect
....
Pipeline
Collect
Collect
Collect
pipelineDecisionMin :: forall (n :: N ). Word32 -> Nat n -> WithOrigin BlockNo -> WithOrigin BlockNo -> PipelineDecision n Source #
Present minimum pipelining of at most
omax
requests, collect responses
eagerly.
pipelineDecisionLowHighMark :: Word32 -> Word32 -> MkPipelineDecision Source #
Pipelining strategy which pipelines up to
highMark
requests; if the
number of pipelined messages exceeds the high mark, it collects messages
until there are at most
lowMark
outstanding requests.
Type level natural numbers
data Nat (n :: N ) where Source #
A value level inductive natural number, indexed by the corresponding type
level natural number
N
.
This is often needed when writing pipelined peers to be able to count the
number of outstanding pipelined yields, and show to the type checker that
SenderCollect
and
SenderDone
are being used correctly.
Utilities
mapChainSyncClientPipelined :: forall header header' point point' tip tip' (m :: Type -> Type ) a. Functor m => (point -> point') -> (point' -> point) -> (header' -> header) -> (tip' -> tip) -> ChainSyncClientPipelined header point tip m a -> ChainSyncClientPipelined header' point' tip' m a Source #
Transform a
ChainSyncClientPipelined
by mapping over the tx header and
the chain tip values.
Note the direction of the individual mapping functions corresponds to whether the types are used as protocol inputs or outputs (or both, as is the case for points).