@@ -33,7 +33,7 @@ import Data.Ix (inRange)
33
33
import Data.List (notElem , sortOn )
34
34
import Data.Map.Strict (Map )
35
35
import qualified Data.Map.Strict as Map
36
- import Data.Maybe (fromMaybe )
36
+ import Data.Maybe (catMaybes , fromMaybe )
37
37
import Data.Ord (Down (Down ))
38
38
import Data.Set (Set , union , (\\) )
39
39
import qualified Data.Set as Set
@@ -49,13 +49,13 @@ import Control.State.Transition
49
49
import Control.State.Transition.Generator (HasTrace , envGen , sigGen )
50
50
import Data.AbstractSize (HasTypeReps )
51
51
52
- import Ledger.Core (BlockCount (.. ), HasHash , Owner (Owner ), Relation (.. ),
52
+ import Ledger.Core (BlockCount (.. ), HasHash , Owner (Owner ), Relation (.. ), Slot ,
53
53
SlotCount (.. ), VKey (VKey ), VKeyGenesis (VKeyGenesis ), dom , hash ,
54
54
minusSlotMaybe , skey , (*.) , (-.) , (∈) , (∉) , (⋪) , (▷) , (▷<=) , (▷>=) , (◁) , (⨃) )
55
55
import qualified Ledger.Core as Core
56
56
import qualified Ledger.Core.Generators as CoreGen
57
57
58
- import Prelude hiding ( min )
58
+ import Prelude
59
59
60
60
61
61
-- | Protocol parameters.
@@ -225,27 +225,57 @@ invertBijection
225
225
a ==> b = not a || b
226
226
infix 1 ==>
227
227
228
+ -- | Check whether a protocol version can follow the current protocol version.
228
229
pvCanFollow
229
230
:: ProtVer
231
+ -- ^ Next protocol version
230
232
-> ProtVer
233
+ -- ^ Previous protocol version
231
234
-> Bool
232
- pvCanFollow (ProtVer mjn min an) (ProtVer mjp mip ap)
233
- = (mjp, mip, ap) < (mjn, min , an)
235
+ pvCanFollow (ProtVer mjn mn an) (ProtVer mjp mip ap)
236
+ = (mjp, mip, ap) < (mjn, mn , an)
234
237
&& (inRange (0 ,1 ) (mjn - mjp))
235
- && ((mjp == mjn) ==> (mip + 1 == min ))
236
- && ((mjp + 1 == mjn) ==> (min == 0 ))
238
+ && ((mjp == mjn) ==> (mip + 1 == mn ))
239
+ && ((mjp + 1 == mjn) ==> (mn == 0 ))
237
240
238
241
-- | Check whether an update proposal marks a valid update
239
242
--
240
- -- TODO At the moment we don't check size in here - should we?
241
- canUpdate
243
+ checkUpdateConstraints
242
244
:: PParams
243
245
-> UProp
244
- -> Bool
245
- canUpdate pps prop =
246
- (prop ^. upParams . maxBkSz <= 2 * pps ^. maxBkSz)
247
- && (prop ^. upParams . maxBkSz > prop ^. upParams . maxTxSz)
248
- && (inRange (0 ,1 ) $ prop ^. upParams . scriptVersion - pps ^. scriptVersion)
246
+ -> [UpdateConstraintViolation ]
247
+ checkUpdateConstraints pps prop =
248
+ catMaybes
249
+ [ (prop ^. upParams . maxBkSz <=? 2 * pps ^. maxBkSz)
250
+ `orError` BlockSizeTooLarge
251
+ , (prop ^. upParams . maxTxSz + 1 <=? prop ^. upParams . maxBkSz)
252
+ `orError` TransactionSizeTooLarge
253
+ , (pps ^. scriptVersion <=? prop ^. upParams . scriptVersion)
254
+ `orError` ScriptVersionTooSmall
255
+ , (prop ^. upParams . scriptVersion <=? pps ^. scriptVersion + 1 )
256
+ `orError` ScriptVersionTooLarge
257
+ ]
258
+
259
+ (<=?) :: Ord a => a -> a -> Maybe (a , Threshold a )
260
+ x <=? y = if x <= y then Nothing else Just (x, Threshold y)
261
+
262
+ infix 4 <=?
263
+
264
+ orError :: Maybe (a , b ) -> (a -> b -> e ) -> Maybe e
265
+ orError mab ferr = uncurry ferr <$> mab
266
+
267
+ canUpdate :: PParams -> UProp -> Rule UPPVV ctx ()
268
+ canUpdate pps prop = violations == [] ?! CannotUpdatePv violations
269
+ where violations = checkUpdateConstraints pps prop
270
+
271
+ -- | Violations on the constraints of the allowed values for new protocol
272
+ -- parameters.
273
+ data UpdateConstraintViolation
274
+ = BlockSizeTooLarge Natural (Threshold Natural )
275
+ | TransactionSizeTooLarge Natural (Threshold Natural )
276
+ | ScriptVersionTooLarge Natural (Threshold Natural )
277
+ | ScriptVersionTooSmall Natural (Threshold Natural )
278
+ deriving (Eq , Ord , Show )
249
279
250
280
svCanFollow
251
281
:: Map ApName (ApVer , Core. Slot , Metadata )
@@ -303,7 +333,7 @@ instance STS UPPVV where
303
333
304
334
data PredicateFailure UPPVV
305
335
= CannotFollowPv
306
- | CannotUpdatePv
336
+ | CannotUpdatePv [ UpdateConstraintViolation ]
307
337
| AlreadyProposedPv
308
338
| InvalidSystemTags
309
339
deriving (Eq , Show )
@@ -316,7 +346,7 @@ instance STS UPPVV where
316
346
nv = up ^. upPV
317
347
ppsn = up ^. upParams
318
348
pvCanFollow nv pv ?! CannotFollowPv
319
- canUpdate pps up ?! CannotUpdatePv
349
+ canUpdate pps up
320
350
nv `notElem` (fst <$> Map. elems rpus) ?! AlreadyProposedPv
321
351
all sTagValid (up ^. upSTags) ?! InvalidSystemTags
322
352
return $! rpus ⨃ [(pid, (nv, ppsn))]
@@ -345,7 +375,7 @@ instance STS UPV where
345
375
data PredicateFailure UPV
346
376
= UPPVVFailure (PredicateFailure UPPVV )
347
377
| UPSVVFailure (PredicateFailure UPSVV )
348
- | AVChangedInPVUpdate ApName ApVer
378
+ | AVChangedInPVUpdate ApName ApVer ( Maybe ( ApVer , Slot , Metadata ))
349
379
| ParamsChangedInSVUpdate
350
380
| PVChangedInSVUpdate
351
381
deriving (Eq , Show )
@@ -359,7 +389,7 @@ instance STS UPV where
359
389
) <- judgmentContext
360
390
rpus' <- trans @ UPPVV $ TRC ((pv, pps), rpus, up)
361
391
let SwVer an av = up ^. upSwVer
362
- inMap an av (swVer <$> avs) ?! AVChangedInPVUpdate an av
392
+ inMap an av (swVer <$> avs) ?! AVChangedInPVUpdate an av ( Map. lookup an avs)
363
393
pure $! (rpus', raus)
364
394
, do
365
395
TRC ( (pv, pps, avs)
@@ -717,8 +747,8 @@ emptyUPIState =
717
747
initialPParams :: PParams
718
748
initialPParams =
719
749
PParams -- TODO: choose more sensible default values
720
- { _maxBkSz = 1000 -- max sizes chosen as non-zero to allow progress
721
- , _maxHdrSz = 100
750
+ { _maxBkSz = 10000 -- max sizes chosen as non-zero to allow progress
751
+ , _maxHdrSz = 1000
722
752
, _maxTxSz = 500
723
753
, _maxPropSz = 10
724
754
, _bkSgnCntT = 0.22 -- As defined in the spec.
@@ -904,19 +934,19 @@ instance HasTrace UPIREG where
904
934
-- is not part of the registered protocol-update proposals
905
935
-- (@rpus@).
906
936
nextAltVersion :: (Natural , Natural ) -> ProtVer
907
- nextAltVersion (maj, min ) = dom (range rpus)
937
+ nextAltVersion (maj, mn ) = dom (range rpus)
908
938
& Set. filter protocolVersionEqualsMajMin
909
939
& Set. map _pvAlt
910
940
& Set. toDescList
911
941
& nextVersion
912
942
where
913
943
protocolVersionEqualsMajMin :: ProtVer -> Bool
914
944
protocolVersionEqualsMajMin pv' =
915
- _pvMaj pv' == maj && _pvMin pv' == min
945
+ _pvMaj pv' == maj && _pvMin pv' == mn
916
946
917
947
nextVersion :: [Natural ] -> ProtVer
918
- nextVersion [] = ProtVer maj min 0
919
- nextVersion (x: _) = ProtVer maj min (1 + x)
948
+ nextVersion [] = ProtVer maj mn 0
949
+ nextVersion (x: _) = ProtVer maj mn (1 + x)
920
950
921
951
-- Generate a software version update.
922
952
swVerGen :: Gen SwVer
@@ -1017,20 +1047,32 @@ dmapGen ngk = Bimap.fromList . uncurry zip <$> vkgVkPairsGen
1017
1047
-- own modules.
1018
1048
ppsUpdateFrom :: PParams -> Gen PParams
1019
1049
ppsUpdateFrom pps = do
1050
+ -- NOTE: we only generate small changes in the parameters to avoid leaving the
1051
+ -- protocol parameters in a state that won't allow to produce any valid blocks
1052
+ -- anymore (for instance if the maximum block size drops to a very small
1053
+ -- value).
1054
+
1020
1055
-- Determine the change in the block size: a decrement or an increment that
1021
1056
-- is no more than twice the current block maximum size.
1022
1057
--
1023
1058
-- We don't expect the maximum block size to change often, so we generate
1024
1059
-- more values around the current block size (@_maxBkSz@).
1025
- newMaxBkSize <- Gen. integral (Range. linearFrom _maxBkSz 1 (2 * _maxBkSz))
1026
- `increasingProbabilityAt`
1027
- (1 , 2 * _maxBkSz)
1060
+ newMaxBkSize <-
1061
+ Gen. integral (Range. linearFrom
1062
+ _maxBkSz
1063
+ (_maxBkSz -? 100 ) -- Decrement value was determined ad-hoc
1064
+ (2 * _maxBkSz)
1065
+ )
1066
+ `increasingProbabilityAt` (_maxBkSz -? 100 , 2 * _maxBkSz)
1028
1067
1029
1068
-- Similarly, we don't expect the transaction size to be changed often, so we
1030
1069
-- also generate more values around the current maximum transaction size.
1031
- newMaxTxSize <- Gen. integral (Range. exponentialFrom _maxTxSz 0 (newMaxBkSize - 1 ))
1032
- `increasingProbabilityAt`
1033
- (0 , newMaxBkSize - 1 )
1070
+ let minTxSzBound = _maxTxSz `min` newMaxBkSize -? 1
1071
+ newMaxTxSize <-
1072
+ Gen. integral (Range. exponential
1073
+ (minTxSzBound -? 10 ) -- Decrement value determined ad-hoc
1074
+ (newMaxBkSize -? 1 )
1075
+ )
1034
1076
1035
1077
PParams
1036
1078
<$> pure newMaxBkSize
@@ -1063,18 +1105,27 @@ ppsUpdateFrom pps = do
1063
1105
1064
1106
nextMaxHdrSzGen :: Gen Natural
1065
1107
nextMaxHdrSzGen =
1066
- Gen. integral (Range. exponentialFrom _maxHdrSz 0 (2 * _maxHdrSz))
1067
- `increasingProbabilityAt` (0 , 2 * _maxHdrSz)
1108
+ Gen. integral (Range. exponentialFrom
1109
+ _maxHdrSz
1110
+ (_maxHdrSz -? 10 )
1111
+ (2 * _maxHdrSz)
1112
+ )
1068
1113
1069
1114
nextMaxPropSz :: Gen Natural
1070
1115
nextMaxPropSz =
1071
- Gen. integral (Range. exponentialFrom _maxPropSz 0 (2 * _maxPropSz))
1072
- `increasingProbabilityAt` (0 , 2 * _maxPropSz)
1116
+ Gen. integral (Range. exponentialFrom
1117
+ _maxPropSz
1118
+ (_maxPropSz -? 1 )
1119
+ (2 * _maxPropSz)
1120
+ )
1073
1121
1074
1122
nextBkSgnCntT :: Gen Double
1075
1123
nextBkSgnCntT =
1076
- Gen. double (Range. exponentialFloatFrom _bkSgnCntT 0 1 )
1077
- `increasingProbabilityAt` (0 , 1 )
1124
+ Gen. double (Range. exponentialFloatFrom
1125
+ _bkSgnCntT
1126
+ (_bkSgnCntT - 0.01 )
1127
+ (_bkSgnCntT + 0.01 )
1128
+ )
1078
1129
1079
1130
nextUpTtl :: Gen SlotCount
1080
1131
nextUpTtl = SlotCount <$>
@@ -1113,6 +1164,9 @@ ppsUpdateFrom pps = do
1113
1164
Gen. integral (Range. exponentialFrom _factorB 0 10 )
1114
1165
`increasingProbabilityAt` (0 , 10 )
1115
1166
1167
+ (-?) :: Natural -> Natural -> Natural
1168
+ n -? m = if n < m then 0 else n - m
1169
+
1116
1170
-- | Generate values the given distribution in 90% of the cases, and values at
1117
1171
-- the bounds of the range in 10% of the cases.
1118
1172
--
@@ -1349,13 +1403,15 @@ instance STS UPIEND where
1349
1403
instance Embed UPEND UPIEND where
1350
1404
wrapFailed = UPENDFailure
1351
1405
1352
- -- | Generate a protocol version endorsement for a given key, or 'Nothing' if no stable and
1353
- -- confirmed protocol version update can be found.
1354
- protocolVersionEndorsementGen
1406
+ -- | Given a list of protocol versions and keys endorsing those versions,
1407
+ -- generate a protocol-version endorsement, or 'Nothing' if the list of
1408
+ -- endorsements is empty. The version to be endorsed will be selected from those
1409
+ -- versions that have the most endorsements.
1410
+ pickHighlyEndorsedProtocolVersion
1355
1411
:: [(ProtVer , Set Core. VKeyGenesis )]
1356
1412
-- ^ Current set of endorsements
1357
1413
-> Gen (Maybe ProtVer )
1358
- protocolVersionEndorsementGen endorsementsList =
1414
+ pickHighlyEndorsedProtocolVersion endorsementsList =
1359
1415
if null mostEndorsedProposals
1360
1416
then pure Nothing
1361
1417
else Just <$> Gen. element mostEndorsedProposals
@@ -1444,3 +1500,75 @@ instance STS UPIEC where
1444
1500
1445
1501
instance Embed PVBUMP UPIEC where
1446
1502
wrapFailed = PVBUMPFailure
1503
+
1504
+ -- | Generate an optional update-proposal and a list of votes, given an update
1505
+ -- environment and state.
1506
+ --
1507
+ -- The update proposal and votes need to be generated at the same time, since
1508
+ -- this allow us to generate update votes for update proposals issued in the
1509
+ -- same block as the votes.
1510
+ updateProposalAndVotesGen
1511
+ :: UPIEnv
1512
+ -> UPIState
1513
+ -> Gen (Maybe UProp , [Vote ])
1514
+ updateProposalAndVotesGen upienv upistate = do
1515
+ let rpus = registeredProtocolUpdateProposals upistate
1516
+ if Set. null (dom rpus)
1517
+ then generateUpdateProposalAndVotes
1518
+ else Gen. frequency [ (5 , generateOnlyVotes)
1519
+ , (1 , generateUpdateProposalAndVotes)
1520
+ ]
1521
+ where
1522
+ generateOnlyVotes = (Nothing ,) <$> sigGen @ UPIVOTES Nothing upienv upistate
1523
+ generateUpdateProposalAndVotes = do
1524
+ updateProposal <- sigGen @ UPIREG Nothing upienv upistate
1525
+ -- We want to have the possibility of generating votes for the proposal we
1526
+ -- registered.
1527
+ case applySTS @ UPIREG (TRC (upienv, upistate, updateProposal)) of
1528
+ Left _ ->
1529
+ (Just updateProposal, )
1530
+ <$> sigGen @ UPIVOTES Nothing upienv upistate
1531
+ Right upistateAfterRegistration ->
1532
+ (Just updateProposal, )
1533
+ <$> sigGen @ UPIVOTES Nothing upienv upistateAfterRegistration
1534
+
1535
+
1536
+ -- | Generate an endorsement given an update environment and state.
1537
+ protocolVersionEndorsementGen
1538
+ :: UPIEnv
1539
+ -> UPIState
1540
+ -> Gen ProtVer
1541
+ protocolVersionEndorsementGen upienv upistate =
1542
+ fromMaybe (protocolVersion upistate)
1543
+ <$> pickHighlyEndorsedProtocolVersion endorsementsList
1544
+ where
1545
+ -- Generate a list of protocol version endorsements. For this we look at the
1546
+ -- current endorsements, and confirmed and stable proposals.
1547
+ --
1548
+ -- If there are no endorsements, then the confirmed and stable proposals
1549
+ -- provide fresh protocol versions that can be endorsed.
1550
+ endorsementsList :: [(ProtVer , Set Core. VKeyGenesis )]
1551
+ endorsementsList = endorsementsMap `Map.union` emptyEndorsements
1552
+ & Map. toList
1553
+ where
1554
+ emptyEndorsements :: Map ProtVer (Set Core. VKeyGenesis )
1555
+ emptyEndorsements = zip stableAndConfirmedVersions (repeat Set. empty)
1556
+ & Map. fromList
1557
+ where
1558
+ stableAndConfirmedVersions
1559
+ :: [ProtVer ]
1560
+ stableAndConfirmedVersions = stableAndConfirmedProposalIDs ◁ rpus
1561
+ & Map. elems
1562
+ & fmap fst
1563
+ where
1564
+ stableAndConfirmedProposalIDs =
1565
+ dom (confirmedProposals upistate ▷<= sn -. 2 *. k)
1566
+ where
1567
+ (sn, _, k, _) = upienv
1568
+
1569
+ rpus = registeredProtocolUpdateProposals upistate
1570
+
1571
+ endorsementsMap :: Map ProtVer (Set Core. VKeyGenesis )
1572
+ endorsementsMap = Set. toList (endorsements upistate)
1573
+ & fmap (second Set. singleton)
1574
+ & Map. fromListWith Set. union
0 commit comments