Skip to content
This repository was archived by the owner on Dec 2, 2024. It is now read-only.

Commit ff494a5

Browse files
committed
PAB: improve consistent slot config through several components
1 parent 404af7a commit ff494a5

File tree

12 files changed

+65
-53
lines changed

12 files changed

+65
-53
lines changed

plutus-contract/src/Wallet/Emulator/Chain.hs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@ getCurrentSlot = send GetCurrentSlot
9595

9696
type ChainEffs = '[State ChainState, LogMsg ChainEvent]
9797

98-
handleControlChain :: Members ChainEffs effs => ChainControlEffect ~> Eff effs
99-
handleControlChain = \case
98+
handleControlChain :: Members ChainEffs effs => SlotConfig -> ChainControlEffect ~> Eff effs
99+
handleControlChain slotCfg = \case
100100
ProcessBlock -> do
101101
st <- get
102102
let pool = st ^. txPool
103103
slot = st ^. currentSlot
104104
idx = st ^. index
105105
ValidatedBlock block events rest =
106-
validateBlock slot idx pool
106+
validateBlock slotCfg slot idx pool
107107

108108
let st' = st & txPool .~ rest
109109
& addBlock block
@@ -140,16 +140,16 @@ data ValidatedBlock = ValidatedBlock
140140
-- | Validate a block given the current slot and UTxO index, returning the valid
141141
-- transactions, success/failure events, remaining transactions and the
142142
-- updated UTxO set.
143-
validateBlock :: Slot -> Index.UtxoIndex -> [Tx] -> ValidatedBlock
144-
validateBlock slot@(Slot s) idx txns =
143+
validateBlock :: SlotConfig -> Slot -> Index.UtxoIndex -> [Tx] -> ValidatedBlock
144+
validateBlock slotCfg slot@(Slot s) idx txns =
145145
let
146146
-- Select those transactions that can be validated in the
147147
-- current slot
148148
(eligibleTxns, rest) = partition (canValidateNow slot) txns
149149

150150
-- Validate eligible transactions, updating the UTXO index each time
151151
processed =
152-
flip S.evalState idx $ for eligibleTxns $ \tx -> do
152+
flip S.evalState (Index.ValidationCtx idx slotCfg) $ for eligibleTxns $ \tx -> do
153153
(err, events_) <- validateEm slot tx
154154
pure (tx, err, events_)
155155

@@ -179,11 +179,11 @@ mkValidationEvent t result events =
179179
Just (phase, err) -> TxnValidationFail phase (txId t) t err events
180180

