|
2 | 2 | {-# LANGUAGE NumericUnderscores #-} |
3 | 3 | {-# LANGUAGE OverloadedStrings #-} |
4 | 4 | {-# LANGUAGE ScopedTypeVariables #-} |
| 5 | +{-# LANGUAGE TypeApplications #-} |
5 | 6 | {-# LANGUAGE TypeFamilies #-} |
6 | 7 |
|
7 | 8 | module Test.Cardano.Api.Experimental.Fee |
@@ -36,7 +37,13 @@ import Data.Time.Clock.POSIX qualified as Time |
36 | 37 | import GHC.Exts (fromList) |
37 | 38 | import Lens.Micro |
38 | 39 |
|
39 | | -import Test.Gen.Cardano.Api.Typed (genAddressInEra, genStakeCredential, genTxIn) |
| 40 | +import Test.Gen.Cardano.Api.Typed |
| 41 | + ( genAddressInEra |
| 42 | + , genScriptHash |
| 43 | + , genStakeCredential |
| 44 | + , genTxIn |
| 45 | + , genVerificationKeyHash |
| 46 | + ) |
40 | 47 |
|
41 | 48 | import Test.Cardano.Api.Experimental (exampleProtocolParams, exampleProtocolParamsEra) |
42 | 49 |
|
@@ -68,6 +75,12 @@ tests = |
68 | 75 | "unwitnessed certs produce no script witnesses" |
69 | 76 | prop_collectTxBodyScriptWitnesses_ignores_unwitnessed_certs |
70 | 77 | ] |
| 78 | + , testGroup |
| 79 | + "estimateTransactionKeyWitnessCount" |
| 80 | + [ testProperty |
| 81 | + "counts key witnesses required by key-credentialed voters" |
| 82 | + prop_estimateTransactionKeyWitnessCount_counts_vote_key_witnesses |
| 83 | + ] |
71 | 84 | , testGroup |
72 | 85 | "createCompatibleTx" |
73 | 86 | [ testProperty |
@@ -1100,6 +1113,24 @@ prop_createCompatibleTx_preserves_all_certs = H.property $ do |
1100 | 1113 | let bodyCerts = ledgerTx ^. L.bodyTxL . L.certsTxBodyL |
1101 | 1114 | Seq.length bodyCerts H.=== expectedCount |
1102 | 1115 |
|
| 1116 | +-- | Regression test for: a key-credentialed voter (e.g. a key-hash DRep) |
| 1117 | +-- requires a VKey witness to satisfy the ledger, but |
| 1118 | +-- 'estimateTransactionKeyWitnessCount''s record pattern does not destructure |
| 1119 | +-- 'txVotingProcedures' at all, so a vote witnessed by |
| 1120 | +-- 'AnyKeyWitnessPlaceholder' contributes zero to the estimate. A transaction |
| 1121 | +-- containing only a generated mix of key-credentialed and script-credentialed |
| 1122 | +-- votes (and nothing else) must be estimated to need exactly one key witness |
| 1123 | +-- per key-credentialed voter - script-credentialed votes must not add to the |
| 1124 | +-- count. |
| 1125 | +prop_estimateTransactionKeyWitnessCount_counts_vote_key_witnesses :: Property |
| 1126 | +prop_estimateTransactionKeyWitnessCount_counts_vote_key_witnesses = H.property $ do |
| 1127 | + (txVotingProcedures, expectedKeyWitnessCount) <- H.forAll genVotingProceduresWithKeyWitnessCount |
| 1128 | + let txBodyContent = |
| 1129 | + Exp.defaultTxBodyContent |
| 1130 | + & Exp.setTxVotingProcedures txVotingProcedures |
| 1131 | + keyWitnessCount = Exp.estimateTransactionKeyWitnessCount @Exp.ConwayEra txBodyContent |
| 1132 | + keyWitnessCount H.=== fromIntegral expectedKeyWitnessCount |
| 1133 | + |
1103 | 1134 | -- --------------------------------------------------------------------------- |
1104 | 1135 | -- Shared cert generators |
1105 | 1136 | -- --------------------------------------------------------------------------- |
@@ -1157,3 +1188,61 @@ genShuffledCertsWithCount = do |
1157 | 1188 | ] |
1158 | 1189 | shuffled <- Gen.shuffle allCerts |
1159 | 1190 | pure (shuffled, length shuffled) |
| 1191 | + |
| 1192 | +-- --------------------------------------------------------------------------- |
| 1193 | +-- Shared vote generators |
| 1194 | +-- --------------------------------------------------------------------------- |
| 1195 | + |
| 1196 | +-- | Generate a 'TxVotingProcedures' whose witness map mixes key-credentialed |
| 1197 | +-- voters ('L.DRepVoter'/'L.CommitteeVoter' over a key hash, plus |
| 1198 | +-- 'L.StakePoolVoter', which is always key-credentialed - all witnessed by |
| 1199 | +-- 'AnyKeyWitnessPlaceholder') with script-credentialed voters |
| 1200 | +-- ('L.DRepVoter'/'L.CommitteeVoter' over a script hash, witnessed by a |
| 1201 | +-- reference-input simple script - 'L.StakePoolVoter' has no |
| 1202 | +-- script-credentialed form). Each bucket draws its hashes via 'Gen.set', so |
| 1203 | +-- voters within a bucket never collide as witness-map keys; voters across |
| 1204 | +-- buckets can never collide either, since they differ in the 'L.Voter' or |
| 1205 | +-- 'L.Credential' constructor regardless of the underlying hash bytes. |
| 1206 | +-- Returns the generated voting procedures together with the number of |
| 1207 | +-- key-credentialed voters, i.e. the key-witness count |
| 1208 | +-- 'estimateTransactionKeyWitnessCount' must report for a transaction |
| 1209 | +-- containing only these votes. |
| 1210 | +genVotingProceduresWithKeyWitnessCount |
| 1211 | + :: Gen (Exp.TxVotingProcedures (Exp.LedgerEra Exp.ConwayEra), Int) |
| 1212 | +genVotingProceduresWithKeyWitnessCount = do |
| 1213 | + drepKeyHashes <- |
| 1214 | + Gen.set (Range.linear 0 5) (Api.unDRepKeyHash <$> genVerificationKeyHash Api.AsDRepKey) |
| 1215 | + committeeKeyHashes <- |
| 1216 | + Gen.set |
| 1217 | + (Range.linear 0 5) |
| 1218 | + (Api.unCommitteeHotKeyHash <$> genVerificationKeyHash Api.AsCommitteeHotKey) |
| 1219 | + stakePoolKeyHashes <- |
| 1220 | + Gen.set (Range.linear 0 5) (Api.unStakePoolKeyHash <$> genVerificationKeyHash Api.AsStakePoolKey) |
| 1221 | + drepScriptHashes <- Gen.set (Range.linear 0 5) (Api.toShelleyScriptHash <$> genScriptHash) |
| 1222 | + committeeScriptHashes <- Gen.set (Range.linear 0 5) (Api.toShelleyScriptHash <$> genScriptHash) |
| 1223 | + refTxIn <- genTxIn |
| 1224 | + |
| 1225 | + let keyVoters = |
| 1226 | + [L.DRepVoter (L.KeyHashObj kh) | kh <- toList drepKeyHashes] |
| 1227 | + <> [L.CommitteeVoter (L.KeyHashObj kh) | kh <- toList committeeKeyHashes] |
| 1228 | + <> [L.StakePoolVoter kh | kh <- toList stakePoolKeyHashes] |
| 1229 | + scriptVoters = |
| 1230 | + [L.DRepVoter (L.ScriptHashObj sh) | sh <- toList drepScriptHashes] |
| 1231 | + <> [L.CommitteeVoter (L.ScriptHashObj sh) | sh <- toList committeeScriptHashes] |
| 1232 | + |
| 1233 | + govActionId = |
| 1234 | + L.GovActionId |
| 1235 | + (L.TxId (L.unsafeMakeSafeHash "0000000000000000000000000000000000000000000000000000000000000000")) |
| 1236 | + (L.GovActionIx 0) |
| 1237 | + votingProcedure = L.VotingProcedure{L.vProcVote = L.VoteYes, L.vProcAnchor = L.SNothing} |
| 1238 | + scriptWitness = Exp.AnySimpleScriptWitness (Exp.SReferenceScript refTxIn) |
| 1239 | + allVoters = keyVoters <> scriptVoters |
| 1240 | + votingProcedures = |
| 1241 | + L.VotingProcedures $ |
| 1242 | + Map.fromList [(voter, Map.singleton govActionId votingProcedure) | voter <- allVoters] |
| 1243 | + witnessMap = |
| 1244 | + Map.fromList $ |
| 1245 | + [(voter, Exp.AnyKeyWitnessPlaceholder) | voter <- keyVoters] |
| 1246 | + <> [(voter, scriptWitness) | voter <- scriptVoters] |
| 1247 | + |
| 1248 | + pure (Exp.TxVotingProcedures votingProcedures witnessMap, length keyVoters) |
0 commit comments