Skip to content

Commit 5937f40

Browse files
authored
Merge pull request #800 from IntersectMBO/jordan/bug-fix-798
Bug fix - redeemer pointer map construction
2 parents 7444f32 + 7e208d2 commit 5937f40

10 files changed

Lines changed: 194 additions & 19 deletions

File tree

cardano-api/cardano-api.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ test-suite cardano-api-test
332332
cardano-ledger-alonzo,
333333
cardano-ledger-api >=1.9,
334334
cardano-ledger-binary,
335+
cardano-ledger-conway,
335336
cardano-ledger-core:{cardano-ledger-core, testlib} >=1.14,
336337
cardano-ledger-mary,
337338
cardano-protocol-tpraos,
@@ -377,6 +378,7 @@ test-suite cardano-api-test
377378
Test.Cardano.Api.Orphans
378379
Test.Cardano.Api.RawBytes
379380
Test.Cardano.Api.Transaction.Autobalance
381+
Test.Cardano.Api.Transaction.Body.Plutus.Scripts
380382
Test.Cardano.Api.TxBody
381383
Test.Cardano.Api.Value
382384

cardano-api/gen/Test/Gen/Cardano/Api/Typed.hs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ module Test.Gen.Cardano.Api.Typed
119119
, genTxValidityUpperBound
120120
, genTxWithdrawals
121121
, genUnsignedQuantity
122+
122123
, genPositiveQuantity
123124
, genValueForMinting
124125
, genValueForTxOut
@@ -133,11 +134,15 @@ module Test.Gen.Cardano.Api.Typed
133134
, genProposal
134135
, genVotingProcedures
135136
, genSimpleScriptWithoutEmptyAnys
137+
, genWitnessable
138+
, genPlutusScriptWitness
139+
, genIndexedPlutusScriptWitness
136140
)
137141
where
138142

139143
import Cardano.Api hiding (txIns)
140144
import qualified Cardano.Api as Api
145+
import qualified Cardano.Api.Experimental as Exp
141146
import Cardano.Api.Byron (KeyWitness (ByronKeyWitness),
142147
WitnessNetworkIdOrByronAddress (..))
143148
import qualified Cardano.Api.Byron as Byron
@@ -146,6 +151,8 @@ import qualified Cardano.Api.Ledger as L
146151
import qualified Cardano.Api.Ledger.Lens as A
147152
import Cardano.Api.Internal.Script (scriptInEraToRefScript)
148153
import Cardano.Api.Shelley
154+
import Cardano.Ledger.Plutus.Language qualified as L
155+
149156
import qualified Cardano.Api.Shelley as ShelleyApi
150157

151158
import qualified Cardano.Binary as CBOR
@@ -168,8 +175,8 @@ import Data.Maybe
168175
import qualified Data.ByteString.Base16 as Base16
169176
import Data.Ratio (Ratio, (%))
170177
import Data.String
171-
import Test.Gen.Cardano.Api.Hardcoded
172-
import Data.Typeable
178+
import Test.Gen.Cardano.Api.Hardcoded
179+
import Data.Typeable
173180
import Data.Word (Word16, Word32, Word64)
174181
import GHC.Exts (IsList (..))
175182
import GHC.Stack
@@ -1362,6 +1369,38 @@ genCurrentTreasuryValue _era = Q.arbitrary
13621369
genTreasuryDonation :: ConwayEraOnwards era -> Gen L.Coin
13631370
genTreasuryDonation _era = Q.arbitrary
13641371

