module Singular.Registry.Wait
( WaitStage (..)
, WaitFailure (..)
, WaitClock
, startWaitClock
, boundWait
, boundWaitSince
, boundWaitClosingSince
, submissionBound
, boundedSignedSubmission
, tryOutcome
) where
import Cardano.Ledger.Api.Tx (txIdTx)
import Cardano.Ledger.TxIn (TxId)
import Control.Exception
( SomeAsyncException
, SomeException
, fromException
, throwIO
, try
)
import GHC.Clock (getMonotonicTime)
import Singular.Registry.Signing (SignedTx, signedTx)
import Singular.Registry.WaitTypes (WaitFailure (..), WaitStage (..))
import System.Timeout (timeout)
newtype WaitClock = WaitClock Double
startWaitClock :: IO WaitClock
startWaitClock :: IO WaitClock
startWaitClock = Double -> WaitClock
WaitClock (Double -> WaitClock) -> IO Double -> IO WaitClock
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO Double
getMonotonicTime
boundWait :: WaitStage -> TxId -> Int -> IO a -> IO a
boundWait :: forall a. WaitStage -> TxId -> Int -> IO a -> IO a
boundWait WaitStage
stage TxId
tid Int
bound IO a
action = do
clock <- IO WaitClock
startWaitClock
boundWaitSince clock stage tid bound action
boundWaitSince
:: WaitClock -> WaitStage -> TxId -> Int -> IO a -> IO a
boundWaitSince :: forall a. WaitClock -> WaitStage -> TxId -> Int -> IO a -> IO a
boundWaitSince WaitClock
clock WaitStage
stage TxId
tid Int
bound IO a
action =
WaitClock
-> WaitStage -> TxId -> Int -> IO (Either Integer a) -> IO a
forall a.
WaitClock
-> WaitStage -> TxId -> Int -> IO (Either Integer a) -> IO a
boundWaitClosingSince WaitClock
clock WaitStage
stage TxId
tid Int
bound (a -> Either Integer a
forall a b. b -> Either a b
Right (a -> Either Integer a) -> IO a -> IO (Either Integer a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IO a
action)
boundWaitClosingSince
:: WaitClock
-> WaitStage
-> TxId
-> Int
-> IO (Either Integer a)
-> IO a
boundWaitClosingSince :: forall a.
WaitClock
-> WaitStage -> TxId -> Int -> IO (Either Integer a) -> IO a
boundWaitClosingSince (WaitClock Double
start) WaitStage
stage TxId
tid Int
bound IO (Either Integer a)
action = do
outcome <- Int -> IO (Either Integer a) -> IO (Maybe (Either Integer a))
forall a. Int -> IO a -> IO (Maybe a)
timeout (Int
bound Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
1_000_000) IO (Either Integer a)
action
end <- getMonotonicTime
let giveUp Maybe Integer
closedAt =
WaitFailure -> IO a
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO
WaitFailure
{ waitStage :: WaitStage
waitStage = WaitStage
stage
, waitTxId :: TxId
waitTxId = TxId
tid
, waitElapsed :: Double
waitElapsed = Double
end Double -> Double -> Double
forall a. Num a => a -> a -> a
- Double
start
, waitBound :: Int
waitBound = Int
bound
, waitClosedAt :: Maybe Integer
waitClosedAt = Maybe Integer
closedAt
}
case outcome of
Maybe (Either Integer a)
Nothing -> Maybe Integer -> IO a
forall {a}. Maybe Integer -> IO a
giveUp Maybe Integer
forall a. Maybe a
Nothing
Just (Left Integer
deadline) -> Maybe Integer -> IO a
forall {a}. Maybe Integer -> IO a
giveUp (Integer -> Maybe Integer
forall a. a -> Maybe a
Just Integer
deadline)
Just (Right a
a) -> a -> IO a
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a
submissionBound :: Int
submissionBound :: Int
submissionBound = Int
300
boundedSignedSubmission
:: Int -> (SignedTx -> IO a) -> SignedTx -> IO a
boundedSignedSubmission :: forall a. Int -> (SignedTx -> IO a) -> SignedTx -> IO a
boundedSignedSubmission Int
bound SignedTx -> IO a
submit SignedTx
signed =
WaitStage -> TxId -> Int -> IO a -> IO a
forall a. WaitStage -> TxId -> Int -> IO a -> IO a
boundWait
WaitStage
SubmissionWait
(Tx TopTx ConwayEra -> TxId
forall era (l :: TxLevel). EraTx era => Tx l era -> TxId
txIdTx (SignedTx -> Tx TopTx ConwayEra
signedTx SignedTx
signed))
Int
bound
(SignedTx -> IO a
submit SignedTx
signed)
tryOutcome :: IO a -> IO (Either SomeException a)
tryOutcome :: forall a. IO a -> IO (Either SomeException a)
tryOutcome IO a
action = do
outcome <- IO a -> IO (Either SomeException a)
forall e a. Exception e => IO a -> IO (Either e a)
try IO a
action
case outcome of
Right a
a -> Either SomeException a -> IO (Either SomeException a)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> Either SomeException a
forall a b. b -> Either a b
Right a
a)
Left SomeException
e
| Just (SomeAsyncException
_ :: SomeAsyncException) <- SomeException -> Maybe SomeAsyncException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e ->
SomeException -> IO (Either SomeException a)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
e
| Just (WaitFailure
_ :: WaitFailure) <- SomeException -> Maybe WaitFailure
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e -> SomeException -> IO (Either SomeException a)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO SomeException
e
| Bool
otherwise -> Either SomeException a -> IO (Either SomeException a)
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (SomeException -> Either SomeException a
forall a b. a -> Either a b
Left SomeException
e)