From 1efbbdfb14acce0be2dd1882a4e5aac5c4b84205 Mon Sep 17 00:00:00 2001 From: Alexey Kuleshevich Date: Thu, 20 Jun 2024 14:25:48 -0600 Subject: [PATCH 1/2] Add a repro test for no PParams update when there are no ticks --- eras/conway/impl/cardano-ledger-conway.cabal | 2 +- .../Cardano/Ledger/Conway/Imp/EnactSpec.hs | 22 +++++++++++++++++++ eras/shelley/impl/CHANGELOG.md | 6 ++++- .../shelley/impl/cardano-ledger-shelley.cabal | 2 +- .../Test/Cardano/Ledger/Shelley/ImpTest.hs | 17 ++++++++++---- 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/eras/conway/impl/cardano-ledger-conway.cabal b/eras/conway/impl/cardano-ledger-conway.cabal index 18d5e3feb04..b01b1695b1b 100644 --- a/eras/conway/impl/cardano-ledger-conway.cabal +++ b/eras/conway/impl/cardano-ledger-conway.cabal @@ -92,7 +92,7 @@ library cardano-ledger-babbage ^>=1.8, cardano-ledger-core ^>=1.13, cardano-ledger-mary ^>=1.6, - cardano-ledger-shelley ^>=1.12.1, + cardano-ledger-shelley ^>=1.12.2, cardano-slotting, cardano-strict-containers, containers, diff --git a/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/EnactSpec.hs b/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/EnactSpec.hs index d4b81048741..35fa2f68f56 100644 --- a/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/EnactSpec.hs +++ b/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/EnactSpec.hs @@ -62,6 +62,7 @@ relevantDuringBootstrapSpec :: relevantDuringBootstrapSpec = do actionPrioritySpec hardForkInitiationNoDRepsSpec + pparamPredictionSpec treasuryWithdrawalsSpec :: forall era. @@ -241,6 +242,27 @@ hardForkInitiationNoDRepsSpec = passNEpochs 2 getProtVer `shouldReturn` nextProtVer +pparamPredictionSpec :: ConwayEraImp era => SpecWith (ImpTestState era) +pparamPredictionSpec = + it "futurePParams" $ do + (committeeMember :| _) <- registerInitialCommittee + modifyPParams $ ppPoolVotingThresholdsL . pvtHardForkInitiationL .~ 2 %! 3 + whenPostBootstrap (modifyPParams $ ppDRepVotingThresholdsL . dvtHardForkInitiationL .~ def) + _ <- setupPoolWithStake $ Coin 22_000_000 + (stakePoolId1, _, _) <- setupPoolWithStake $ Coin 22_000_000 + (stakePoolId2, _, _) <- setupPoolWithStake $ Coin 22_000_000 + curProtVer <- getProtVer + nextMajorVersion <- succVersion $ pvMajor curProtVer + let nextProtVer = curProtVer {pvMajor = nextMajorVersion} + govActionId <- submitGovAction $ HardForkInitiation SNothing nextProtVer + submitYesVote_ (CommitteeVoter committeeMember) govActionId + submitYesVote_ (StakePoolVoter stakePoolId1) govActionId + submitYesVote_ (StakePoolVoter stakePoolId2) govActionId + passEpoch + advanceToPointOfNoReturn + passEpoch + getProtVer `shouldReturn` nextProtVer + noConfidenceSpec :: forall era. ConwayEraImp era => SpecWith (ImpTestState era) noConfidenceSpec = it "NoConfidence" $ do diff --git a/eras/shelley/impl/CHANGELOG.md b/eras/shelley/impl/CHANGELOG.md index 535a6a3cc78..20174a05bab 100644 --- a/eras/shelley/impl/CHANGELOG.md +++ b/eras/shelley/impl/CHANGELOG.md @@ -1,9 +1,13 @@ # Version history for `cardano-ledger-shelley` -## 1.12.1.1 +## 1.12.2.0 * +### `testlib` + +* Add `advanceToPointOfNoReturn` + ## 1.12.1.0 * diff --git a/eras/shelley/impl/cardano-ledger-shelley.cabal b/eras/shelley/impl/cardano-ledger-shelley.cabal index 8ae50395f7e..c70b24e0098 100644 --- a/eras/shelley/impl/cardano-ledger-shelley.cabal +++ b/eras/shelley/impl/cardano-ledger-shelley.cabal @@ -1,6 +1,6 @@ cabal-version: 3.0 name: cardano-ledger-shelley -version: 1.12.1.0 +version: 1.12.2.0 license: Apache-2.0 maintainer: operations@iohk.io author: IOHK diff --git a/eras/shelley/impl/testlib/Test/Cardano/Ledger/Shelley/ImpTest.hs b/eras/shelley/impl/testlib/Test/Cardano/Ledger/Shelley/ImpTest.hs index 75711b51769..331954a460e 100644 --- a/eras/shelley/impl/testlib/Test/Cardano/Ledger/Shelley/ImpTest.hs +++ b/eras/shelley/impl/testlib/Test/Cardano/Ledger/Shelley/ImpTest.hs @@ -111,6 +111,7 @@ module Test.Cardano.Ledger.Shelley.ImpTest ( impKeyPairsG, impNativeScriptsG, produceScript, + advanceToPointOfNoReturn, ) where import qualified Cardano.Chain.Common as Byron @@ -180,6 +181,7 @@ import Cardano.Ledger.Shelley.Scripts ( pattern RequireMOf, pattern RequireSignature, ) +import Cardano.Ledger.Slot (getTheSlotOfNoReturn) import Cardano.Ledger.Tools (calcMinFeeTxNativeScriptWits, integralToByteStringN) import Cardano.Ledger.TxIn (TxId (..), TxIn (..)) import Cardano.Ledger.UMap as UMap @@ -751,8 +753,10 @@ runImpTestM mQCSize impState (ImpTestM m) = do endState <- readIORef ioRef pure (res, endState) -runShelleyBase :: Globals -> ShelleyBase a -> a -runShelleyBase globals act = runIdentity $ runReaderT act globals +runShelleyBase :: ShelleyBase a -> ImpTestM era a +runShelleyBase act = do + globals <- use impGlobalsL + pure $ runIdentity $ runReaderT act globals getRewardAccountAmount :: RewardAccount (EraCrypto era) -> ImpTestM era Coin getRewardAccountAmount rewardAcount = do @@ -1016,7 +1020,6 @@ tryRunImpRule :: ) tryRunImpRule stsEnv stsState stsSignal = do let trc = TRC (stsEnv, stsState, stsSignal) - globals <- use impGlobalsL let stsOpts = ApplySTSOpts @@ -1024,7 +1027,7 @@ tryRunImpRule stsEnv stsState stsSignal = do , asoEvents = EPReturn , asoAssertions = AssertionsAll } - pure $ runShelleyBase globals (applySTSOptsEither @(EraRule rule era) stsOpts trc) + runShelleyBase (applySTSOptsEither @(EraRule rule era) stsOpts trc) runImpRule :: forall rule era. @@ -1546,3 +1549,9 @@ produceScript scriptHash = do mkBasicTx mkBasicTxBody & bodyTxL . outputsTxBodyL .~ SSeq.singleton (mkBasicTxOut addr (inject (Coin 10))) txInAt (0 :: Int) <$> submitTx tx + +advanceToPointOfNoReturn :: ImpTestM era () +advanceToPointOfNoReturn = do + impLastTick <- gets impLastTick + (_, slotOfNoReturn, _) <- runShelleyBase $ getTheSlotOfNoReturn impLastTick + impLastTickL .= slotOfNoReturn From b7b9e8d69962d742ea0da4b6ba562ee983381e8d Mon Sep 17 00:00:00 2001 From: Alexey Kuleshevich Date: Thu, 20 Jun 2024 14:33:43 -0600 Subject: [PATCH 2/2] 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 ++++++++++--------- .../Cardano/Ledger/Conway/Imp/EnactSpec.hs | 4 +- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs b/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs index 0c601f766c5..40bcbddd7a0 100644 --- a/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs +++ b/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs @@ -467,29 +467,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 diff --git a/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/EnactSpec.hs b/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/EnactSpec.hs index 35fa2f68f56..1b160c9ccb4 100644 --- a/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/EnactSpec.hs +++ b/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/EnactSpec.hs @@ -245,7 +245,7 @@ hardForkInitiationNoDRepsSpec = pparamPredictionSpec :: ConwayEraImp era => SpecWith (ImpTestState era) pparamPredictionSpec = it "futurePParams" $ do - (committeeMember :| _) <- registerInitialCommittee + committeeMembers' <- registerInitialCommittee modifyPParams $ ppPoolVotingThresholdsL . pvtHardForkInitiationL .~ 2 %! 3 whenPostBootstrap (modifyPParams $ ppDRepVotingThresholdsL . dvtHardForkInitiationL .~ def) _ <- setupPoolWithStake $ Coin 22_000_000 @@ -255,7 +255,7 @@ pparamPredictionSpec = nextMajorVersion <- succVersion $ pvMajor curProtVer let nextProtVer = curProtVer {pvMajor = nextMajorVersion} govActionId <- submitGovAction $ HardForkInitiation SNothing nextProtVer - submitYesVote_ (CommitteeVoter committeeMember) govActionId + submitYesVoteCCs_ committeeMembers' govActionId submitYesVote_ (StakePoolVoter stakePoolId1) govActionId submitYesVote_ (StakePoolVoter stakePoolId2) govActionId passEpoch