@@ -45,7 +45,7 @@ import Control.Monad.Trans.Class (lift)
4545import Control.Monad.Trans.Either (EitherT , eitherT , firstEitherT , newEitherT )
4646import Data.Aeson (ToJSON , Value (Array , Bool , Null , Number , Object , String ))
4747import Data.Aeson.Extras (encodeByteString )
48- import Data.Either ( fromRight )
48+ import Data.Function ( fix )
4949import Data.HashMap.Strict qualified as HM
5050import Data.Kind (Type )
5151import Data.Map qualified as Map
@@ -203,34 +203,62 @@ handlePABReq contractEnv req = do
203203 printBpiLog @ w Debug $ pretty resp
204204 pure resp
205205
206+ {- | Await till transaction status change to something from `Unknown`.
207+ Uses `chain-index` to query transaction by id.
208+ Important notes:
209+ * if transaction is not found in `chain-index` status considered to be `Unknown`
210+ * if transaction is found but `transactionStatus` failed to make status - status considered to be `Unknown`
211+ * uses `TxStatusPolling` to set `chain-index` polling interval and number of blocks to wait until timeout,
212+ if timeout is reached, returns whatever status it was able to get during last check
213+ -}
206214awaitTxStatusChange ::
207215 forall (w :: Type ) (effs :: [Type -> Type ]).
208216 Member (PABEffect w ) effs =>
209217 ContractEnvironment w ->
210218 Ledger. TxId ->
211219 Eff effs TxStatus
212220awaitTxStatusChange contractEnv txId = do
213- -- The depth (in blocks) after which a transaction cannot be rolled back anymore (from Plutus.ChainIndex.TxIdState)
214- let chainConstant = 8
215-
216- mTx <- queryChainIndexForTxState
217- case mTx of
218- Nothing -> pure Unknown
219- Just txState -> do
220- printBpiLog @ w Debug $ " Found transaction in node, waiting" <+> pretty chainConstant <+> " blocks for it to settle."
221- awaitNBlocks @ w contractEnv (chainConstant + 1 )
222- -- Check if the tx is still present in chain-index, in case of a rollback
223- -- we might not find it anymore.
224- ciTxState' <- queryChainIndexForTxState
225- case ciTxState' of
226- Nothing -> pure Unknown
227- Just _ -> do
228- blk <- fromInteger <$> currentBlock contractEnv
229- -- This will set the validity correctly based on the txState.
230- -- The tx will always be committed, as we wait for chainConstant + 1 blocks
231- let status = transactionStatus blk txState txId
232- pure $ fromRight Unknown status
221+ checkStartedBlock <- currentBlock contractEnv
222+ printBpiLog @ w Debug $ pretty $ " Awaiting status change for " ++ show txId
223+
224+ let txStatusPolling = contractEnv. cePABConfig. pcTxStatusPolling
225+ pollInterval = fromIntegral $ txStatusPolling. spInterval
226+ pollTimeout = txStatusPolling. spBlocksTimeOut
227+ cutOffBlock = checkStartedBlock + fromIntegral pollTimeout
228+
229+ fix $ \ loop -> do
230+ currBlock <- currentBlock contractEnv
231+ txStatus <- getStatus
232+ case (txStatus, currBlock > cutOffBlock) of
233+ (status, True ) -> do
234+ logDebug . mconcat . fmap mconcat $
235+ [ [" Timeout for waiting `TxId " , show txId, " ` status change reached" ]
236+ , [" - waited " , show pollTimeout, " blocks." ]
237+ , [" Current status: " , show status]
238+ ]
239+ return status
240+ (Unknown , _) -> do
241+ threadDelay @ w pollInterval
242+ loop
243+ (status, _) -> return status
233244 where
245+ getStatus = do
246+ mTx <- queryChainIndexForTxState
247+ case mTx of
248+ Nothing -> do
249+ logDebug $ " TxId " ++ show txId ++ " not found in index"
250+ return Unknown
251+ Just txState -> do
252+ logDebug $ " TxId " ++ show txId ++ " found in index, checking status"
253+ blk <- fromInteger <$> currentBlock contractEnv
254+ case transactionStatus blk txState txId of
255+ Left e -> do
256+ logDebug $ " Status check for TxId " ++ show txId ++ " failed with " ++ show e
257+ return Unknown
258+ Right st -> do
259+ logDebug $ " Status for TxId " ++ show txId ++ " is " ++ show st
260+ return st
261+
234262 queryChainIndexForTxState :: Eff effs (Maybe TxIdState )
235263 queryChainIndexForTxState = do
236264 mTx <- join . preview _TxIdResponse <$> (queryChainIndex @ w $ TxFromTxId txId)
@@ -240,6 +268,8 @@ awaitTxStatusChange contractEnv txId = do
240268 pure . Just $ fromTx blk tx
241269 Nothing -> pure Nothing
242270
271+ logDebug = printBpiLog @ w Debug . pretty
272+
243273-- | This will FULLY balance a transaction
244274balanceTx ::
245275 forall (w :: Type ) (effs :: [Type -> Type ]).
@@ -355,25 +385,25 @@ awaitSlot contractEnv s@(Slot n) = do
355385 | n < tip'. slot -> pure $ Slot tip'. slot
356386 _ -> awaitSlot contractEnv s
357387
358- -- | Wait for n Blocks.
359- awaitNBlocks ::
360- forall (w :: Type ) (effs :: [Type -> Type ]).
361- Member (PABEffect w ) effs =>
362- ContractEnvironment w ->
363- Integer ->
364- Eff effs ()
365- awaitNBlocks contractEnv n = do
366- current <- currentBlock contractEnv
367- go current
368- where
369- go :: Integer -> Eff effs ()
370- go start = do
371- threadDelay @ w (fromIntegral contractEnv. cePABConfig. pcTipPollingInterval)
372- tip <- CardanoCLI. queryTip @ w contractEnv. cePABConfig
373- case tip of
374- Right tip'
375- | start + n <= tip'. block -> pure ()
376- _ -> go start
388+ -- -- | Wait for n Blocks.
389+ -- awaitNBlocks ::
390+ -- forall (w :: Type) (effs :: [Type -> Type]).
391+ -- Member (PABEffect w) effs =>
392+ -- ContractEnvironment w ->
393+ -- Integer ->
394+ -- Eff effs ()
395+ -- awaitNBlocks contractEnv n = do
396+ -- current <- currentBlock contractEnv
397+ -- go current
398+ -- where
399+ -- go :: Integer -> Eff effs ()
400+ -- go start = do
401+ -- threadDelay @w (fromIntegral contractEnv.cePABConfig.pcTipPollingInterval)
402+ -- tip <- CardanoCLI.queryTip @w contractEnv.cePABConfig
403+ -- case tip of
404+ -- Right tip'
405+ -- | start + n <= tip'.block -> pure ()
406+ -- _ -> go start
377407
378408{- | Wait at least until the given time. Uses the awaitSlot under the hood, so the same constraints
379409 are applying here as well.
0 commit comments