{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE NamedFieldPuns      #-}
{-# LANGUAGE ScopedTypeVariables #-}


-- | A view of the chain synchronisation protocol from the point of view of the
-- client.
--
-- This provides a view that uses less complex types and should be easier to
-- use than the underlying typed protocol itself.
--
-- For execution, a conversion into the typed protocol is provided.
--
module Ouroboros.Network.Protocol.ChainSync.Client
  ( -- * Protocol type for the client
    -- | The protocol states from the point of view of the client.
    ChainSyncClient (..)
  , ClientStIdle (..)
  , ClientStNext (..)
  , ClientStIntersect (..)
    -- * Execution as a typed protocol
  , chainSyncClientPeer
    -- * Utilities
  , mapChainSyncClient
  ) where

import Network.TypedProtocol.Core
import Network.TypedProtocol.Peer.Client

import Ouroboros.Network.Protocol.ChainSync.Type


-- | A chain sync protocol client, on top of some effect 'm'.
-- The first choice of request is within that 'm'.
newtype ChainSyncClient header point tip m a = ChainSyncClient {
    forall header point tip (m :: * -> *) a.
ChainSyncClient header point tip m a
-> m (ClientStIdle header point tip m a)
runChainSyncClient :: m (ClientStIdle header point tip m a)
  }


-- | In the 'StIdle' protocol state, the server does not have agency and can choose to
-- send a request next, or a find intersection message.
--
data ClientStIdle header point tip m a where

  -- | Send the 'MsgRequestNext', with handlers for the replies.
  --
  -- The handlers for this message are more complicated than most RPCs because
  -- the server can either send us a reply immediately or it can send us a
  -- 'MsgAwaitReply' to indicate that the server itself has to block for a
  -- state change before it can send us the reply.
  --
  -- In the waiting case, the client gets the chance to take a local action.
  --
  SendMsgRequestNext
    :: m ()   -- ^ promptly invoked when 'MsgAwaitReply' is received
    -> ClientStNext header point tip m a
    -> ClientStIdle header point tip m a

  -- | Send the 'MsgFindIntersect', with handlers for the replies.
  --
  SendMsgFindIntersect
    :: [point]
    -> ClientStIntersect header point tip m a
    -> ClientStIdle header point tip m a

  -- | The client decided to end the protocol.
  --
  SendMsgDone
    :: a
    -> ClientStIdle header point tip m a

-- | In the 'StNext' protocol state, the client does not have agency and is
-- waiting to receive either
--
--  * a roll forward,
--  * roll back message,
--
-- It must be prepared to handle any of these.
--
data ClientStNext header point tip m a =
     ClientStNext {
       forall header point tip (m :: * -> *) a.
ClientStNext header point tip m a
-> header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward  :: header -- header to add to the chain
                           -> tip    -- information about tip of the chain
                           -> ChainSyncClient header point tip m a,

       forall header point tip (m :: * -> *) a.
ClientStNext header point tip m a
-> point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward :: point        -- rollback point
                           -> tip          -- information about tip of the chain
                           -> ChainSyncClient header point tip m a
     }

-- | In the 'StIntersect' protocol state, the client does not have agency and
-- is waiting to receive:
--
--  * an intersection improved,
--  * unchanged message,
--  * the termination message.
--
-- It must be prepared to handle any of these.
--
data ClientStIntersect header point tip m a =
     ClientStIntersect {
       forall header point tip (m :: * -> *) a.
ClientStIntersect header point tip m a
-> point -> tip -> ChainSyncClient header point tip m a
recvMsgIntersectFound    :: point        -- found intersection point
                                -> tip          -- information about tip of the chain
                                -> ChainSyncClient header point tip m a,

       forall header point tip (m :: * -> *) a.
ClientStIntersect header point tip m a
-> tip -> ChainSyncClient header point tip m a
recvMsgIntersectNotFound :: tip          -- information about tip of the chain
                                -> ChainSyncClient header point tip m a
     }


-- | Transform a 'ChainSyncClient' 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).
--
mapChainSyncClient :: forall header header' point point' tip tip' m a.
                      Functor m
                   => (point  -> point')
                   -> (point' -> point)
                   -> (header' -> header)
                   -> (tip' -> tip)
                   -> ChainSyncClient header  point  tip  m a
                   -> ChainSyncClient header' point' tip' m a
mapChainSyncClient :: forall header header' point point' tip tip' (m :: * -> *) a.
Functor m =>
(point -> point')
-> (point' -> point)
-> (header' -> header)
-> (tip' -> tip)
-> ChainSyncClient header point tip m a
-> ChainSyncClient header' point' tip' m a
mapChainSyncClient point -> point'
fpoint point' -> point
fpoint' header' -> header
fheader tip' -> tip
ftip =
    ChainSyncClient header point tip m a
-> ChainSyncClient header' point' tip' m a
goClient
  where
    goClient :: ChainSyncClient header  point  tip  m a
             -> ChainSyncClient header' point' tip' m a
    goClient :: ChainSyncClient header point tip m a
-> ChainSyncClient header' point' tip' m a
goClient (ChainSyncClient m (ClientStIdle header point tip m a)
c) = m (ClientStIdle header' point' tip' m a)
-> ChainSyncClient header' point' tip' m a
forall header point tip (m :: * -> *) a.
m (ClientStIdle header point tip m a)
-> ChainSyncClient header point tip m a
ChainSyncClient ((ClientStIdle header point tip m a
 -> ClientStIdle header' point' tip' m a)
-> m (ClientStIdle header point tip m a)
-> m (ClientStIdle header' point' tip' m a)
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ClientStIdle header point tip m a
-> ClientStIdle header' point' tip' m a
goIdle m (ClientStIdle header point tip m a)
c)

    goIdle :: ClientStIdle header  point  tip  m a
           -> ClientStIdle header' point' tip' m a
    goIdle :: ClientStIdle header point tip m a
-> ClientStIdle header' point' tip' m a
goIdle (SendMsgRequestNext m ()
stAwait ClientStNext header point tip m a
stNext) =
      m ()
-> ClientStNext header' point' tip' m a
-> ClientStIdle header' point' tip' m a
forall (m :: * -> *) header point tip a.
m ()
-> ClientStNext header point tip m a
-> ClientStIdle header point tip m a
SendMsgRequestNext m ()
stAwait (ClientStNext header point tip m a
-> ClientStNext header' point' tip' m a
goNext ClientStNext header point tip m a
stNext)

    goIdle (SendMsgFindIntersect [point]
points ClientStIntersect header point tip m a
stIntersect) =
      [point']
-> ClientStIntersect header' point' tip' m a
-> ClientStIdle header' point' tip' m a
forall point header tip (m :: * -> *) a.
[point]
-> ClientStIntersect header point tip m a
-> ClientStIdle header point tip m a
SendMsgFindIntersect ((point -> point') -> [point] -> [point']
forall a b. (a -> b) -> [a] -> [b]
map point -> point'
fpoint [point]
points) (ClientStIntersect header point tip m a
-> ClientStIntersect header' point' tip' m a
goIntersect ClientStIntersect header point tip m a
stIntersect)

    goIdle (SendMsgDone a
a) = a -> ClientStIdle header' point' tip' m a
forall a header point tip (m :: * -> *).
a -> ClientStIdle header point tip m a
SendMsgDone a
a

    goNext :: ClientStNext header  point  tip  m a
           -> ClientStNext header' point' tip' m a
    goNext :: ClientStNext header point tip m a
-> ClientStNext header' point' tip' m a
goNext ClientStNext{header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward :: forall header point tip (m :: * -> *) a.
ClientStNext header point tip m a
-> header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward :: header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward, point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward :: forall header point tip (m :: * -> *) a.
ClientStNext header point tip m a
-> point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward :: point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward} =
      ClientStNext {
        recvMsgRollForward :: header' -> tip' -> ChainSyncClient header' point' tip' m a
recvMsgRollForward  = \header'
hdr tip'
tip ->
          ChainSyncClient header point tip m a
-> ChainSyncClient header' point' tip' m a
goClient (header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward (header' -> header
fheader header'
hdr) (tip' -> tip
ftip tip'
tip)),

        recvMsgRollBackward :: point' -> tip' -> ChainSyncClient header' point' tip' m a
recvMsgRollBackward = \point'
pt  tip'
tip ->
          ChainSyncClient header point tip m a
-> ChainSyncClient header' point' tip' m a
goClient (point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward (point' -> point
fpoint' point'
pt) (tip' -> tip
ftip tip'
tip))
      }

    goIntersect :: ClientStIntersect header  point  tip  m a
                -> ClientStIntersect header' point' tip' m a
    goIntersect :: ClientStIntersect header point tip m a
-> ClientStIntersect header' point' tip' m a
goIntersect ClientStIntersect { point -> tip -> ChainSyncClient header point tip m a
recvMsgIntersectFound :: forall header point tip (m :: * -> *) a.
ClientStIntersect header point tip m a
-> point -> tip -> ChainSyncClient header point tip m a
recvMsgIntersectFound :: point -> tip -> ChainSyncClient header point tip m a
recvMsgIntersectFound,
                                    tip -> ChainSyncClient header point tip m a
recvMsgIntersectNotFound :: forall header point tip (m :: * -> *) a.
ClientStIntersect header point tip m a
-> tip -> ChainSyncClient header point tip m a
recvMsgIntersectNotFound :: tip -> ChainSyncClient header point tip m a
recvMsgIntersectNotFound } =
      ClientStIntersect {
        recvMsgIntersectFound :: point' -> tip' -> ChainSyncClient header' point' tip' m a
recvMsgIntersectFound = \point'
pt tip'
tip ->
          ChainSyncClient header point tip m a
-> ChainSyncClient header' point' tip' m a
goClient (point -> tip -> ChainSyncClient header point tip m a
recvMsgIntersectFound (point' -> point
fpoint' point'
pt) (tip' -> tip
ftip tip'
tip)),

        recvMsgIntersectNotFound :: tip' -> ChainSyncClient header' point' tip' m a
recvMsgIntersectNotFound = \tip'
tip ->
          ChainSyncClient header point tip m a
-> ChainSyncClient header' point' tip' m a
goClient (tip -> ChainSyncClient header point tip m a
recvMsgIntersectNotFound (tip' -> tip
ftip tip'
tip))
      }


-- | Interpret a 'ChainSyncClient' action sequence as a 'Peer' on the client
-- side of the 'ChainSyncProtocol'.
--
chainSyncClientPeer
  :: forall header point tip m a .
     Monad m
  => ChainSyncClient header point tip m a
  -> Client (ChainSync header point tip) NonPipelined StIdle m a
chainSyncClientPeer :: forall header point tip (m :: * -> *) a.
Monad m =>
ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
chainSyncClientPeer (ChainSyncClient m (ClientStIdle header point tip m a)
mclient) =
    m (Client (ChainSync header point tip) 'NonPipelined 'StIdle m a)
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
m (Client ps pl st m a) -> Client ps pl st m a
Effect (m (Client (ChainSync header point tip) 'NonPipelined 'StIdle m a)
 -> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a)
-> m (Client
        (ChainSync header point tip) 'NonPipelined 'StIdle m a)
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall a b. (a -> b) -> a -> b
$ (ClientStIdle header point tip m a
 -> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a)
-> m (ClientStIdle header point tip m a)
-> m (Client
        (ChainSync header point tip) 'NonPipelined 'StIdle m a)
forall a b. (a -> b) -> m a -> m b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ClientStIdle header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
chainSyncClientPeer_ m (ClientStIdle header point tip m a)
mclient
  where
    chainSyncClientPeer_
      :: ClientStIdle header point tip m a
      -> Client (ChainSync header point tip) NonPipelined StIdle m a
    chainSyncClientPeer_ :: ClientStIdle header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
chainSyncClientPeer_ (SendMsgRequestNext m ()
stAwait ClientStNext header point tip m a
stNext) =
        Message (ChainSync header point tip) 'StIdle ('StNext 'StCanAwait)
-> Client
     (ChainSync header point tip)
     'NonPipelined
     ('StNext 'StCanAwait)
     m
     a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a
       (st' :: ps).
(StateTokenI st, StateTokenI st', StateAgency st ~ 'ClientAgency,
 Outstanding pl ~ 'Z) =>
Message ps st st' -> Client ps pl st' m a -> Client ps pl st m a
Yield Message (ChainSync header point tip) 'StIdle ('StNext 'StCanAwait)
forall {k} {k1} {k2} (header :: k) (point :: k1) (tip :: k2).
Message (ChainSync header point tip) 'StIdle ('StNext 'StCanAwait)
MsgRequestNext (Client
   (ChainSync header point tip)
   'NonPipelined
   ('StNext 'StCanAwait)
   m
   a
 -> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a)
-> Client
     (ChainSync header point tip)
     'NonPipelined
     ('StNext 'StCanAwait)
     m
     a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall a b. (a -> b) -> a -> b
$
        (forall (st' :: ChainSync header point tip).
 Message (ChainSync header point tip) ('StNext 'StCanAwait) st'
 -> Client (ChainSync header point tip) 'NonPipelined st' m a)
-> Client
     (ChainSync header point tip)
     'NonPipelined
     ('StNext 'StCanAwait)
     m
     a
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'ServerAgency,
 Outstanding pl ~ 'Z) =>
(forall (st' :: ps). Message ps st st' -> Client ps pl st' m a)
-> Client ps pl st m a
Await ((forall (st' :: ChainSync header point tip).
  Message (ChainSync header point tip) ('StNext 'StCanAwait) st'
  -> Client (ChainSync header point tip) 'NonPipelined st' m a)
 -> Client
      (ChainSync header point tip)
      'NonPipelined
      ('StNext 'StCanAwait)
      m
      a)
-> (forall (st' :: ChainSync header point tip).
    Message (ChainSync header point tip) ('StNext 'StCanAwait) st'
    -> Client (ChainSync header point tip) 'NonPipelined st' m a)
-> Client
     (ChainSync header point tip)
     'NonPipelined
     ('StNext 'StCanAwait)
     m
     a
forall a b. (a -> b) -> a -> b
$ \Message (ChainSync header point tip) ('StNext 'StCanAwait) st'
resp ->
        case Message (ChainSync header point tip) ('StNext 'StCanAwait) st'
resp of
          MsgRollForward header1
header tip1
tip ->
              ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall header point tip (m :: * -> *) a.
Monad m =>
ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
chainSyncClientPeer (header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward header
header1
header tip
tip1
tip)
            where
              ClientStNext{header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward :: forall header point tip (m :: * -> *) a.
ClientStNext header point tip m a
-> header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward :: header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward} = ClientStNext header point tip m a
stNext

          MsgRollBackward point1
pRollback tip1
tip ->
              ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall header point tip (m :: * -> *) a.
Monad m =>
ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
chainSyncClientPeer (point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward point
point1
pRollback tip
tip1
tip)
            where
              ClientStNext{point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward :: forall header point tip (m :: * -> *) a.
ClientStNext header point tip m a
-> point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward :: point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward} = ClientStNext header point tip m a
stNext

          -- This code could be factored more easily by changing the protocol type
          -- to put both roll forward and back under a single constructor.
          Message (ChainSync header point tip) ('StNext 'StCanAwait) st'
R:MessageChainSyncfromto
  (*) (*) (*) header point tip ('StNext 'StCanAwait) st'
MsgAwaitReply ->
            m (Client (ChainSync header point tip) 'NonPipelined st' m a)
-> Client (ChainSync header point tip) 'NonPipelined st' m a
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
m (Client ps pl st m a) -> Client ps pl st m a
Effect (m (Client (ChainSync header point tip) 'NonPipelined st' m a)
 -> Client (ChainSync header point tip) 'NonPipelined st' m a)
-> m (Client (ChainSync header point tip) 'NonPipelined st' m a)
-> Client (ChainSync header point tip) 'NonPipelined st' m a
forall a b. (a -> b) -> a -> b
$ do
              m ()
stAwait
              Client (ChainSync header point tip) 'NonPipelined st' m a
-> m (Client (ChainSync header point tip) 'NonPipelined st' m a)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Client (ChainSync header point tip) 'NonPipelined st' m a
 -> m (Client (ChainSync header point tip) 'NonPipelined st' m a))
-> Client (ChainSync header point tip) 'NonPipelined st' m a
-> m (Client (ChainSync header point tip) 'NonPipelined st' m a)
forall a b. (a -> b) -> a -> b
$ (forall (st' :: ChainSync header point tip).
 Message (ChainSync header point tip) st' st'
 -> Client (ChainSync header point tip) 'NonPipelined st' m a)
-> Client (ChainSync header point tip) 'NonPipelined st' m a
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'ServerAgency,
 Outstanding pl ~ 'Z) =>
(forall (st' :: ps). Message ps st st' -> Client ps pl st' m a)
-> Client ps pl st m a
Await ((forall (st' :: ChainSync header point tip).
  Message (ChainSync header point tip) st' st'
  -> Client (ChainSync header point tip) 'NonPipelined st' m a)
 -> Client (ChainSync header point tip) 'NonPipelined st' m a)
-> (forall (st' :: ChainSync header point tip).
    Message (ChainSync header point tip) st' st'
    -> Client (ChainSync header point tip) 'NonPipelined st' m a)
-> Client (ChainSync header point tip) 'NonPipelined st' m a
forall a b. (a -> b) -> a -> b
$ \Message (ChainSync header point tip) st' st'
resp' ->
                case Message (ChainSync header point tip) st' st'
resp' of
                  MsgRollForward header1
header tip1
tip ->
                      ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall header point tip (m :: * -> *) a.
Monad m =>
ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
chainSyncClientPeer (header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward header
header1
header tip
tip1
tip)
                    where
                      ClientStNext{header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward :: forall header point tip (m :: * -> *) a.
ClientStNext header point tip m a
-> header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward :: header -> tip -> ChainSyncClient header point tip m a
recvMsgRollForward} = ClientStNext header point tip m a
stNext
                  MsgRollBackward point1
pRollback tip1
tip ->
                      ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall header point tip (m :: * -> *) a.
Monad m =>
ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
chainSyncClientPeer (point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward point
point1
pRollback tip
tip1
tip)
                    where
                      ClientStNext{point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward :: forall header point tip (m :: * -> *) a.
ClientStNext header point tip m a
-> point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward :: point -> tip -> ChainSyncClient header point tip m a
recvMsgRollBackward} = ClientStNext header point tip m a
stNext

    chainSyncClientPeer_ (SendMsgFindIntersect [point]
points ClientStIntersect header point tip m a
stIntersect) =
        Message (ChainSync header point tip) 'StIdle 'StIntersect
-> Client
     (ChainSync header point tip) 'NonPipelined 'StIntersect m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a
       (st' :: ps).
(StateTokenI st, StateTokenI st', StateAgency st ~ 'ClientAgency,
 Outstanding pl ~ 'Z) =>
Message ps st st' -> Client ps pl st' m a -> Client ps pl st m a
Yield ([point]
-> Message (ChainSync header point tip) 'StIdle 'StIntersect
forall {k} {k2} point1 (header :: k) (tip :: k2).
[point1]
-> Message (ChainSync header point1 tip) 'StIdle 'StIntersect
MsgFindIntersect [point]
points) (Client (ChainSync header point tip) 'NonPipelined 'StIntersect m a
 -> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a)
-> Client
     (ChainSync header point tip) 'NonPipelined 'StIntersect m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall a b. (a -> b) -> a -> b
$
        (forall (st' :: ChainSync header point tip).
 Message (ChainSync header point tip) 'StIntersect st'
 -> Client (ChainSync header point tip) 'NonPipelined st' m a)
-> Client
     (ChainSync header point tip) 'NonPipelined 'StIntersect m a
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'ServerAgency,
 Outstanding pl ~ 'Z) =>
(forall (st' :: ps). Message ps st st' -> Client ps pl st' m a)
-> Client ps pl st m a
Await ((forall (st' :: ChainSync header point tip).
  Message (ChainSync header point tip) 'StIntersect st'
  -> Client (ChainSync header point tip) 'NonPipelined st' m a)
 -> Client
      (ChainSync header point tip) 'NonPipelined 'StIntersect m a)
-> (forall (st' :: ChainSync header point tip).
    Message (ChainSync header point tip) 'StIntersect st'
    -> Client (ChainSync header point tip) 'NonPipelined st' m a)
-> Client
     (ChainSync header point tip) 'NonPipelined 'StIntersect m a
forall a b. (a -> b) -> a -> b
$ \Message (ChainSync header point tip) 'StIntersect st'
resp ->
        case Message (ChainSync header point tip) 'StIntersect st'
resp of
          MsgIntersectFound point1
pIntersect tip1
tip ->
            ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall header point tip (m :: * -> *) a.
Monad m =>
ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
chainSyncClientPeer (point -> tip -> ChainSyncClient header point tip m a
recvMsgIntersectFound point
point1
pIntersect tip
tip1
tip)

          MsgIntersectNotFound tip1
tip ->
            ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall header point tip (m :: * -> *) a.
Monad m =>
ChainSyncClient header point tip m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
chainSyncClientPeer (tip -> ChainSyncClient header point tip m a
recvMsgIntersectNotFound tip
tip1
tip)
      where
        ClientStIntersect {
          point -> tip -> ChainSyncClient header point tip m a
recvMsgIntersectFound :: forall header point tip (m :: * -> *) a.
ClientStIntersect header point tip m a
-> point -> tip -> ChainSyncClient header point tip m a
recvMsgIntersectFound :: point -> tip -> ChainSyncClient header point tip m a
recvMsgIntersectFound,
          tip -> ChainSyncClient header point tip m a
recvMsgIntersectNotFound :: forall header point tip (m :: * -> *) a.
ClientStIntersect header point tip m a
-> tip -> ChainSyncClient header point tip m a
recvMsgIntersectNotFound :: tip -> ChainSyncClient header point tip m a
recvMsgIntersectNotFound
        } = ClientStIntersect header point tip m a
stIntersect

    chainSyncClientPeer_ (SendMsgDone a
a) =
      Message (ChainSync header point tip) 'StIdle 'StDone
-> Client (ChainSync header point tip) 'NonPipelined 'StDone m a
-> Client (ChainSync header point tip) 'NonPipelined 'StIdle m a
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a
       (st' :: ps).
(StateTokenI st, StateTokenI st', StateAgency st ~ 'ClientAgency,
 Outstanding pl ~ 'Z) =>
Message ps st st' -> Client ps pl st' m a -> Client ps pl st m a
Yield Message (ChainSync header point tip) 'StIdle 'StDone
forall {k} {k1} {k2} (header :: k) (point :: k1) (tip :: k2).
Message (ChainSync header point tip) 'StIdle 'StDone
MsgDone (a -> Client (ChainSync header point tip) 'NonPipelined 'StDone m a
forall ps (pl :: IsPipelined) (st :: ps) (m :: * -> *) a.
(StateTokenI st, StateAgency st ~ 'NobodyAgency,
 Outstanding pl ~ 'Z) =>
a -> Client ps pl st m a
Done a
a)