{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
module Cardano.Rpc.Server.Internal.UtxoRpc.WaitForTx
( waitForTxMethod
, maxWaitForTxRefs
, parseRequestRefs
, waitForTxIdleTimeout
, idleTimeLeft
, nextIdleDeadline
, idleDeadlineAfterStep
, DrainedChange (..)
, drainedBlocks
, WaitForTxEvent (..)
, WaitForTxState (..)
, initialWaitForTxState
, stepWaitForTx
)
where
import Cardano.Api
import Cardano.Api.Consensus qualified as Consensus
import Cardano.Rpc.Proto.Api.UtxoRpc.Submit qualified as U5c
import Cardano.Rpc.Server.Internal.Error
import Cardano.Rpc.Server.Internal.Monad
import Cardano.Rpc.Server.NodeKernelAccess
import Cardano.Ledger.Core qualified as L
import Ouroboros.Consensus.Mempool.API qualified as Consensus (MempoolSnapshot (snapshotHasTx))
import RIO
import Data.ByteString qualified as BS
import Data.ProtoLens (defMessage)
import Data.Set qualified as Set
import Data.Time.Clock (DiffTime)
import Data.Traversable (mapAccumL)
import Network.GRPC.Spec
( GrpcError (GrpcDeadlineExceeded, GrpcInvalidArgument)
, NextElem (NextElem, NoNextElem)
, Proto (Proto)
)
waitForTxMethod
:: forall e m
. MonadRpc e m
=> Proto U5c.WaitForTxRequest
-> (NextElem (Proto U5c.WaitForTxResponse) -> IO ())
-> m ()
waitForTxMethod :: forall e (m :: * -> *).
MonadRpc e m =>
Proto WaitForTxRequest
-> (NextElem (Proto WaitForTxResponse) -> IO ()) -> m ()
waitForTxMethod Proto WaitForTxRequest
request NextElem (Proto WaitForTxResponse) -> IO ()
send = do
refs <- [ByteString] -> m (Set TxId)
forall (m :: * -> *). MonadIO m => [ByteString] -> m (Set TxId)
parseRequestRefs ([ByteString] -> m (Set TxId)) -> [ByteString] -> m (Set TxId)
forall a b. (a -> b) -> a -> b
$ Proto WaitForTxRequest
request Proto WaitForTxRequest
-> Getting [ByteString] (Proto WaitForTxRequest) [ByteString]
-> [ByteString]
forall s a. s -> Getting a s a -> a
^. Getting [ByteString] (Proto WaitForTxRequest) [ByteString]
forall (f :: * -> *) s a.
(Functor f, HasField s "ref" a) =>
LensLike' f s a
U5c.ref
case initialWaitForTxState refs of
Maybe WaitForTxState
Nothing -> IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ NextElem (Proto WaitForTxResponse) -> IO ()
send NextElem (Proto WaitForTxResponse)
forall a. NextElem a
NoNextElem
Just WaitForTxState
state -> do
nodeKernelAccess <- m NodeKernelAccess
forall e (m :: * -> *). MonadRpc e m => m NodeKernelAccess
grabNodeKernelAccess
withBlockFollower nodeKernelAccess $ \ChainFollower BlockInMode
follower -> do
tip <- NodeKernelAccess -> ChainFollower BlockInMode -> m ChainPoint
forall (m :: * -> *) a.
MonadIO m =>
NodeKernelAccess -> ChainFollower a -> m ChainPoint
positionFollowerAtCurrentTip NodeKernelAccess
nodeKernelAccess ChainFollower BlockInMode
follower
now <- getMonotonicDiffTime
waitLoop nodeKernelAccess follower state tip (now + waitForTxIdleTimeout)
where
waitLoop
:: NodeKernelAccess
-> ChainFollower BlockInMode
-> WaitForTxState
-> ChainPoint
-> DiffTime
-> m ()
waitLoop :: NodeKernelAccess
-> ChainFollower BlockInMode
-> WaitForTxState
-> ChainPoint
-> DiffTime
-> m ()
waitLoop NodeKernelAccess
nodeKernelAccess ChainFollower BlockInMode
follower WaitForTxState
state ChainPoint
lastTip DiffTime
deadline = do
now <- m DiffTime
forall (m :: * -> *). MonadIO m => m DiffTime
getMonotonicDiffTime
(change, expired) <- case idleTimeLeft deadline now of
Maybe Int
Nothing -> (,Bool
True) (NodeChange -> (NodeChange, Bool))
-> m NodeChange -> m (NodeChange, Bool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m NodeChange
readyChangeOrIdleTimeout
Just Int
timeLeft ->
Int -> m NodeChange -> m (Maybe NodeChange)
forall (m :: * -> *) a.
MonadUnliftIO m =>
Int -> m a -> m (Maybe a)
timeout Int
timeLeft (STM NodeChange -> m NodeChange
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically STM NodeChange
nextChange) m (Maybe NodeChange)
-> (Maybe NodeChange -> m (NodeChange, Bool))
-> m (NodeChange, Bool)
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe NodeChange
Nothing -> (,Bool
True) (NodeChange -> (NodeChange, Bool))
-> m NodeChange -> m (NodeChange, Bool)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m NodeChange
readyChangeOrIdleTimeout
Just NodeChange
waited -> (NodeChange, Bool) -> m (NodeChange, Bool)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (NodeChange
waited, Bool
False)
(event, tip) <- case change of
TipMoved ChainPoint
newTip -> do
blocks <- ChainFollower BlockInMode -> Set TxId -> m [Set TxId]
forall (m :: * -> *).
MonadIO m =>
ChainFollower BlockInMode -> Set TxId -> m [Set TxId]
drainFollower ChainFollower BlockInMode
follower (Set TxId -> m [Set TxId]) -> Set TxId -> m [Set TxId]
forall a b. (a -> b) -> a -> b
$ WaitForTxState -> Set TxId
pendingRefs WaitForTxState
state
pure (TipBlocks blocks, newTip)
MempoolChanged Set TxId
inMempool -> (WaitForTxEvent, ChainPoint) -> m (WaitForTxEvent, ChainPoint)
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Set TxId -> WaitForTxEvent
MempoolMembership Set TxId
inMempool, ChainPoint
lastTip)
let (next, responses) = stepWaitForTx state event
liftIO $ mapM_ (send . NextElem) responses
sentAt <- getMonotonicDiffTime
case next of
Maybe WaitForTxState
Nothing -> IO () -> m ()
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ NextElem (Proto WaitForTxResponse) -> IO ()
send NextElem (Proto WaitForTxResponse)
forall a. NextElem a
NoNextElem
Just WaitForTxState
state' ->
m () -> (DiffTime -> m ()) -> Maybe DiffTime -> m ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe m ()
forall a. m a
throwIdleTimeout (NodeKernelAccess
-> ChainFollower BlockInMode
-> WaitForTxState
-> ChainPoint
-> DiffTime
-> m ()
waitLoop NodeKernelAccess
nodeKernelAccess ChainFollower BlockInMode
follower WaitForTxState
state' ChainPoint
tip) (Maybe DiffTime -> m ()) -> Maybe DiffTime -> m ()
forall a b. (a -> b) -> a -> b
$
Bool
-> DiffTime
-> DiffTime
-> [Proto WaitForTxResponse]
-> Maybe DiffTime
idleDeadlineAfterStep Bool
expired DiffTime
sentAt DiffTime
deadline [Proto WaitForTxResponse]
responses
where
nextChange :: STM NodeChange
nextChange :: STM NodeChange
nextChange = NodeKernelAccess -> WaitForTxState -> ChainPoint -> STM NodeChange
nextNodeChange NodeKernelAccess
nodeKernelAccess WaitForTxState
state ChainPoint
lastTip
readyChangeOrIdleTimeout :: m NodeChange
readyChangeOrIdleTimeout :: m NodeChange
readyChangeOrIdleTimeout = m NodeChange
-> (NodeChange -> m NodeChange) -> Maybe NodeChange -> m NodeChange
forall b a. b -> (a -> b) -> Maybe a -> b
maybe m NodeChange
forall a. m a
throwIdleTimeout NodeChange -> m NodeChange
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe NodeChange -> m NodeChange)
-> m (Maybe NodeChange) -> m NodeChange
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< STM (Maybe NodeChange) -> m (Maybe NodeChange)
forall (m :: * -> *) a. MonadIO m => STM a -> m a
atomically (STM NodeChange -> STM (Maybe NodeChange)
forall (f :: * -> *) a. Alternative f => f a -> f (Maybe a)
optional STM NodeChange
nextChange)
throwIdleTimeout :: m a
throwIdleTimeout :: forall a. m a
throwIdleTimeout =
GrpcError -> Text -> m a
forall (m :: * -> *) a. MonadIO m => GrpcError -> Text -> m a
throwGrpcErrorWithMessage
GrpcError
GrpcDeadlineExceeded
Text
"no WaitForTx update for 10 minutes, reopen the stream to keep waiting"
maxWaitForTxRefs :: Int
maxWaitForTxRefs :: Int
maxWaitForTxRefs = Int
500
parseRequestRefs :: MonadIO m => [ByteString] -> m (Set TxId)
parseRequestRefs :: forall (m :: * -> *). MonadIO m => [ByteString] -> m (Set TxId)
parseRequestRefs [ByteString]
refs = do
let refCount :: Int
refCount = [ByteString] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [ByteString]
refs
Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
refCount Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
maxWaitForTxRefs) (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$
GrpcError -> Text -> m ()
forall (m :: * -> *) a. MonadIO m => GrpcError -> Text -> m a
throwGrpcErrorWithMessage GrpcError
GrpcInvalidArgument (Text -> m ()) -> Text -> m ()
forall a b. (a -> b) -> a -> b
$
Text
"too many transaction refs: "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a. Show a => a -> Text
tshow Int
refCount
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
", maximum "
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a. Show a => a -> Text
tshow Int
maxWaitForTxRefs
Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"; batch your requests"
[TxId] -> Set TxId
forall a. Ord a => [a] -> Set a
Set.fromList ([TxId] -> Set TxId) -> m [TxId] -> m (Set TxId)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (ByteString -> m TxId) -> [ByteString] -> m [TxId]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse ByteString -> m TxId
forall (m :: * -> *). MonadIO m => ByteString -> m TxId
parseRef [ByteString]
refs
waitForTxIdleTimeout :: DiffTime
waitForTxIdleTimeout :: DiffTime
waitForTxIdleTimeout = DiffTime
10 DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
* DiffTime
60
idleTimeLeft
:: DiffTime
-> DiffTime
-> Maybe Int
idleTimeLeft :: DiffTime -> DiffTime -> Maybe Int
idleTimeLeft DiffTime
deadline DiffTime
now
| DiffTime
now DiffTime -> DiffTime -> Bool
forall a. Ord a => a -> a -> Bool
>= DiffTime
deadline = Maybe Int
forall a. Maybe a
Nothing
| Bool
otherwise = Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> (DiffTime -> Int) -> DiffTime -> Maybe Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DiffTime -> Int
toMicros (DiffTime -> Maybe Int) -> DiffTime -> Maybe Int
forall a b. (a -> b) -> a -> b
$ DiffTime
deadline DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
- DiffTime
now
nextIdleDeadline
:: DiffTime
-> DiffTime
-> [Proto U5c.WaitForTxResponse]
-> DiffTime
nextIdleDeadline :: DiffTime -> DiffTime -> [Proto WaitForTxResponse] -> DiffTime
nextIdleDeadline DiffTime
now DiffTime
deadline [Proto WaitForTxResponse]
responses
| [Proto WaitForTxResponse] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Proto WaitForTxResponse]
responses = DiffTime
deadline
| Bool
otherwise = DiffTime
now DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
+ DiffTime
waitForTxIdleTimeout
idleDeadlineAfterStep
:: Bool
-> DiffTime
-> DiffTime
-> [Proto U5c.WaitForTxResponse]
-> Maybe DiffTime
idleDeadlineAfterStep :: Bool
-> DiffTime
-> DiffTime
-> [Proto WaitForTxResponse]
-> Maybe DiffTime
idleDeadlineAfterStep Bool
expired DiffTime
now DiffTime
deadline [Proto WaitForTxResponse]
responses
| Bool
expired Bool -> Bool -> Bool
&& [Proto WaitForTxResponse] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Proto WaitForTxResponse]
responses = Maybe DiffTime
forall a. Maybe a
Nothing
| Bool
otherwise = DiffTime -> Maybe DiffTime
forall a. a -> Maybe a
Just (DiffTime -> Maybe DiffTime) -> DiffTime -> Maybe DiffTime
forall a b. (a -> b) -> a -> b
$ DiffTime -> DiffTime -> [Proto WaitForTxResponse] -> DiffTime
nextIdleDeadline DiffTime
now DiffTime
deadline [Proto WaitForTxResponse]
responses
toMicros :: DiffTime -> Int
toMicros :: DiffTime -> Int
toMicros = DiffTime -> Int
forall b. Integral b => DiffTime -> b
forall a b. (RealFrac a, Integral b) => a -> b
ceiling (DiffTime -> Int) -> (DiffTime -> DiffTime) -> DiffTime -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (DiffTime -> DiffTime -> DiffTime
forall a. Num a => a -> a -> a
* DiffTime
1000000)
getMonotonicDiffTime :: MonadIO m => m DiffTime
getMonotonicDiffTime :: forall (m :: * -> *). MonadIO m => m DiffTime
getMonotonicDiffTime = Double -> DiffTime
forall a b. (Real a, Fractional b) => a -> b
realToFrac (Double -> DiffTime) -> m Double -> m DiffTime
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m Double
forall (m :: * -> *). MonadIO m => m Double
getMonotonicTime
data NodeChange
=
TipMoved ChainPoint
|
MempoolChanged (Set TxId)
nextNodeChange
:: NodeKernelAccess
-> WaitForTxState
-> ChainPoint
-> STM NodeChange
nextNodeChange :: NodeKernelAccess -> WaitForTxState -> ChainPoint -> STM NodeChange
nextNodeChange NodeKernelAccess
nodeKernelAccess WaitForTxState{Set TxId
pendingRefs :: WaitForTxState -> Set TxId
pendingRefs :: Set TxId
pendingRefs, Set TxId
mempoolNotifiedRefs :: Set TxId
mempoolNotifiedRefs :: WaitForTxState -> Set TxId
mempoolNotifiedRefs} ChainPoint
lastTip =
STM NodeChange
tipMoved STM NodeChange -> STM NodeChange -> STM NodeChange
forall a. STM a -> STM a -> STM a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> STM NodeChange
mempoolChanged
where
tipMoved :: STM NodeChange
tipMoved :: STM NodeChange
tipMoved = do
tip <- NodeKernelAccess -> STM ChainPoint
readChainTipPoint NodeKernelAccess
nodeKernelAccess
checkSTM $ tip /= lastTip
pure $ TipMoved tip
mempoolChanged :: STM NodeChange
mempoolChanged :: STM NodeChange
mempoolChanged = do
AnyCardanoEra era <- NodeKernelAccess -> STM AnyCardanoEra
readCurrentEra NodeKernelAccess
nodeKernelAccess
snapshot <- readMempoolSnapshot nodeKernelAccess
let inMempool =
(TxId -> Bool) -> Set TxId -> Set TxId
forall a. (a -> Bool) -> Set a -> Set a
Set.filter
(MempoolSnapshot (CardanoBlock StandardCrypto)
-> GenTxId (CardanoBlock StandardCrypto) -> Bool
forall blk. MempoolSnapshot blk -> GenTxId blk -> Bool
Consensus.snapshotHasTx MempoolSnapshot (CardanoBlock StandardCrypto)
snapshot (GenTxId (CardanoBlock StandardCrypto) -> Bool)
-> (TxId -> GenTxId (CardanoBlock StandardCrypto)) -> TxId -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TxIdInMode -> GenTxId (CardanoBlock StandardCrypto)
forall block.
(CardanoBlock StandardCrypto ~ block) =>
TxIdInMode -> TxId (GenTx block)
Consensus.toConsensusTxId (TxIdInMode -> GenTxId (CardanoBlock StandardCrypto))
-> (TxId -> TxIdInMode)
-> TxId
-> GenTxId (CardanoBlock StandardCrypto)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CardanoEra era -> TxId -> TxIdInMode
forall era. CardanoEra era -> TxId -> TxIdInMode
Consensus.TxIdInMode CardanoEra era
era)
Set TxId
pendingRefs
checkSTM $ inMempool /= mempoolNotifiedRefs
pure $ MempoolChanged inMempool
drainFollower
:: forall m
. MonadIO m
=> ChainFollower BlockInMode
-> Set TxId
-> m [Set TxId]
drainFollower :: forall (m :: * -> *).
MonadIO m =>
ChainFollower BlockInMode -> Set TxId -> m [Set TxId]
drainFollower ChainFollower{forall (m :: * -> *).
MonadIO m =>
m (Maybe (ChainChange BlockInMode))
tryNextChange :: forall (m :: * -> *).
MonadIO m =>
m (Maybe (ChainChange BlockInMode))
tryNextChange :: forall a.
ChainFollower a
-> forall (m :: * -> *). MonadIO m => m (Maybe (ChainChange a))
tryNextChange} Set TxId
pendingRefs = [DrainedChange] -> [Set TxId]
drainedBlocks ([DrainedChange] -> [Set TxId])
-> m [DrainedChange] -> m [Set TxId]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [DrainedChange] -> m [DrainedChange]
go []
where
go :: [DrainedChange] -> m [DrainedChange]
go :: [DrainedChange] -> m [DrainedChange]
go [DrainedChange]
changes =
m (Maybe (ChainChange BlockInMode))
forall (m :: * -> *).
MonadIO m =>
m (Maybe (ChainChange BlockInMode))
tryNextChange m (Maybe (ChainChange BlockInMode))
-> (Maybe (ChainChange BlockInMode) -> m [DrainedChange])
-> m [DrainedChange]
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe (ChainChange BlockInMode)
Nothing -> [DrainedChange] -> m [DrainedChange]
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ([DrainedChange] -> m [DrainedChange])
-> [DrainedChange] -> m [DrainedChange]
forall a b. (a -> b) -> a -> b
$ [DrainedChange] -> [DrainedChange]
forall a. [a] -> [a]
reverse [DrainedChange]
changes
Just (ChainApply blockInMode :: BlockInMode
blockInMode@(BlockInMode CardanoEra era
_ Block era
block)) -> do
let BlockHeader SlotNo
slot Hash BlockHeader
headerHash BlockNo
_ = Block era -> BlockHeader
forall era. Block era -> BlockHeader
getBlockHeader Block era
block
inBlock :: Set TxId
inBlock = Set TxId
pendingRefs Set TxId -> Set TxId -> Set TxId
forall a. Ord a => Set a -> Set a -> Set a
`Set.intersection` BlockInMode -> Set TxId
blockTxIds BlockInMode
blockInMode
[DrainedChange] -> m [DrainedChange]
go ([DrainedChange] -> m [DrainedChange])
-> [DrainedChange] -> m [DrainedChange]
forall a b. (a -> b) -> a -> b
$ ChainPoint -> Set TxId -> DrainedChange
DrainedBlock (SlotNo -> Hash BlockHeader -> ChainPoint
ChainPoint SlotNo
slot Hash BlockHeader
headerHash) Set TxId
inBlock DrainedChange -> [DrainedChange] -> [DrainedChange]
forall a. a -> [a] -> [a]
: [DrainedChange]
changes
Just (ChainRollBack ChainPoint
point) -> [DrainedChange] -> m [DrainedChange]
go ([DrainedChange] -> m [DrainedChange])
-> [DrainedChange] -> m [DrainedChange]
forall a b. (a -> b) -> a -> b
$ ChainPoint -> DrainedChange
DrainedRollBack ChainPoint
point DrainedChange -> [DrainedChange] -> [DrainedChange]
forall a. a -> [a] -> [a]
: [DrainedChange]
changes
data DrainedChange
=
DrainedBlock ChainPoint (Set TxId)
|
DrainedRollBack ChainPoint
deriving Int -> DrainedChange -> ShowS
[DrainedChange] -> ShowS
DrainedChange -> String
(Int -> DrainedChange -> ShowS)
-> (DrainedChange -> String)
-> ([DrainedChange] -> ShowS)
-> Show DrainedChange
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> DrainedChange -> ShowS
showsPrec :: Int -> DrainedChange -> ShowS
$cshow :: DrainedChange -> String
show :: DrainedChange -> String
$cshowList :: [DrainedChange] -> ShowS
showList :: [DrainedChange] -> ShowS
Show
drainedBlocks :: [DrainedChange] -> [Set TxId]
drainedBlocks :: [DrainedChange] -> [Set TxId]
drainedBlocks = [Set TxId] -> [Set TxId]
forall a. [a] -> [a]
reverse ([Set TxId] -> [Set TxId])
-> ([DrainedChange] -> [Set TxId]) -> [DrainedChange] -> [Set TxId]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ChainPoint, Set TxId) -> Set TxId)
-> [(ChainPoint, Set TxId)] -> [Set TxId]
forall a b. (a -> b) -> [a] -> [b]
map (ChainPoint, Set TxId) -> Set TxId
forall a b. (a, b) -> b
snd ([(ChainPoint, Set TxId)] -> [Set TxId])
-> ([DrainedChange] -> [(ChainPoint, Set TxId)])
-> [DrainedChange]
-> [Set TxId]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([(ChainPoint, Set TxId)]
-> DrainedChange -> [(ChainPoint, Set TxId)])
-> [(ChainPoint, Set TxId)]
-> [DrainedChange]
-> [(ChainPoint, Set TxId)]
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' [(ChainPoint, Set TxId)]
-> DrainedChange -> [(ChainPoint, Set TxId)]
step []
where
step :: [(ChainPoint, Set TxId)] -> DrainedChange -> [(ChainPoint, Set TxId)]
step :: [(ChainPoint, Set TxId)]
-> DrainedChange -> [(ChainPoint, Set TxId)]
step [(ChainPoint, Set TxId)]
blocks = \case
DrainedBlock ChainPoint
point Set TxId
refs -> (ChainPoint
point, Set TxId
refs) (ChainPoint, Set TxId)
-> [(ChainPoint, Set TxId)] -> [(ChainPoint, Set TxId)]
forall a. a -> [a] -> [a]
: [(ChainPoint, Set TxId)]
blocks
DrainedRollBack ChainPoint
point -> ((ChainPoint, Set TxId) -> Bool)
-> [(ChainPoint, Set TxId)] -> [(ChainPoint, Set TxId)]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile ((ChainPoint -> ChainPoint -> Bool
forall a. Eq a => a -> a -> Bool
/= ChainPoint
point) (ChainPoint -> Bool)
-> ((ChainPoint, Set TxId) -> ChainPoint)
-> (ChainPoint, Set TxId)
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ChainPoint, Set TxId) -> ChainPoint
forall a b. (a, b) -> a
fst) [(ChainPoint, Set TxId)]
blocks
data WaitForTxEvent
=
TipBlocks [Set TxId]
|
MempoolMembership (Set TxId)
deriving (WaitForTxEvent -> WaitForTxEvent -> Bool
(WaitForTxEvent -> WaitForTxEvent -> Bool)
-> (WaitForTxEvent -> WaitForTxEvent -> Bool) -> Eq WaitForTxEvent
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: WaitForTxEvent -> WaitForTxEvent -> Bool
== :: WaitForTxEvent -> WaitForTxEvent -> Bool
$c/= :: WaitForTxEvent -> WaitForTxEvent -> Bool
/= :: WaitForTxEvent -> WaitForTxEvent -> Bool
Eq, Int -> WaitForTxEvent -> ShowS
[WaitForTxEvent] -> ShowS
WaitForTxEvent -> String
(Int -> WaitForTxEvent -> ShowS)
-> (WaitForTxEvent -> String)
-> ([WaitForTxEvent] -> ShowS)
-> Show WaitForTxEvent
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> WaitForTxEvent -> ShowS
showsPrec :: Int -> WaitForTxEvent -> ShowS
$cshow :: WaitForTxEvent -> String
show :: WaitForTxEvent -> String
$cshowList :: [WaitForTxEvent] -> ShowS
showList :: [WaitForTxEvent] -> ShowS
Show)
blockTxIds :: BlockInMode -> Set TxId
blockTxIds :: BlockInMode -> Set TxId
blockTxIds (BlockInMode CardanoEra era
_ Block era
block) = case Block era
block of
ByronBlock{} -> Set TxId
forall a. Set a
Set.empty
ShelleyBlock ShelleyBasedEra era
sbe ShelleyBlock (ConsensusProtocol era) (ShelleyLedgerEra era)
_ ->
ShelleyBasedEra era
-> (ShelleyBasedEraConstraints era => Set TxId) -> Set TxId
forall era a.
ShelleyBasedEra era -> (ShelleyBasedEraConstraints era => a) -> a
shelleyBasedEraConstraints ShelleyBasedEra era
sbe ((ShelleyBasedEraConstraints era => Set TxId) -> Set TxId)
-> (ShelleyBasedEraConstraints era => Set TxId) -> Set TxId
forall a b. (a -> b) -> a -> b
$
[TxId] -> Set TxId
forall a. Ord a => [a] -> Set a
Set.fromList
[TxId -> TxId
fromShelleyTxId (Tx TopTx (ShelleyLedgerEra era) -> TxId
forall era (l :: TxLevel). EraTx era => Tx l era -> TxId
L.txIdTx Tx TopTx (ShelleyLedgerEra era)
ledgerTx) | ShelleyTx ShelleyBasedEra era
_ Tx TopTx (ShelleyLedgerEra era)
ledgerTx <- Block era -> [Tx era]
forall era. Block era -> [Tx era]
getBlockTxs Block era
block]
parseRef :: forall m. MonadIO m => ByteString -> m TxId
parseRef :: forall (m :: * -> *). MonadIO m => ByteString -> m TxId
parseRef ByteString
bytes =
(SerialiseAsRawBytesError -> m TxId)
-> (TxId -> m TxId)
-> Either SerialiseAsRawBytesError TxId
-> m TxId
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (m TxId -> SerialiseAsRawBytesError -> m TxId
forall a b. a -> b -> a
const m TxId
throwInvalidRef) TxId -> m TxId
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either SerialiseAsRawBytesError TxId -> m TxId)
-> Either SerialiseAsRawBytesError TxId -> m TxId
forall a b. (a -> b) -> a -> b
$ AsType TxId -> ByteString -> Either SerialiseAsRawBytesError TxId
forall a.
SerialiseAsRawBytes a =>
AsType a -> ByteString -> Either SerialiseAsRawBytesError a
deserialiseFromRawBytes AsType TxId
AsTxId ByteString
bytes
where
throwInvalidRef :: m TxId
throwInvalidRef :: m TxId
throwInvalidRef =
GrpcError -> Text -> m TxId
forall (m :: * -> *) a. MonadIO m => GrpcError -> Text -> m a
throwGrpcErrorWithMessage GrpcError
GrpcInvalidArgument (Text -> m TxId) -> Text -> m TxId
forall a b. (a -> b) -> a -> b
$
Text
"invalid transaction id (" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Int -> Text
forall a. Show a => a -> Text
tshow (ByteString -> Int
BS.length ByteString
bytes) Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" bytes)"
data WaitForTxState = WaitForTxState
{ WaitForTxState -> Set TxId
pendingRefs :: !(Set TxId)
, WaitForTxState -> Set TxId
mempoolNotifiedRefs :: !(Set TxId)
}
deriving (WaitForTxState -> WaitForTxState -> Bool
(WaitForTxState -> WaitForTxState -> Bool)
-> (WaitForTxState -> WaitForTxState -> Bool) -> Eq WaitForTxState
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: WaitForTxState -> WaitForTxState -> Bool
== :: WaitForTxState -> WaitForTxState -> Bool
$c/= :: WaitForTxState -> WaitForTxState -> Bool
/= :: WaitForTxState -> WaitForTxState -> Bool
Eq, Int -> WaitForTxState -> ShowS
[WaitForTxState] -> ShowS
WaitForTxState -> String
(Int -> WaitForTxState -> ShowS)
-> (WaitForTxState -> String)
-> ([WaitForTxState] -> ShowS)
-> Show WaitForTxState
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> WaitForTxState -> ShowS
showsPrec :: Int -> WaitForTxState -> ShowS
$cshow :: WaitForTxState -> String
show :: WaitForTxState -> String
$cshowList :: [WaitForTxState] -> ShowS
showList :: [WaitForTxState] -> ShowS
Show)
initialWaitForTxState :: Set TxId -> Maybe WaitForTxState
initialWaitForTxState :: Set TxId -> Maybe WaitForTxState
initialWaitForTxState Set TxId
refs =
WaitForTxState -> Maybe WaitForTxState
whilePending WaitForTxState{pendingRefs :: Set TxId
pendingRefs = Set TxId
refs, mempoolNotifiedRefs :: Set TxId
mempoolNotifiedRefs = Set TxId
forall a. Set a
Set.empty}
stepWaitForTx
:: WaitForTxState
-> WaitForTxEvent
-> (Maybe WaitForTxState, [Proto U5c.WaitForTxResponse])
stepWaitForTx :: WaitForTxState
-> WaitForTxEvent
-> (Maybe WaitForTxState, [Proto WaitForTxResponse])
stepWaitForTx WaitForTxState
state =
(WaitForTxState -> Maybe WaitForTxState)
-> (WaitForTxState, [Proto WaitForTxResponse])
-> (Maybe WaitForTxState, [Proto WaitForTxResponse])
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first WaitForTxState -> Maybe WaitForTxState
whilePending ((WaitForTxState, [Proto WaitForTxResponse])
-> (Maybe WaitForTxState, [Proto WaitForTxResponse]))
-> (WaitForTxEvent -> (WaitForTxState, [Proto WaitForTxResponse]))
-> WaitForTxEvent
-> (Maybe WaitForTxState, [Proto WaitForTxResponse])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. \case
TipBlocks [Set TxId]
blocks -> [[Proto WaitForTxResponse]] -> [Proto WaitForTxResponse]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[Proto WaitForTxResponse]] -> [Proto WaitForTxResponse])
-> (WaitForTxState, [[Proto WaitForTxResponse]])
-> (WaitForTxState, [Proto WaitForTxResponse])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (WaitForTxState
-> Set TxId -> (WaitForTxState, [Proto WaitForTxResponse]))
-> WaitForTxState
-> [Set TxId]
-> (WaitForTxState, [[Proto WaitForTxResponse]])
forall (t :: * -> *) s a b.
Traversable t =>
(s -> a -> (s, b)) -> s -> t a -> (s, t b)
mapAccumL WaitForTxState
-> Set TxId -> (WaitForTxState, [Proto WaitForTxResponse])
confirmBlock WaitForTxState
state [Set TxId]
blocks
MempoolMembership Set TxId
inMempool -> WaitForTxState
-> Set TxId -> (WaitForTxState, [Proto WaitForTxResponse])
announceMempool WaitForTxState
state Set TxId
inMempool
confirmBlock
:: WaitForTxState
-> Set TxId
-> (WaitForTxState, [Proto U5c.WaitForTxResponse])
confirmBlock :: WaitForTxState
-> Set TxId -> (WaitForTxState, [Proto WaitForTxResponse])
confirmBlock WaitForTxState{Set TxId
pendingRefs :: WaitForTxState -> Set TxId
pendingRefs :: Set TxId
pendingRefs, Set TxId
mempoolNotifiedRefs :: WaitForTxState -> Set TxId
mempoolNotifiedRefs :: Set TxId
mempoolNotifiedRefs} Set TxId
block =
( WaitForTxState
{ pendingRefs :: Set TxId
pendingRefs = Set TxId
pendingRefs Set TxId -> Set TxId -> Set TxId
forall a. Ord a => Set a -> Set a -> Set a
`Set.difference` Set TxId
confirmed
, mempoolNotifiedRefs :: Set TxId
mempoolNotifiedRefs = Set TxId
mempoolNotifiedRefs Set TxId -> Set TxId -> Set TxId
forall a. Ord a => Set a -> Set a -> Set a
`Set.difference` Set TxId
confirmed
}
, [ Proto WaitForTxResponse
forall msg. Message msg => msg
defMessage
Proto WaitForTxResponse
-> (Proto WaitForTxResponse -> Proto WaitForTxResponse)
-> Proto WaitForTxResponse
forall a b. a -> (a -> b) -> b
& LensLike' Identity (Proto WaitForTxResponse) ByteString
forall (f :: * -> *) s a.
(Functor f, HasField s "ref" a) =>
LensLike' f s a
U5c.ref LensLike' Identity (Proto WaitForTxResponse) ByteString
-> ByteString -> Proto WaitForTxResponse -> Proto WaitForTxResponse
forall s t a b. ASetter s t a b -> b -> s -> t
.~ TxId -> ByteString
forall a. SerialiseAsRawBytes a => a -> ByteString
serialiseToRawBytes TxId
ref
Proto WaitForTxResponse
-> (Proto WaitForTxResponse -> Proto WaitForTxResponse)
-> Proto WaitForTxResponse
forall a b. a -> (a -> b) -> b
& LensLike' Identity (Proto WaitForTxResponse) (Proto Stage)
forall (f :: * -> *) s a.
(Functor f, HasField s "stage" a) =>
LensLike' f s a
U5c.stage LensLike' Identity (Proto WaitForTxResponse) (Proto Stage)
-> Proto Stage
-> Proto WaitForTxResponse
-> Proto WaitForTxResponse
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Stage -> Proto Stage
forall msg. msg -> Proto msg
Proto Stage
U5c.STAGE_CONFIRMED
| TxId
ref <- Set TxId -> [TxId]
forall a. Set a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList Set TxId
confirmed
]
)
where
confirmed :: Set TxId
confirmed :: Set TxId
confirmed = Set TxId
pendingRefs Set TxId -> Set TxId -> Set TxId
forall a. Ord a => Set a -> Set a -> Set a
`Set.intersection` Set TxId
block
announceMempool
:: WaitForTxState
-> Set TxId
-> (WaitForTxState, [Proto U5c.WaitForTxResponse])
announceMempool :: WaitForTxState
-> Set TxId -> (WaitForTxState, [Proto WaitForTxResponse])
announceMempool state :: WaitForTxState
state@WaitForTxState{Set TxId
pendingRefs :: WaitForTxState -> Set TxId
pendingRefs :: Set TxId
pendingRefs, Set TxId
mempoolNotifiedRefs :: WaitForTxState -> Set TxId
mempoolNotifiedRefs :: Set TxId
mempoolNotifiedRefs} Set TxId
inMempool =
( WaitForTxState
state{mempoolNotifiedRefs = present}
, [ Proto WaitForTxResponse
forall msg. Message msg => msg
defMessage
Proto WaitForTxResponse
-> (Proto WaitForTxResponse -> Proto WaitForTxResponse)
-> Proto WaitForTxResponse
forall a b. a -> (a -> b) -> b
& LensLike' Identity (Proto WaitForTxResponse) ByteString
forall (f :: * -> *) s a.
(Functor f, HasField s "ref" a) =>
LensLike' f s a
U5c.ref LensLike' Identity (Proto WaitForTxResponse) ByteString
-> ByteString -> Proto WaitForTxResponse -> Proto WaitForTxResponse
forall s t a b. ASetter s t a b -> b -> s -> t
.~ TxId -> ByteString
forall a. SerialiseAsRawBytes a => a -> ByteString
serialiseToRawBytes TxId
ref
Proto WaitForTxResponse
-> (Proto WaitForTxResponse -> Proto WaitForTxResponse)
-> Proto WaitForTxResponse
forall a b. a -> (a -> b) -> b
& LensLike' Identity (Proto WaitForTxResponse) (Proto Stage)
forall (f :: * -> *) s a.
(Functor f, HasField s "stage" a) =>
LensLike' f s a
U5c.stage LensLike' Identity (Proto WaitForTxResponse) (Proto Stage)
-> Proto Stage
-> Proto WaitForTxResponse
-> Proto WaitForTxResponse
forall s t a b. ASetter s t a b -> b -> s -> t
.~ Stage -> Proto Stage
forall msg. msg -> Proto msg
Proto Stage
U5c.STAGE_MEMPOOL
| TxId
ref <- Set TxId -> [TxId]
forall a. Set a -> [a]
forall (t :: * -> *) a. Foldable t => t a -> [a]
toList (Set TxId -> [TxId]) -> Set TxId -> [TxId]
forall a b. (a -> b) -> a -> b
$ Set TxId
present Set TxId -> Set TxId -> Set TxId
forall a. Ord a => Set a -> Set a -> Set a
`Set.difference` Set TxId
mempoolNotifiedRefs
]
)
where
present :: Set TxId
present :: Set TxId
present = Set TxId
pendingRefs Set TxId -> Set TxId -> Set TxId
forall a. Ord a => Set a -> Set a -> Set a
`Set.intersection` Set TxId
inMempool
whilePending :: WaitForTxState -> Maybe WaitForTxState
whilePending :: WaitForTxState -> Maybe WaitForTxState
whilePending state :: WaitForTxState
state@WaitForTxState{Set TxId
pendingRefs :: WaitForTxState -> Set TxId
pendingRefs :: Set TxId
pendingRefs}
| Set TxId -> Bool
forall a. Set a -> Bool
Set.null Set TxId
pendingRefs = Maybe WaitForTxState
forall a. Maybe a
Nothing
| Bool
otherwise = WaitForTxState -> Maybe WaitForTxState
forall a. a -> Maybe a
Just WaitForTxState
state