181181
-- | Validate a transaction in the current emulator state.
182-
validateEm :: S.MonadState Index.UtxoIndex m => Slot -> Tx -> m (Maybe Index.ValidationErrorInPhase, [ScriptValidationEvent])
182+
validateEm :: S.MonadState Index.ValidationCtx m => Slot -> Tx -> m (Maybe Index.ValidationErrorInPhase, [ScriptValidationEvent])
183183
validateEm h txn = do
184-
idx <- S.get
185-
let ((e, idx'), events) = Index.runValidation (Index.validateTransaction h txn) idx
186-
_ <- S.put idx'
184+
ctx <- S.get
185+
let ((e, idx'), events) = Index.runValidation (Index.validateTransaction h txn) ctx
186+
_ <- S.put ctx{Index.vctxIndex=idx'}
187187
pure (e, events)
188188

189189
-- | Adds a block to ChainState, without validation.

plutus-contract/src/Wallet/Emulator/Types.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,6 @@ processEmulated slotCfg feeCfg act =
106106
& reinterpret2 @ChainEffect @(State ChainState) @(LogMsg ChainEvent) (handleChain slotCfg)
107107
& interpret (Eff.handleZoomedState chainState)
108108
& interpret (mapLog (review chainEvent))
109-
& reinterpret2 @ChainControlEffect @(State ChainState) @(LogMsg ChainEvent) handleControlChain
109+
& reinterpret2 @ChainControlEffect @(State ChainState) @(LogMsg ChainEvent) (handleControlChain slotCfg)
110110
& interpret (Eff.handleZoomedState chainState)
111111
& interpret (mapLog (review chainEvent))

plutus-contract/src/Wallet/Emulator/Wallet.hs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import Ledger.Constraints.OffChain (UnbalancedTx (..))
5151
import Ledger.Constraints.OffChain qualified as U
5252
import Ledger.Credential (Credential (..))
5353
import Ledger.Fee (FeeConfig (..), calcFees)
54-
import Ledger.TimeSlot (posixTimeRangeToContainedSlotRange)
54+
import Ledger.TimeSlot (SlotConfig, posixTimeRangeToContainedSlotRange)
5555
import Ledger.Tx qualified as Tx
5656
import Ledger.Value qualified as Value
5757
import Plutus.ChainIndex (PageQuery)
@@ -210,7 +210,7 @@ handleWallet feeCfg = \case
210210
slotConfig <- WAPI.getClientSlotConfig
211211
let validitySlotRange = posixTimeRangeToContainedSlotRange slotConfig (utx' ^. U.validityTimeRange)
212212
let utx = utx' & U.tx . validRange .~ validitySlotRange
213-
utxWithFees <- validateTxAndAddFees feeCfg utxo utx
213+
utxWithFees <- validateTxAndAddFees feeCfg slotConfig utxo utx
214214
-- balance to add fees
215215
tx' <- handleBalanceTx utxo (utx & U.tx . fee .~ (utxWithFees ^. U.tx . fee))
216216
tx'' <- handleAddSignature tx'
@@ -260,15 +260,16 @@ validateTxAndAddFees ::
260260
, Member (State WalletState) effs
261261
)
262262
=> FeeConfig
263+
-> SlotConfig
263264
-> Map.Map TxOutRef ChainIndexTxOut
264265
-> UnbalancedTx
265266
-> Eff effs UnbalancedTx
266-
validateTxAndAddFees feeCfg ownTxOuts utx = do
267+
validateTxAndAddFees feeCfg slotCfg ownTxOuts utx = do
267268
-- Balance and sign just for validation
268269
tx <- handleBalanceTx ownTxOuts utx
269270
signedTx <- handleAddSignature tx
270271
let utxoIndex = Ledger.UtxoIndex $ unBalancedTxUtxoIndex utx <> (toTxOut <$> ownTxOuts)
271-
((e, _), events) = Ledger.runValidation (Ledger.validateTransactionOffChain signedTx) utxoIndex
272+
((e, _), events) = Ledger.runValidation (Ledger.validateTransactionOffChain signedTx) (Ledger.ValidationCtx utxoIndex slotCfg)
272273
for_ e $ \(phase, ve) -> do
273274
logWarn $ ValidationFailed phase (txId tx) tx ve events
274275
throwError $ WAPI.ValidationError ve

plutus-contract/test/Spec/Emulator.hs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ pubKey3 = walletPubKeyHash wallet3
116116

117117
utxo :: Property
118118
utxo = property $ do
119-
Mockchain txPool o <- forAll Gen.genMockchain
119+
Mockchain txPool o _ <- forAll Gen.genMockchain
120120
Hedgehog.assert (unspentOutputs [map Valid txPool] == o)
121121

122122
txnValid :: Property
@@ -153,7 +153,7 @@ selectCoinProp = property $ do
153153

154154
txnUpdateUtxo :: Property
155155
txnUpdateUtxo = property $ do
156-
(Mockchain m _, txn) <- forAll genChainTxn
156+
(Mockchain m _ _, txn) <- forAll genChainTxn
157157
let options = defaultCheckOptions & emulatorConfig . Trace.initialChainState .~ Right m
158158

159159
-- submit the same txn twice, so it should be accepted the first time
@@ -173,14 +173,14 @@ txnUpdateUtxo = property $ do
173173

174174
validTrace :: Property
175175
validTrace = property $ do
176-
(Mockchain m _, txn) <- forAll genChainTxn
176+
(Mockchain m _ _, txn) <- forAll genChainTxn
177177
let options = defaultCheckOptions & emulatorConfig . Trace.initialChainState .~ Right m
178178
trace = Trace.liftWallet wallet1 (submitTxn $ Right txn)
179179
checkPredicateInner options assertNoFailedTransactions trace Hedgehog.annotate Hedgehog.assert
180180

181181
validTrace2 :: Property
182182
validTrace2 = property $ do
183-
(Mockchain m _, txn) <- forAll genChainTxn
183+
(Mockchain m _ _, txn) <- forAll genChainTxn
184184
let options = defaultCheckOptions & emulatorConfig . Trace.initialChainState .~ Right m
185185
trace = do
186186
Trace.liftWallet wallet1 (submitTxn $ Right txn)
@@ -190,7 +190,7 @@ validTrace2 = property $ do
190190

191191
invalidTrace :: Property
192192
invalidTrace = property $ do
193-
(Mockchain m _, txn) <- forAll genChainTxn
193+
(Mockchain m _ _, txn) <- forAll genChainTxn
194194
let invalidTxn = txn { txMint = Ada.adaValueOf 1 }
195195
options = defaultCheckOptions & emulatorConfig . Trace.initialChainState .~ Right m
196196
trace = Trace.liftWallet wallet1 (submitTxn $ Right invalidTxn)
@@ -205,7 +205,7 @@ invalidTrace = property $ do
205205

206206
invalidScript :: Property
207207
invalidScript = property $ do
208-
(Mockchain m _, txn1) <- forAll genChainTxn
208+
(Mockchain m _ _, txn1) <- forAll genChainTxn
209209

210210
-- modify one of the outputs to be a script output
211211
index <- forAll $ Gen.int (Range.linear 0 ((length $ txOutputs txn1) -1))

plutus-ledger/src/Ledger/Generators.hs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,12 +114,13 @@ constantFee = def { fcScriptsFeeFactor = 0 }
114114
-- unspent outputs of the chain when it is first created.
115115
data Mockchain = Mockchain {
116116
mockchainInitialTxPool :: [Tx],
117-
mockchainUtxo :: Map TxOutRef TxOut
117+
mockchainUtxo :: Map TxOutRef TxOut,
118+
mockchainSlotConfig :: SlotConfig
118119
} deriving Show
119120

120121
-- | The empty mockchain.
121122
emptyChain :: Mockchain
122-
emptyChain = Mockchain [] Map.empty
123+
emptyChain = Mockchain [] Map.empty def
123124

124125
-- | Generate a mockchain.
125126
--
@@ -130,9 +131,11 @@ genMockchain' :: MonadGen m
130131
genMockchain' gm = do
131132
let (txn, ot) = genInitialTransaction gm
132133
tid = txId txn
134+
slotCfg <- genSlotConfig
133135
pure Mockchain {
134136
mockchainInitialTxPool = [txn],
135-
mockchainUtxo = Map.fromList $ first (TxOutRef tid) <$> zip [0..] ot
137+
mockchainUtxo = Map.fromList $ first (TxOutRef tid) <$> zip [0..] ot,
138+
mockchainSlotConfig = slotCfg
136139
}
137140

138141
-- | Generate a mockchain using the default 'GeneratorModel'.
@@ -171,7 +174,7 @@ genValidTransaction' :: MonadGen m
171174
-> FeeConfig
172175
-> Mockchain
173176
-> m Tx
174-
genValidTransaction' g feeCfg (Mockchain _ ops) = do
177+
genValidTransaction' g feeCfg (Mockchain _ ops _) = do
175178
-- Take a random number of UTXO from the input
176179
nUtxo <- if Map.null ops
177180
then Gen.discard
@@ -350,10 +353,10 @@ assertValid tx mc = Hedgehog.assert $ isNothing $ validateMockchain mc tx
350353

351354
-- | Validate a transaction in a mockchain.
352355
validateMockchain :: Mockchain -> Tx -> Maybe Index.ValidationError
353-
validateMockchain (Mockchain txPool _) tx = result where
356+
validateMockchain (Mockchain txPool _ slotCfg) tx = result where
354357
h = 1
355358
idx = Index.initialise [map Valid txPool]
356-
result = fmap snd $ fst $ fst $ Index.runValidation (Index.validateTransaction h tx) idx
359+
result = fmap snd $ fst $ fst $ Index.runValidation (Index.validateTransaction h tx) (ValidationCtx idx slotCfg)
357360

358361
{- | Split a value into max. n positive-valued parts such that the sum of the
359362
parts equals the original value.
@@ -379,7 +382,8 @@ genTxInfo :: MonadGen m => Mockchain -> m TxInfo
379382
genTxInfo chain = do
380383
tx <- genValidTransaction chain
381384
let idx = UtxoIndex $ mockchainUtxo chain
382-
let (res, _) = runWriter $ runExceptT $ runReaderT (_runValidation (Index.mkTxInfo tx)) idx
385+
let slotCfg = mockchainSlotConfig chain
386+
let (res, _) = runWriter $ runExceptT $ runReaderT (_runValidation (Index.mkTxInfo tx)) (ValidationCtx idx slotCfg)
383387
either (const Gen.discard) pure res
384388

385389
genScriptPurposeSpending :: MonadGen m => TxInfo -> m Contexts.ScriptPurpose

plutus-ledger/src/Ledger/Index.hs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
module 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)
5455
import Control.Monad.Reader (MonadReader (..), ReaderT (..), ask)
5556
import Control.Monad.Writer (MonadWriter, Writer, runWriter, tell)
5657
import Data.Aeson (FromJSON, ToJSON)
57-
import Data.Default (Default (def))
5858
import Data.Foldable (asum, fold, foldl', traverse_)
5959
import Data.Map qualified as Map
6060
import 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.
9294
newtype UtxoIndex = UtxoIndex { getIndex :: Map.Map TxOutRef TxOut }
@@ -159,12 +161,12 @@ deriving via (PrettyShow ValidationPhase) instance Pretty ValidationPhase
159161
type 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.
170172
lkpValue :: 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'.
176178
lkpTxOut :: 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.
180182
validateTransaction :: 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.
386388
mkTxInfo :: ValidationMonad m => Tx -> m TxInfo
387389
mkTxInfo 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

plutus-pab/src/Cardano/Chain.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,15 @@ handleControlChain ::
8383
, Member (LogMsg EC.ChainEvent) effs
8484
, LastMember m effs
8585
, MonadIO m )
86-
=> EC.ChainControlEffect ~> Eff effs
87-
handleControlChain = \case
86+
=> SlotConfig -> EC.ChainControlEffect ~> Eff effs
87+
handleControlChain slotCfg = \case
8888
EC.ProcessBlock -> do
8989
st <- get
9090
let pool = st ^. txPool
9191
slot = st ^. currentSlot
9292
idx = st ^. index
9393
EC.ValidatedBlock block events rest =
94-
EC.validateBlock slot idx pool
94+
EC.validateBlock slotCfg slot idx pool
9595

9696
let st' = st & txPool .~ rest
9797
& tip ?~ block

plutus-pab/src/Cardano/Node/Mock.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ runChainEffects trace slotCfg clientHandler stateVar eff = do
8888
runChain = interpret (mapLog ProcessingChainEvent)
8989
. reinterpret (handleChain slotCfg)
9090
. interpret (mapLog ProcessingChainEvent)
91-
. reinterpret handleControlChain
91+
. reinterpret (handleControlChain slotCfg)
9292

9393
mergeState = interpret (handleZoomedState chainState)
9494

plutus-pab/src/Cardano/Node/Server.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ main trace MockServerConfig { mscBaseUrl
6767
{ _chainState = initialState
6868
, _eventHistory = mempty
6969
}
70-
serverHandler <- liftIO $ Server.runServerNode trace mscSocketPath mscKeptBlocks (_chainState appState)
70+
serverHandler <- liftIO $ Server.runServerNode trace mscSocketPath mscKeptBlocks (_chainState appState) mscSlotConfig
7171
serverState <- liftIO $ newMVar appState
7272
handleDelayEffect $ delayThread (2 :: Second)
7373
clientHandler <- liftIO $ Client.runTxSender mscSocketPath

0 commit comments

Comments
 (0)