1372+
genWitnessable :: L.AlonzoEraScript era => Gen (Exp.Witnessable Exp.TxInItem era)
1373+
genWitnessable = Exp.WitTxIn <$> genTxIn
1374+
1375+
genIndexedPlutusScriptWitness
1376+
:: L.AlonzoEraScript (ShelleyLedgerEra era)
1377+
=> Gen (Exp.IndexedPlutusScriptWitness Exp.TxInItem L.PlutusV3 Exp.SpendingScript (ShelleyLedgerEra era))
1378+
genIndexedPlutusScriptWitness = do
1379+
index <- Gen.word32 $ Range.linear 1 10
1380+
witnessable <- genWitnessable
1381+
Exp.IndexedPlutusScriptWitness
1382+
<$> genWitnessable
1383+
<*> genPlutusPurpose index witnessable
1384+
<*> genPlutusScriptWitness
1385+
1386+
genPlutusPurpose
1387+
:: Word32
1388+
-> Exp.Witnessable thing (ShelleyLedgerEra era)
1389+
-> Gen (L.PlutusPurpose L.AsIx (ShelleyLedgerEra era))
1390+
genPlutusPurpose index wit = return $ Exp.toPlutusScriptPurpose index wit
1391+
1392+
genPlutusScriptWitness :: Gen (Exp.PlutusScriptWitness L.PlutusV3 purpose era)
1393+
genPlutusScriptWitness = do
1394+
let l = Exp.toPlutusSLanguage PlutusScriptV3
1395+
Exp.PlutusScriptWitness l . Exp.PReferenceScript
1396+
<$> genTxIn
1397+
<*> genPlutusScriptDatum
1398+
<*> genHashableScriptData
1399+
<*> genExecutionUnits
1400+
1401+
genPlutusScriptDatum :: Gen (Exp.PlutusScriptDatum lang purpose)
1402+
genPlutusScriptDatum = return Exp.NoScriptDatum
1403+
13651404
-- | This generator does not generate a valid witness - just a random one.
13661405
genScriptWitnessForStake :: ShelleyBasedEra era -> Gen (Api.ScriptWitness WitCtxStake era)
13671406
genScriptWitnessForStake sbe = do

cardano-api/src/Cardano/Api/Experimental.hs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,35 @@ module Cardano.Api.Experimental
3434
, babbageEraOnwardsToEra
3535
, eraToBabbageEraOnwards
3636
, sbeToEra
37+
38+
-- ** Witness related
39+
, AnyWitness (..)
40+
, PlutusScriptWitness (..)
41+
, Witnessable (..)
42+
, WitnessableItem (..)
43+
44+
-- ** Plutus related
45+
, PlutusScriptInEra (..)
46+
, PlutusScriptOrReferenceInput (..)
47+
, IndexedPlutusScriptWitness (..)
48+
, PlutusScriptPurpose (..)
49+
, PlutusScriptDatum (..)
50+
, NoScriptDatum (..)
51+
52+
-- ** Internal
53+
, getAnyWitnessRedeemerPointerMap
54+
, toPlutusScriptPurpose
55+
56+
-- ** Legacy
57+
, toPlutusSLanguage
3758
)
3859
where
3960

4061
import Cardano.Api.Internal.Experimental.Eras
62+
import Cardano.Api.Internal.Experimental.Plutus.IndexedPlutusScriptWitness
63+
import Cardano.Api.Internal.Experimental.Plutus.Script
64+
import Cardano.Api.Internal.Experimental.Plutus.ScriptWitness
65+
import Cardano.Api.Internal.Experimental.Plutus.Shim.LegacyScripts
4166
import Cardano.Api.Internal.Experimental.Tx
67+
import Cardano.Api.Internal.Experimental.Witness.AnyWitness
4268
import Cardano.Api.Internal.Fees (evaluateTransactionExecutionUnitsShelley)

cardano-api/src/Cardano/Api/Internal/Experimental/Plutus/IndexedPlutusScriptWitness.hs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ module Cardano.Api.Internal.Experimental.Plutus.IndexedPlutusScriptWitness
2020
, createIndexedPlutusScriptWitnesses
2121
, getAnyWitnessRedeemerPointerMap
2222
, obtainAlonzoScriptPurposeConstraints
23+
24+
-- * Exposed for testing
25+
, constructRedeeemerPointerMap
2326
)
2427
where
2528

@@ -48,17 +51,22 @@ import GHC.Exts
4851
-- and the index of the thing it is witnessing.
4952
data IndexedPlutusScriptWitness witnessable (lang :: L.Language) (purpose :: PlutusScriptPurpose) era where
5053
IndexedPlutusScriptWitness
51-
:: Witnessable witnessable era
54+
:: L.AlonzoEraScript era
55+
=> Witnessable witnessable era
5256
-> (L.PlutusPurpose L.AsIx era)
5357
-> (PlutusScriptWitness lang purpose era)
5458
-> IndexedPlutusScriptWitness witnessable lang purpose era
5559

