1212module Ledger.Index (
1313 -- * Types for transaction validation based on UTXO index
1414 ValidationMonad ,
15+ ValidationCtx (.. ),
1516 UtxoIndex (.. ),
1617 insert ,
1718 insertCollateral ,
@@ -54,7 +55,6 @@ import Control.Monad.Except (ExceptT, MonadError (..), runExcept, runExceptT)
5455import Control.Monad.Reader (MonadReader (.. ), ReaderT (.. ), ask )
5556import Control.Monad.Writer (MonadWriter , Writer , runWriter , tell )
5657import Data.Aeson (FromJSON , ToJSON )
57- import Data.Default (Default (def ))
5858import Data.Foldable (asum , fold , foldl' , traverse_ )
5959import Data.Map qualified as Map
6060import Data.OpenApi.Schema qualified as OpenApi
@@ -86,7 +86,9 @@ import Prettyprinter.Extras (PrettyShow (..))
8686
8787-- | Context for validating transactions. We need access to the unspent
8888-- transaction outputs of the blockchain, and we can throw 'ValidationError's.
89- type ValidationMonad m = (MonadReader UtxoIndex m , MonadError ValidationError m , MonadWriter [ScriptValidationEvent ] m )
89+ type ValidationMonad m = (MonadReader ValidationCtx m , MonadError ValidationError m , MonadWriter [ScriptValidationEvent ] m )
90+
91+ data ValidationCtx = ValidationCtx { vctxIndex :: UtxoIndex , vctxSlotConfig :: TimeSlot. SlotConfig }
9092
9193-- | The UTxOs of a blockchain indexed by their references.
9294newtype UtxoIndex = UtxoIndex { getIndex :: Map. Map TxOutRef TxOut }
@@ -159,12 +161,12 @@ deriving via (PrettyShow ValidationPhase) instance Pretty ValidationPhase
159161type ValidationErrorInPhase = (ValidationPhase , ValidationError )
160162
161163-- | A monad for running transaction validation inside, which is an instance of 'ValidationMonad'.
162- newtype Validation a = Validation { _runValidation :: (ReaderT UtxoIndex (ExceptT ValidationError (Writer [ScriptValidationEvent ]))) a }
163- deriving newtype (Functor , Applicative , Monad , MonadReader UtxoIndex , MonadError ValidationError , MonadWriter [ScriptValidationEvent ])
164+ newtype Validation a = Validation { _runValidation :: (ReaderT ValidationCtx (ExceptT ValidationError (Writer [ScriptValidationEvent ]))) a }
165+ deriving newtype (Functor , Applicative , Monad , MonadReader ValidationCtx , MonadError ValidationError , MonadWriter [ScriptValidationEvent ])
164166
165167-- | Run a 'Validation' on a 'UtxoIndex'.
166- runValidation :: Validation (Maybe ValidationErrorInPhase , UtxoIndex ) -> UtxoIndex -> ((Maybe ValidationErrorInPhase , UtxoIndex ), [ScriptValidationEvent ])
167- runValidation l idx = runWriter $ fmap (either (\ e -> (Just (Phase1 , e), idx )) id ) $ runExceptT $ runReaderT (_runValidation l) idx
168+ runValidation :: Validation (Maybe ValidationErrorInPhase , UtxoIndex ) -> ValidationCtx -> ((Maybe ValidationErrorInPhase , UtxoIndex ), [ScriptValidationEvent ])
169+ runValidation l ctx = runWriter $ fmap (either (\ e -> (Just (Phase1 , e), vctxIndex ctx )) id ) $ runExceptT $ runReaderT (_runValidation l) ctx
168170
169171-- | Determine the unspent value that a ''TxOutRef' refers to.
170172lkpValue :: ValidationMonad m => TxOutRef -> m V. Value
@@ -174,7 +176,7 @@ lkpValue = fmap txOutValue . lkpTxOut
174176-- output for this reference exists. If you want to handle the lookup error
175177-- you can use 'runLookup'.
176178lkpTxOut :: ValidationMonad m => TxOutRef -> m TxOut
177- lkpTxOut t = lookup t =<< ask
179+ lkpTxOut t = lookup t . vctxIndex =<< ask
178180
179181-- | Validate a transaction in a 'ValidationMonad' context.
180182validateTransaction :: ValidationMonad m
@@ -187,7 +189,7 @@ validateTransaction h t = do
187189 _ <- lkpOutputs $ toListOf (inputs . scriptTxIns) t
188190
189191 -- see note [Minting of Ada]
190- emptyUtxoSet <- reader (Map. null . getIndex)
192+ emptyUtxoSet <- reader (Map. null . getIndex . vctxIndex )
191193 unless emptyUtxoSet (checkTransactionFee t)
192194
193195 validateTransactionOffChain t
@@ -201,7 +203,7 @@ validateTransactionOffChain t = do
201203 checkFeeIsAda t
202204
203205 -- see note [Minting of Ada]
204- emptyUtxoSet <- reader (Map. null . getIndex)
206+ emptyUtxoSet <- reader (Map. null . getIndex . vctxIndex )
205207 unless emptyUtxoSet (checkMintingAuthorised t)
206208
207209 checkValidInputs (toListOf (inputs . pubKeyTxIns)) t
@@ -212,13 +214,13 @@ validateTransactionOffChain t = do
212214 checkValidInputs (toListOf (inputs . scriptTxIns)) t
213215 unless emptyUtxoSet (checkMintingScripts t)
214216
215- idx <- ask
217+ idx <- vctxIndex <$> ask
216218 pure (Nothing , insert t idx)
217219 )
218220 `catchError` payCollateral
219221 where
220222 payCollateral e = do
221- idx <- ask
223+ idx <- vctxIndex <$> ask
222224 pure (Just (Phase2 , e), insertCollateral t idx)
223225
224226-- | Check that a transaction can be validated in the given slot.
@@ -385,6 +387,7 @@ checkTransactionFee tx =
385387-- | Create the data about the transaction which will be passed to a validator script.
386388mkTxInfo :: ValidationMonad m => Tx -> m TxInfo
387389mkTxInfo tx = do
390+ slotCfg <- vctxSlotConfig <$> ask
388391 txins <- traverse mkIn $ Set. toList $ view inputs tx
389392 let ptx = TxInfo
390393 { txInfoInputs = txins
@@ -393,7 +396,7 @@ mkTxInfo tx = do
393396 , txInfoFee = txFee tx
394397 , txInfoDCert = [] -- DCerts not supported in emulator
395398 , txInfoWdrl = [] -- Withdrawals not supported in emulator
396- , txInfoValidRange = TimeSlot. slotRangeToPOSIXTimeRange def $ txValidRange tx
399+ , txInfoValidRange = TimeSlot. slotRangeToPOSIXTimeRange slotCfg $ txValidRange tx
397400 , txInfoSignatories = fmap pubKeyHash $ Map. keys (tx ^. signatures)
398401 , txInfoData = Map. toList (tx ^. datumWitnesses)
399402 , txInfoId = txId tx
0 commit comments