22{-# LANGUAGE DataKinds #-}
33{-# LANGUAGE FlexibleContexts #-}
44{-# LANGUAGE GADTs #-}
5+ {-# LANGUAGE NamedFieldPuns #-}
56{-# LANGUAGE OverloadedLists #-}
67{-# LANGUAGE OverloadedStrings #-}
78{-# LANGUAGE RankNTypes #-}
1112module Test.Cardano.Ledger.Alonzo.Imp.UtxosSpec (spec ) where
1213
1314import Cardano.Ledger.Alonzo.Core
14- import Cardano.Ledger.Alonzo.Plutus.Evaluate (CollectError (NoCostModel ))
15+ import Cardano.Ledger.Alonzo.Plutus.Evaluate (
16+ CollectError (NoCostModel ),
17+ TransactionScriptFailure (RedeemerPointsToUnknownScriptHash ),
18+ evalTxExUnits ,
19+ )
1520import Cardano.Ledger.Alonzo.Rules (
1621 AlonzoUtxosPredFailure (.. ),
1722 TagMismatchDescription (.. ),
1823 )
19- import Cardano.Ledger.Alonzo.Scripts (eraLanguages )
24+ import Cardano.Ledger.Alonzo.Scripts (ExUnits ( .. ), eraLanguages )
2025import Cardano.Ledger.Alonzo.TxWits (unRedeemersL )
26+ import Cardano.Ledger.BaseTypes (Globals (.. ), StrictMaybe (.. ))
2127import Cardano.Ledger.Plutus.Data (Data (.. ))
2228import Cardano.Ledger.Plutus.Language (hashPlutusScript , withSLanguage )
2329import Cardano.Ledger.Shelley.LedgerState (curPParamsEpochStateL , nesEsL )
30+ import Control.Monad.Reader (asks )
31+ import Data.Either (isLeft )
32+ import qualified Data.Map.Merge.Strict as Map
2433import qualified Data.Map.Strict as Map
2534import qualified Data.Set as Set
26- import Lens.Micro ((&) , (.~) , (<>~) )
35+ import Lens.Micro (set , (%~) , (&) , (.~) , (<>~) , (^.) , _2 )
36+ import Lens.Micro.Mtl (use )
2737import qualified PlutusLedgerApi.Common as P
38+ import qualified PlutusLedgerApi.V1 as PV1
2839import Test.Cardano.Ledger.Alonzo.ImpTest
2940import Test.Cardano.Ledger.Imp.Common
3041import Test.Cardano.Ledger.Plutus.Examples (
@@ -44,8 +55,8 @@ spec ::
4455 SpecWith (ImpInit (LedgerSpec era ))
4556spec = describe " UTXOS" $
4657 forM_ (eraLanguages @ era ) $ \ lang ->
47- withSLanguage lang $ \ slang ->
48- describe ( show lang) $ do
58+ describe ( show lang) $
59+ withSLanguage lang $ \ slang -> do
4960 let redeemerSameAsDatumHash = hashPlutusScript $ redeemerSameAsDatum slang
5061 alwaysSucceedsWithDatumHash = hashPlutusScript $ alwaysSucceedsWithDatum slang
5162
@@ -56,6 +67,57 @@ spec = describe "UTXOS" $
5667 , (" inputsOutputsAreNotEmptyWithDatum" , inputsOutputsAreNotEmptyWithDatum)
5768 ]
5869
70+ describe " ExUnits" $ do
71+ it " Calculate ExUnits" $ do
72+ let
73+ overrideExUnits tx = do
74+ pp <- getsNES $ nesEsL . curPParamsEpochStateL
75+ utxo <- getUTxO
76+ Globals {epochInfo, systemStart} <- use impGlobalsL
77+ purposeUnits <-
78+ either (fail . show ) pure . sequence $
79+ evalTxExUnits pp tx utxo epochInfo systemStart
80+ pure $ tx & witsTxL . rdmrsTxWitsL . unRedeemersL %~ spliceUnits purposeUnits
81+ spliceUnits =
82+ Map. merge
83+ Map. dropMissing -- Ignore purposes not already in the redeemers
84+ Map. preserveMissing -- Don't touch purposes not being updated
85+ (Map. zipWithMatched $ \ _ -> set _2) -- Replace the units, keep the datum
86+ redoAddrWits = updateAddrTxWits . (witsTxL . addrTxWitsL .~ mempty )
87+
88+ txIn <- produceScript alwaysSucceedsWithDatumHash
89+ withPostFixup (overrideExUnits >=> fixupPPHash >=> redoAddrWits) $
90+ submitTx_ $
91+ mkBasicTx mkBasicTxBody & bodyTxL . inputsTxBodyL .~ [txIn]
92+
93+ it " Attempt to calculate ExUnits with an invalid tx" $ do
94+ txIn <- produceScript alwaysSucceedsWithDatumHash
95+ let tx = mkBasicTx mkBasicTxBody & bodyTxL . inputsTxBodyL .~ [txIn]
96+
97+ txFixed <- (tx & ) =<< asks iteFixup
98+ logToExpr txFixed
99+
100+ let
101+ twiddleIx (SJust (SpendingPurpose (AsIx 0 ))) = SpendingPurpose (AsIx 1 )
102+ twiddleIx _ = SpendingPurpose (AsIx 0 )
103+ badPurpose =
104+ twiddleIx $
105+ redeemerPointer (txFixed ^. bodyTxL) (SpendingPurpose $ AsItem txIn)
106+ du = (Data $ PV1. I 42 , ExUnits 5000 5000 )
107+ txBorked =
108+ txFixed
109+ & witsTxL . rdmrsTxWitsL . unRedeemersL %~ Map. insert badPurpose du
110+ logToExpr txBorked
111+
112+ pp <- getsNES $ nesEsL . curPParamsEpochStateL
113+ utxo <- getUTxO
114+ Globals {epochInfo, systemStart} <- use impGlobalsL
115+ let report = evalTxExUnits pp txBorked utxo epochInfo systemStart
116+ logToExpr report
117+
118+ Map. filter isLeft report
119+ `shouldBe` Map. singleton badPurpose (Left (RedeemerPointsToUnknownScriptHash badPurpose))
120+
59121 describe " Spending scripts with a Datum" $ do
60122 forM_ scripts $ \ (name, script) -> do
61123 it name $ do
0 commit comments