From 86ae8a3b5a0d0139f3c25d116f294a31ff9dd3c5 Mon Sep 17 00:00:00 2001 From: Alexey Kuleshevich Date: Thu, 20 Jun 2024 14:33:43 -0600 Subject: [PATCH] Improve stability of `futurePParams` prediction: Ensure that every Conway Epoch begins with a correct prediction for `futurePParams`. The problem that this commit fixes has to do with the fact that `futurePParams` where correctly predicted on the very first `TICK`. However, if there are no blocks prior to point-of-no-return, which can't happen on a normal running chain, there would be no `TICK`, thus there would be no prediction. So, regardless if there was a correct prediciton after the point-of-no-return, `PParamUpdate` would be simply ignored, since `futurePParams` would be already set to `NoPParamUpdate`. Despite the fact that this can't really happen on mainnet, we can fix this quite easily by predicting `futurePParams` during DRepPulser initialization, which is exactly what being imlemented in this commit. --- .../src/Cardano/Ledger/Conway/Governance.hs | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs b/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs index 2554ec907c6..c1b2ccf1126 100644 --- a/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs +++ b/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs @@ -464,29 +464,30 @@ setFreshDRepPulsingState epochNo stakePoolDistr epochState = do umap = dsUnified dState umapSize = Map.size $ umElems umap pulseSize = max 1 (umapSize `div` (fromIntegral :: Word64 -> Int) (4 * k)) - epochState' = - epochState - & epochStateGovStateL . cgsDRepPulsingStateL - .~ DRPulsing - ( DRepPulser - { dpPulseSize = pulseSize - , dpUMap = dsUnified dState - , dpIndex = 0 -- used as the index of the remaining UMap - , dpStakeDistr = stakeDistr -- used as part of the snapshot - , dpStakePoolDistr = stakePoolDistr - , dpDRepDistr = Map.empty -- The partial result starts as the empty map - , dpDRepState = vsDReps vState - , dpCurrentEpoch = epochNo - , dpCommitteeState = vsCommitteeState vState - , dpEnactState = - mkEnactState govState - & ensTreasuryL .~ epochState ^. epochStateTreasuryL - , dpProposals = proposalsActions props - , dpProposalDeposits = proposalsDeposits props - , dpGlobals = globals - } - ) - pure epochState' + govState' = + predictFuturePParams $ + govState + & cgsDRepPulsingStateL + .~ DRPulsing + ( DRepPulser + { dpPulseSize = pulseSize + , dpUMap = dsUnified dState + , dpIndex = 0 -- used as the index of the remaining UMap + , dpStakeDistr = stakeDistr -- used as part of the snapshot + , dpStakePoolDistr = stakePoolDistr + , dpDRepDistr = Map.empty -- The partial result starts as the empty map + , dpDRepState = vsDReps vState + , dpCurrentEpoch = epochNo + , dpCommitteeState = vsCommitteeState vState + , dpEnactState = + mkEnactState govState + & ensTreasuryL .~ epochState ^. epochStateTreasuryL + , dpProposals = proposalsActions props + , dpProposalDeposits = proposalsDeposits props + , dpGlobals = globals + } + ) + pure $ epochState & epochStateGovStateL .~ govState' -- | Force computation of DRep stake distribution and figure out the next enact -- state. This operation is useful in cases when access to new EnactState or DRep stake