60+
deriving instance Show (IndexedPlutusScriptWitness witnessable lang purpose era)
61+
5662
data AnyIndexedPlutusScriptWitness era where
5763
AnyIndexedPlutusScriptWitness
5864
:: GetPlutusScriptPurpose era
5965
=> IndexedPlutusScriptWitness witnessable lang purpose era
6066
-> AnyIndexedPlutusScriptWitness era
6167

68+
deriving instance Show (AnyIndexedPlutusScriptWitness era)
69+
6270
-- | These are all of the "things" a plutus script can witness. We include the relevant
6371
-- type class constraint to avoid boilerplate when creating the 'PlutusPurpose' in
6472
-- the 'GetPlutusScriptPurpose' instances.
@@ -141,7 +149,8 @@ instance GetPlutusScriptPurpose era where
141149
toPlutusScriptPurpose index WitProposal{} = L.mkProposingPurpose (L.AsIx index)
142150

143151
createIndexedPlutusScriptWitness
144-
:: Word32
152+
:: L.AlonzoEraScript era
153+
=> Word32
145154
-> Witnessable witnessable era
146155
-> PlutusScriptWitness lang purpose era
147156
-> IndexedPlutusScriptWitness witnessable lang purpose era
@@ -151,7 +160,8 @@ createIndexedPlutusScriptWitness index witnessable =
151160
-- | Create a list of indexed plutus script witnesses from anything witnessable that has been
152161
-- witnesseed by a plutus script.
153162
createIndexedPlutusScriptWitnesses
154-
:: [(Witnessable witnessable era, AnyWitness era)]
163+
:: L.AlonzoEraScript era
164+
=> [(Witnessable witnessable era, AnyWitness era)]
155165
-> [AnyIndexedPlutusScriptWitness era]
156166
createIndexedPlutusScriptWitnesses witnessableThings =
157167
[ AnyIndexedPlutusScriptWitness $ createIndexedPlutusScriptWitness index thing sWit
@@ -162,16 +172,15 @@ createIndexedPlutusScriptWitnesses witnessableThings =
162172

163173
-- | The transaction's redeemer pointer map allows the ledger to connect a redeemer and execution unit pairing to the relevant
164174
-- script. The ledger basically reconstructs the indicies (redeemer pointers) of this map can then look up the relevant
165-
-- execution units/redeemer pairing. NB the redeemer pointer has been renamed to 'PlutusPurpose AsIndex' in the ledger.
175+
-- execution units/redeemer pairing. NB: the redeemer pointer has been renamed to 'PlutusPurpose AsIndex' in the ledger.
166176
getAnyWitnessRedeemerPointerMap
167177
:: AlonzoEraOnwards era
168-
-> (Witnessable witnessable (ShelleyLedgerEra era), AnyWitness (ShelleyLedgerEra era))
178+
-> [(Witnessable witnessable (ShelleyLedgerEra era), AnyWitness (ShelleyLedgerEra era))]
169179
-> L.Redeemers (ShelleyLedgerEra era)
170-
getAnyWitnessRedeemerPointerMap eon (_, AnyKeyWitnessPlaceholder) = alonzoEraOnwardsConstraints eon mempty
171-
getAnyWitnessRedeemerPointerMap eon (_, AnySimpleScriptWitness{}) = alonzoEraOnwardsConstraints eon mempty
172180
getAnyWitnessRedeemerPointerMap eon anyWit =
173181
constructRedeeemerPointerMap eon $
174-
createIndexedPlutusScriptWitnesses [anyWit]
182+
alonzoEraOnwardsConstraints eon $
183+
createIndexedPlutusScriptWitnesses anyWit
175184

176185
-- | An 'IndexedPlutusScriptWitness' contains everything we need to construct a single
177186
-- entry in the redeemer pointer map.

cardano-api/src/Cardano/Api/Internal/Experimental/Plutus/ScriptWitness.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
{-# LANGUAGE MultiParamTypeClasses #-}
88
{-# LANGUAGE PolyKinds #-}
99
{-# LANGUAGE ScopedTypeVariables #-}
10+
{-# LANGUAGE StandaloneDeriving #-}
1011
{-# LANGUAGE TypeFamilyDependencies #-}
1112
{-# LANGUAGE UndecidableInstances #-}
1213

@@ -65,6 +66,8 @@ data PlutusScriptWitness (lang :: L.Language) (purpose :: PlutusScriptPurpose) e
6566
-> ExecutionUnits
6667
-> PlutusScriptWitness lang purpose era
6768

69+
deriving instance Show (PlutusScriptWitness lang purpose era)
70+
6871
getPlutusScriptWitnessLanguage :: PlutusScriptWitness lang purpose era -> L.Language
6972
getPlutusScriptWitnessLanguage (PlutusScriptWitness l _ _ _ _) =
7073
case l of

cardano-api/src/Cardano/Api/Internal/Experimental/Plutus/Shim/LegacyScripts.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
module Cardano.Api.Internal.Experimental.Plutus.Shim.LegacyScripts
1414
( legacyWitnessToScriptRequirements
15+
, toPlutusSLanguage
1516
)
1617
where
1718

cardano-api/src/Cardano/Api/Internal/Experimental/Witness/TxScriptWitnessRequirements.hs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,27 @@ instance Monoid (TxScriptWitnessRequirements L.ConwayEra) where
6262

6363
getTxScriptWitnessRequirements
6464
:: AlonzoEraOnwards era
65-
-> (Witnessable witnessable (ShelleyLedgerEra era), AnyWitness (ShelleyLedgerEra era))
65+
-> [(Witnessable witnessable (ShelleyLedgerEra era), AnyWitness (ShelleyLedgerEra era))]
6666
-> TxScriptWitnessRequirements (ShelleyLedgerEra era)
67-
getTxScriptWitnessRequirements era (thing, anyWit) =
68-
TxScriptWitnessRequirements
69-
(maybe mempty Set.singleton $ getAnyWitnessPlutusLanguage anyWit)
70-
(maybe mempty return $ getAnyWitnessScript (convert era) anyWit)
71-
(getAnyWitnessScriptData era anyWit)
72-
(getAnyWitnessRedeemerPointerMap era (thing, anyWit))
67+
getTxScriptWitnessRequirements era wits =
68+
let TxScriptWitnessRequirements l s d _ =
69+
obtainMonoidConstraint era $
70+
mconcat
71+
[ TxScriptWitnessRequirements
72+
(maybe mempty Set.singleton $ getAnyWitnessPlutusLanguage anyWit)
73+
(maybe mempty return $ getAnyWitnessScript (convert era) anyWit)
74+
(getAnyWitnessScriptData era anyWit)
75+
(alonzoEraOnwardsConstraints era mempty)
76+
| (_, anyWit) <- wits
77+
]
78+
in TxScriptWitnessRequirements l s d (getAnyWitnessRedeemerPointerMap era wits)
7379

7480
getTxScriptWitnessesRequirements
7581
:: AlonzoEraOnwards era
7682
-> [(Witnessable witnessable (ShelleyLedgerEra era), AnyWitness (ShelleyLedgerEra era))]
7783
-> TxScriptWitnessRequirements (ShelleyLedgerEra era)
7884
getTxScriptWitnessesRequirements eon wits =
79-
obtainMonoidConstraint eon $ mconcat $ map (getTxScriptWitnessRequirements eon) wits
85+
obtainMonoidConstraint eon $ getTxScriptWitnessRequirements eon wits
8086

8187
obtainMonoidConstraint
8288
:: AlonzoEraOnwards era

cardano-api/src/Cardano/Api/Internal/ScriptData.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ data HashableScriptData
9898
!BS.ByteString
9999
-- ^ Original 'ScriptData' bytes
100100
!ScriptData
101-
deriving (Eq, Show)
101+
deriving (Eq, Show, Ord)
102102

103103
instance HasTypeProxy HashableScriptData where
104104
data AsType HashableScriptData = AsHashableScriptData
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
{-# LANGUAGE DataKinds #-}
2+
{-# LANGUAGE GADTs #-}
3+
{-# LANGUAGE TypeApplications #-}
4+
5+
module Test.Cardano.Api.Transaction.Body.Plutus.Scripts
6+
( tests
7+
)
8+
where
9+
10+
import Cardano.Api (AlonzoEraOnwards (..))
11+
import Cardano.Api.Experimental
12+
import Cardano.Api.Ledger qualified as L
13+
import Cardano.Api.Shelley (fromAlonzoData)
14+
15+
import Cardano.Ledger.Alonzo.TxWits qualified as L
16+
import Cardano.Ledger.Conway qualified as L
17+
18+
import Prelude
19+
20+
import Data.List qualified as List
21+
import Data.Map.Strict qualified as Map
22+
23+
import Test.Gen.Cardano.Api.Typed (genIndexedPlutusScriptWitness, genWitnessable)
24+
25+
import Test.Cardano.Api.Orphans ()
26+
27+
import Hedgehog
28+
import Hedgehog.Gen qualified as Gen
29+
import Hedgehog.Range qualified as Range
30+
import Test.Tasty (TestTree, testGroup)
31+
import Test.Tasty.Hedgehog (testProperty)
32+
33+
-- | This property checks that the redeemer pointer map is constructed correctly.
34+
-- Previously identical script purposes were being created and overwriting each other
35+
-- in the redeemer pointer map.
36+
prop_getAnyWitnessRedeemerPointerMap :: Property
37+
prop_getAnyWitnessRedeemerPointerMap = property $ do
38+
let eon = AlonzoEraOnwardsConway
39+
l <- forAll $ Gen.int (Range.linear 2 5)
40+
witnessables <- forAll $ Gen.list (Range.singleton l) $ genWitnessable @L.ConwayEra
41+
wits <-
42+
forAll $
43+
Gen.list (Range.singleton l) $
44+
genIndexedPlutusScriptWitness @ConwayEra
45+
let anyWits =
46+
[ AnyPlutusScriptWitness swit
47+
| IndexedPlutusScriptWitness _ _ swit <- wits
48+
]
49+
50+
zipped = zip witnessables anyWits
51+
expectedRedeemerPointerMapLength = length zipped
52+
finalWits = take expectedRedeemerPointerMapLength wits
53+
54+
L.Redeemers constructedRedeemerPointerMap = getAnyWitnessRedeemerPointerMap eon zipped
55+
56+
annotate "Constructed redeemer pointer map"
57+
annotateShow constructedRedeemerPointerMap
58+
let redeemerPointerMapSize = Map.size constructedRedeemerPointerMap
59+
60+
cover 30 "Redeemer pointer map size more than 1" $ redeemerPointerMapSize > 1
61+
62+
-- Confirm we have the expected number of redeemers
63+
Map.size constructedRedeemerPointerMap === expectedRedeemerPointerMapLength
64+
65+
let initialRedeemers =
66+
[ redeemer
67+
| IndexedPlutusScriptWitness _ _ swit <- finalWits
68+
, let PlutusScriptWitness _ _ _ redeemer _ = swit
69+
]
70+
71+
ledgerRedeemers :: [L.Data L.ConwayEra]
72+
ledgerRedeemers = map fst $ Map.elems constructedRedeemerPointerMap
73+
74+
convertedRedeemers = map fromAlonzoData ledgerRedeemers
75+
76+
annotate "Initial Indexed Script Witnesses"
77+
annotateShow wits
78+
79+
-- Confirm we have idential redeemers
80+
List.sort initialRedeemers === List.sort convertedRedeemers
81+
82+
tests :: TestTree
83+
tests =
84+
testGroup
85+
"Test.Cardano.Api.Transaction.Body.Plutus.Scripts"
86+
[ testProperty "prop_getAnyWitnessRedeemerPointerMap" prop_getAnyWitnessRedeemerPointerMap
87+
]

cardano-api/test/cardano-api-test/cardano-api-test.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import Test.Cardano.Api.Metadata qualified
2424
import Test.Cardano.Api.Ord qualified
2525
import Test.Cardano.Api.RawBytes qualified
2626
import Test.Cardano.Api.Transaction.Autobalance qualified
27+
import Test.Cardano.Api.Transaction.Body.Plutus.Scripts qualified
2728
import Test.Cardano.Api.TxBody qualified
2829
import Test.Cardano.Api.Value qualified
2930

@@ -59,6 +60,7 @@ tests =
5960
, Test.Cardano.Api.Metadata.tests
6061
, Test.Cardano.Api.Ord.tests
6162
, Test.Cardano.Api.RawBytes.tests
63+
, Test.Cardano.Api.Transaction.Body.Plutus.Scripts.tests
6264
, Test.Cardano.Api.Transaction.Autobalance.tests
6365
, Test.Cardano.Api.TxBody.tests
6466
, Test.Cardano.Api.Value.tests

0 commit comments

Comments
 (0)