diff --git a/eras/conway/impl/CHANGELOG.md b/eras/conway/impl/CHANGELOG.md index ce4e3535cff..e20bd61e7b2 100644 --- a/eras/conway/impl/CHANGELOG.md +++ b/eras/conway/impl/CHANGELOG.md @@ -1,8 +1,12 @@ # Version history for `cardano-ledger-conway` -## 1.15.1.1 +## 1.16.0.0 -* +* Added `ConwayCommitteeIsUnknown` predicate failure to `ConwayGovCertPredFailure` +* Added `ceCurrentCommittee` and `ceCommitteeProposals` to `CertEnv` +* Added `certsCurrentCommittee` and `certsCommitteeProposals` to `CertsEnv` +* Added `cgceCurrentCommittee` and `cgceCommitteeProposals` to `ConwayGovCertEnv` +* Added `proposalsWithPurpose`, `isGovActionWithPurpose` and `ToGovActionPurpose` ## 1.15.1.0 diff --git a/eras/conway/impl/cardano-ledger-conway.cabal b/eras/conway/impl/cardano-ledger-conway.cabal index 2bf8d42e158..18d5e3feb04 100644 --- a/eras/conway/impl/cardano-ledger-conway.cabal +++ b/eras/conway/impl/cardano-ledger-conway.cabal @@ -1,6 +1,6 @@ cabal-version: 3.0 name: cardano-ledger-conway -version: 1.15.1.0 +version: 1.16.0.0 license: Apache-2.0 maintainer: operations@iohk.io author: IOHK diff --git a/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs b/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs index 2554ec907c6..0c601f766c5 100644 --- a/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs +++ b/eras/conway/impl/src/Cardano/Ledger/Conway/Governance.hs @@ -28,6 +28,8 @@ module Cardano.Ledger.Conway.Governance ( GovActionIx (..), GovActionId (..), GovActionPurpose (..), + ToGovActionPurpose, + isGovActionWithPurpose, DRepPulsingState (..), DRepPulser (..), govActionIdToText, @@ -85,6 +87,7 @@ module Cardano.Ledger.Conway.Governance ( proposalsSize, proposalsLookupId, proposalsActionsMap, + proposalsWithPurpose, cgsProposalsL, cgsDRepPulsingStateL, cgsCurPParamsL, diff --git a/eras/conway/impl/src/Cardano/Ledger/Conway/Governance/Procedures.hs b/eras/conway/impl/src/Cardano/Ledger/Conway/Governance/Procedures.hs index 4598447e2a7..ab671fc721d 100644 --- a/eras/conway/impl/src/Cardano/Ledger/Conway/Governance/Procedures.hs +++ b/eras/conway/impl/src/Cardano/Ledger/Conway/Governance/Procedures.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveGeneric #-} @@ -38,6 +39,8 @@ module Cardano.Ledger.Conway.Governance.Procedures ( GovActionIx (..), GovPurposeId (..), GovActionPurpose (..), + ToGovActionPurpose, + isGovActionWithPurpose, GovRelation (..), grPParamUpdateL, grHardForkL, @@ -606,6 +609,29 @@ data GovActionPurpose | ConstitutionPurpose deriving (Eq, Show, Generic) +class ToGovActionPurpose (p :: GovActionPurpose) where + toGovActionPurpose :: GovActionPurpose + +instance ToGovActionPurpose 'PParamUpdatePurpose where + toGovActionPurpose = PParamUpdatePurpose +instance ToGovActionPurpose 'HardForkPurpose where + toGovActionPurpose = HardForkPurpose +instance ToGovActionPurpose 'CommitteePurpose where + toGovActionPurpose = CommitteePurpose +instance ToGovActionPurpose 'ConstitutionPurpose where + toGovActionPurpose = ConstitutionPurpose + +isGovActionWithPurpose :: forall p era. ToGovActionPurpose p => GovAction era -> Bool +isGovActionWithPurpose govAction = + case govAction of + ParameterChange {} -> toGovActionPurpose @p == PParamUpdatePurpose + HardForkInitiation {} -> toGovActionPurpose @p == HardForkPurpose + TreasuryWithdrawals {} -> False + NoConfidence {} -> toGovActionPurpose @p == CommitteePurpose + UpdateCommittee {} -> toGovActionPurpose @p == CommitteePurpose + NewConstitution {} -> toGovActionPurpose @p == ConstitutionPurpose + InfoAction -> False + newtype GovPurposeId (p :: GovActionPurpose) era = GovPurposeId { unGovPurposeId :: GovActionId (EraCrypto era) } diff --git a/eras/conway/impl/src/Cardano/Ledger/Conway/Governance/Proposals.hs b/eras/conway/impl/src/Cardano/Ledger/Conway/Governance/Proposals.hs index bd0eb08bb2e..17c6469fbb6 100644 --- a/eras/conway/impl/src/Cardano/Ledger/Conway/Governance/Proposals.hs +++ b/eras/conway/impl/src/Cardano/Ledger/Conway/Governance/Proposals.hs @@ -16,6 +16,7 @@ {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE TypeApplications #-} {-# LANGUAGE UndecidableInstances #-} -- | This module isolates all the types and functionality around @@ -90,6 +91,7 @@ module Cardano.Ledger.Conway.Governance.Proposals ( proposalsAddVote, proposalsLookupId, proposalsActionsMap, + proposalsWithPurpose, toPrevGovActionIds, fromPrevGovActionIds, @@ -236,6 +238,25 @@ instance EraPParams era => ToJSON (Proposals era) where toJSON = toJSON . pProps toEncoding = toEncoding . pProps +proposalsWithPurpose :: + forall p era. + ToGovActionPurpose p => + (forall f. Lens' (GovRelation f era) (f (GovPurposeId p era))) -> + Proposals era -> + Map (GovPurposeId p era) (GovActionState era) +proposalsWithPurpose propL Proposals {pProps, pGraph} = + fromMaybe (assert False fallBackMapWithPurpose) $ + Map.traverseWithKey + (\(GovPurposeId govActionId) _ -> OMap.lookup govActionId pProps) + (unPGraph (pGraph ^. propL)) + where + -- In case there is a bug and there is an inconsistency in state we want to report in + -- testing, while falling back onto alternative slower implementation + fallBackMapWithPurpose :: Map (GovPurposeId p era) (GovActionState era) + fallBackMapWithPurpose = + Map.mapKeysMonotonic GovPurposeId $ + Map.filter (isGovActionWithPurpose @p . pProcGovAction . gasProposalProcedure) (OMap.toMap pProps) + -- | Add a single @`GovActionState`@ to the @`Proposals`@ forest. -- The tree to which it is added is picked according to its -- @`GovActionPurpose`@. Returns `Nothing` when the operation cannot diff --git a/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Cert.hs b/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Cert.hs index 486dad254dd..79338ab83ab 100644 --- a/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Cert.hs +++ b/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Cert.hs @@ -22,7 +22,7 @@ module Cardano.Ledger.Conway.Rules.Cert ( CertEnv (..), ) where -import Cardano.Ledger.BaseTypes (EpochNo, ShelleyBase, SlotNo) +import Cardano.Ledger.BaseTypes (EpochNo, ShelleyBase, SlotNo, StrictMaybe) import Cardano.Ledger.Binary (DecCBOR (..), EncCBOR (..)) import Cardano.Ledger.Binary.Coders import Cardano.Ledger.Conway.Core @@ -32,6 +32,12 @@ import Cardano.Ledger.Conway.Era ( ConwayEra, ConwayGOVCERT, ) +import Cardano.Ledger.Conway.Governance ( + Committee, + GovActionPurpose (..), + GovActionState, + GovPurposeId, + ) import Cardano.Ledger.Conway.Rules.Deleg ( ConwayDelegEnv (..), ConwayDelegPredFailure (..), @@ -64,6 +70,7 @@ import Control.State.Transition.Extended ( wrapEvent, wrapFailed, ) +import qualified Data.Map.Strict as Map import Data.Typeable (Typeable) import Data.Void (absurd) import GHC.Generics (Generic) @@ -73,13 +80,15 @@ data CertEnv era = CertEnv { ceSlotNo :: !SlotNo , cePParams :: !(PParams era) , ceCurrentEpoch :: !EpochNo + , ceCurrentCommittee :: StrictMaybe (Committee era) + , ceCommitteeProposals :: Map.Map (GovPurposeId 'CommitteePurpose era) (GovActionState era) } deriving (Generic) -deriving instance Eq (PParams era) => Eq (CertEnv era) -deriving instance Show (PParams era) => Show (CertEnv era) +deriving instance EraPParams era => Eq (CertEnv era) +deriving instance EraPParams era => Show (CertEnv era) -instance NFData (PParams era) => NFData (CertEnv era) +instance EraPParams era => NFData (CertEnv era) data ConwayCertPredFailure era = DelegFailure (PredicateFailure (EraRule "DELEG" era)) @@ -196,7 +205,7 @@ certTransition :: ) => TransitionRule (ConwayCERT era) certTransition = do - TRC (CertEnv slot pp currentEpoch, cState, c) <- judgmentContext + TRC (CertEnv slot pp currentEpoch committee committeeProposals, cState, c) <- judgmentContext let CertState {certDState, certPState, certVState} = cState pools = psStakePoolParams certPState @@ -209,7 +218,8 @@ certTransition = do pure $ cState {certPState = newPState} ConwayTxCertGov govCert -> do newVState <- - trans @(EraRule "GOVCERT" era) $ TRC (ConwayGovCertEnv pp currentEpoch, certVState, govCert) + trans @(EraRule "GOVCERT" era) $ + TRC (ConwayGovCertEnv pp currentEpoch committee committeeProposals, certVState, govCert) pure $ cState {certVState = newVState} instance diff --git a/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Certs.hs b/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Certs.hs index adf4efd5a3a..b2f909bb158 100644 --- a/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Certs.hs +++ b/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Certs.hs @@ -29,6 +29,7 @@ import Cardano.Ledger.BaseTypes ( Globals (..), ShelleyBase, SlotNo, + StrictMaybe, binOpEpochNo, ) import Cardano.Ledger.Binary (DecCBOR (..), EncCBOR (..)) @@ -43,7 +44,14 @@ import Cardano.Ledger.Binary.Coders ( import Cardano.Ledger.CertState (VState, certDStateL, certVStateL, vsDRepsL, vsNumDormantEpochsL) import Cardano.Ledger.Conway.Core import Cardano.Ledger.Conway.Era (ConwayCERT, ConwayCERTS, ConwayEra) -import Cardano.Ledger.Conway.Governance (Voter (DRepVoter), VotingProcedures (unVotingProcedures)) +import Cardano.Ledger.Conway.Governance ( + Committee, + GovActionPurpose (..), + GovActionState, + GovPurposeId, + Voter (DRepVoter), + VotingProcedures (unVotingProcedures), + ) import Cardano.Ledger.Conway.Rules.Cert (CertEnv (CertEnv), ConwayCertEvent, ConwayCertPredFailure) import Cardano.Ledger.Conway.Rules.Deleg (ConwayDelegPredFailure) import Cardano.Ledger.Conway.Rules.GovCert (ConwayGovCertPredFailure, updateDRepExpiry) @@ -82,6 +90,8 @@ data CertsEnv era = CertsEnv , certsPParams :: !(PParams era) , certsSlotNo :: !SlotNo , certsCurrentEpoch :: !EpochNo + , certsCurrentCommittee :: StrictMaybe (Committee era) + , certsCommitteeProposals :: Map.Map (GovPurposeId 'CommitteePurpose era) (GovActionState era) } data ConwayCertsPredFailure era @@ -189,7 +199,7 @@ conwayCertsTransition :: TransitionRule (ConwayCERTS era) conwayCertsTransition = do TRC - ( env@(CertsEnv tx pp slot currentEpoch) + ( env@(CertsEnv tx pp slot currentEpoch committee committeeProposals) , certState , certificates ) <- @@ -240,7 +250,7 @@ conwayCertsTransition = do certState' <- trans @(ConwayCERTS era) $ TRC (env, certState, gamma) trans @(EraRule "CERT" era) $ - TRC (CertEnv slot pp currentEpoch, certState', txCert) + TRC (CertEnv slot pp currentEpoch committee committeeProposals, certState', txCert) instance ( Era era diff --git a/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/GovCert.hs b/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/GovCert.hs index d67297efe39..74b3000defd 100644 --- a/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/GovCert.hs +++ b/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/GovCert.hs @@ -25,7 +25,9 @@ where import Cardano.Ledger.BaseTypes ( EpochNo, ShelleyBase, + StrictMaybe, addEpochInterval, + strictMaybe, ) import Cardano.Ledger.Binary (DecCBOR (..), EncCBOR (..), encodeListLen) import Cardano.Ledger.Binary.Coders @@ -38,6 +40,14 @@ import Cardano.Ledger.CertState ( import Cardano.Ledger.Coin (Coin) import Cardano.Ledger.Conway.Core import Cardano.Ledger.Conway.Era (ConwayEra, ConwayGOVCERT) +import Cardano.Ledger.Conway.Governance ( + Committee (..), + GovAction (..), + GovActionPurpose (..), + GovActionState (..), + GovPurposeId, + ProposalProcedure (..), + ) import Cardano.Ledger.Conway.TxCert (ConwayGovCert (..)) import Cardano.Ledger.Credential (Credential) import Cardano.Ledger.Crypto (Crypto) @@ -56,6 +66,7 @@ import Control.State.Transition.Extended ( TRC (TRC), TransitionRule, failBecause, + failOnJust, judgmentContext, transitionRules, (?!), @@ -71,14 +82,17 @@ import NoThunks.Class (NoThunks (..)) data ConwayGovCertEnv era = ConwayGovCertEnv { cgcePParams :: !(PParams era) , cgceCurrentEpoch :: !EpochNo + , cgceCurrentCommittee :: StrictMaybe (Committee era) + , cgceCommitteeProposals :: Map.Map (GovPurposeId 'CommitteePurpose era) (GovActionState era) + -- ^ All of the `UpdateCommittee` proposals } deriving (Generic) -instance (NFData (PParams era), Era era) => NFData (ConwayGovCertEnv era) +instance EraPParams era => NFData (ConwayGovCertEnv era) -deriving instance Show (PParams era) => Show (ConwayGovCertEnv era) +deriving instance EraPParams era => Show (ConwayGovCertEnv era) -deriving instance Eq (PParams era) => Eq (ConwayGovCertEnv era) +deriving instance EraPParams era => Eq (ConwayGovCertEnv era) data ConwayGovCertPredFailure era = ConwayDRepAlreadyRegistered !(Credential 'DRepRole (EraCrypto era)) @@ -86,6 +100,10 @@ data ConwayGovCertPredFailure era | ConwayDRepIncorrectDeposit !Coin !Coin -- The first is the given and the second is the expected deposit | ConwayCommitteeHasPreviouslyResigned !(Credential 'ColdCommitteeRole (EraCrypto era)) | ConwayDRepIncorrectRefund !Coin !Coin -- The first is the given and the second is the expected refund + | -- | Predicate failure whenever an update to an unknown committee member is + -- attempted. Current Constitutional Committee and all available proposals will be + -- searched before reporting this predicate failure. + ConwayCommitteeIsUnknown !(Credential 'ColdCommitteeRole (EraCrypto era)) deriving (Show, Eq, Generic) type instance EraRuleFailure "GOVCERT" (ConwayEra c) = ConwayGovCertPredFailure (ConwayEra c) @@ -116,15 +134,19 @@ instance <> encCBOR (2 :: Word8) <> encCBOR deposit <> encCBOR expectedDeposit - ConwayCommitteeHasPreviouslyResigned keyH -> + ConwayCommitteeHasPreviouslyResigned coldCred -> encodeListLen 2 <> encCBOR (3 :: Word8) - <> encCBOR keyH + <> encCBOR coldCred ConwayDRepIncorrectRefund refund expectedRefund -> encodeListLen 3 <> encCBOR (4 :: Word8) <> encCBOR refund <> encCBOR expectedRefund + ConwayCommitteeIsUnknown coldCred -> + encodeListLen 2 + <> encCBOR (5 :: Word8) + <> encCBOR coldCred instance (Typeable era, Crypto (EraCrypto era)) => @@ -143,12 +165,15 @@ instance expectedDeposit <- decCBOR pure (3, ConwayDRepIncorrectDeposit deposit expectedDeposit) 3 -> do - keyH <- decCBOR - pure (2, ConwayCommitteeHasPreviouslyResigned keyH) + coldCred <- decCBOR + pure (2, ConwayCommitteeHasPreviouslyResigned coldCred) 4 -> do refund <- decCBOR expectedRefund <- decCBOR pure (3, ConwayDRepIncorrectRefund refund expectedRefund) + 5 -> do + coldCred <- decCBOR + pure (2, ConwayCommitteeIsUnknown coldCred) k -> invalidKey k instance @@ -175,14 +200,33 @@ conwayGovCertTransition :: ConwayEraPParams era => TransitionRule (ConwayGOVCERT era) conwayGovCertTransition = do TRC - ( ConwayGovCertEnv {cgcePParams, cgceCurrentEpoch} + ( ConwayGovCertEnv {cgcePParams, cgceCurrentEpoch, cgceCurrentCommittee, cgceCommitteeProposals} , vState@VState {vsDReps} - , c + , cert ) <- judgmentContext let ppDRepDeposit = cgcePParams ^. ppDRepDepositL ppDRepActivity = cgcePParams ^. ppDRepActivityL - case c of + checkAndOverwriteCommitteeMemberState coldCred newMemberState = do + let VState {vsCommitteeState = CommitteeState csCommitteeCreds} = vState + coldCredResigned = + Map.lookup coldCred csCommitteeCreds >>= \case + CommitteeMemberResigned {} -> Just coldCred + CommitteeHotCredential {} -> Nothing + failOnJust coldCredResigned ConwayCommitteeHasPreviouslyResigned + let isCurrentMember = + strictMaybe False (Map.member coldCred . committeeMembers) cgceCurrentCommittee + isPotentialFutureMember = + any (committeeUpdateContainsColdCred coldCred) cgceCommitteeProposals + isCurrentMember || isPotentialFutureMember ?! ConwayCommitteeIsUnknown coldCred + pure + vState + { vsCommitteeState = + CommitteeState + { csCommitteeCreds = Map.insert coldCred newMemberState csCommitteeCreds + } + } + case cert of ConwayRegDRep cred deposit mAnchor -> do Map.notMember cred vsDReps ?! ConwayDRepAlreadyRegistered cred deposit == ppDRepDeposit ?! ConwayDRepIncorrectDeposit deposit ppDRepDeposit @@ -201,11 +245,7 @@ conwayGovCertTransition = do let paidDeposit = drepState ^. drepDepositL in refund == paidDeposit ?! ConwayDRepIncorrectRefund refund paidDeposit pure vState {vsDReps = Map.delete cred vsDReps} - ConwayAuthCommitteeHotKey coldCred hotCred -> - checkAndOverwriteCommitteeHotCred vState coldCred $ CommitteeHotCredential hotCred - ConwayResignCommitteeColdKey coldCred anchor -> - checkAndOverwriteCommitteeHotCred vState coldCred $ CommitteeMemberResigned anchor - -- Update a DRep expiry too along with its anchor. + -- Update a DRep expiry along with its anchor. ConwayUpdateDRep cred mAnchor -> do Map.member cred vsDReps ?! ConwayDRepNotRegistered cred pure @@ -222,20 +262,15 @@ conwayGovCertTransition = do cred vsDReps } + ConwayAuthCommitteeHotKey coldCred hotCred -> + checkAndOverwriteCommitteeMemberState coldCred $ CommitteeHotCredential hotCred + ConwayResignCommitteeColdKey coldCred anchor -> + checkAndOverwriteCommitteeMemberState coldCred $ CommitteeMemberResigned anchor where - checkColdCredHasNotResigned coldCred csCommitteeCreds = - case Map.lookup coldCred csCommitteeCreds of - Just (CommitteeMemberResigned _) -> failBecause $ ConwayCommitteeHasPreviouslyResigned coldCred - _ -> pure () - checkAndOverwriteCommitteeHotCred vState@VState {vsCommitteeState = CommitteeState csCommitteeCreds} coldCred hotCred = do - checkColdCredHasNotResigned coldCred csCommitteeCreds - pure - vState - { vsCommitteeState = - CommitteeState - { csCommitteeCreds = Map.insert coldCred hotCred csCommitteeCreds - } - } + committeeUpdateContainsColdCred coldCred GovActionState {gasProposalProcedure} = + case pProcGovAction gasProposalProcedure of + UpdateCommittee _ _ newMembers _ -> Map.member coldCred newMembers + _ -> False updateDRepExpiry :: -- | DRepActivity PParam diff --git a/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Ledger.hs b/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Ledger.hs index 6b9ea7c67e9..9ddfc8c1c63 100644 --- a/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Ledger.hs +++ b/eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Ledger.hs @@ -42,7 +42,7 @@ import Cardano.Ledger.BaseTypes (ShelleyBase, StrictMaybe (..), epochInfoPure) import Cardano.Ledger.Binary (DecCBOR (..), EncCBOR (..)) import Cardano.Ledger.Binary.Coders import Cardano.Ledger.Coin (Coin) -import Cardano.Ledger.Conway.Core +import Cardano.Ledger.Conway.Core hiding (proposals) import Cardano.Ledger.Conway.Era ( ConwayCERTS, ConwayDELEG, @@ -57,7 +57,9 @@ import Cardano.Ledger.Conway.Governance ( GovProcedures (..), Proposals, constitutionScriptL, + grCommitteeL, proposalsGovStateL, + proposalsWithPurpose, ) import Cardano.Ledger.Conway.Rules.Cert (CertEnv, ConwayCertEvent (..), ConwayCertPredFailure (..)) import Cardano.Ledger.Conway.Rules.Certs ( @@ -365,10 +367,14 @@ ledgerTransition = do (utxoState', certStateAfterCERTS) <- if tx ^. isValidTxL == IsValid True then do + let govState = utxoState ^. utxosGovStateL + committee = govState ^. committeeGovStateL + proposals = govState ^. proposalsGovStateL + committeeProposals = proposalsWithPurpose grCommitteeL proposals certStateAfterCERTS <- trans @(EraRule "CERTS" era) $ TRC - ( CertsEnv tx pp slot currentEpoch + ( CertsEnv tx pp slot currentEpoch committee committeeProposals , certState , StrictSeq.fromStrict $ txBody ^. certsTxBodyL ) @@ -395,9 +401,9 @@ ledgerTransition = do (txIdTxBody txBody) currentEpoch pp - (utxoState ^. utxosGovStateL . constitutionGovStateL . constitutionScriptL) + (govState ^. constitutionGovStateL . constitutionScriptL) (certState ^. certVStateL . vsCommitteeStateL) - , utxoState ^. utxosGovStateL . proposalsGovStateL + , proposals , govProcedures ) let utxoState' = diff --git a/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/GovCertSpec.hs b/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/GovCertSpec.hs index a8c13ed7f35..6bd1831a3ff 100644 --- a/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/GovCertSpec.hs +++ b/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/GovCertSpec.hs @@ -14,6 +14,7 @@ module Test.Cardano.Ledger.Conway.Imp.GovCertSpec ( relevantDuringBootstrapSpec, ) where +import Cardano.Ledger.BaseTypes (EpochNo (..)) import Cardano.Ledger.Coin (Coin (..)) import Cardano.Ledger.Conway.Core ( EraGov (..), @@ -65,9 +66,18 @@ spec :: SpecWith (ImpTestState era) spec = do relevantDuringBootstrapSpec - it - "A CC that has resigned will need to be first voted out and then voted in to be considered active" - $ do + it "Authorizing proposed CC key" $ do + someCred <- KeyHashObj <$> freshKeyHash + submitGovAction_ $ + UpdateCommittee SNothing mempty (Map.singleton someCred (EpochNo 1234)) (1 %! 2) + submitTx_ + ( mkBasicTx mkBasicTxBody + & bodyTxL . certsTxBodyL + .~ SSeq.singleton (ResignCommitteeColdTxCert someCred SNothing) + ) + -- A CC that has resigned will need to be first voted out and then voted in to be considered active + it "CC re-election" $ + do (drepCred, _, _) <- setupSingleDRep 1_000_000 passNEpochs 2 -- Add a fresh CC @@ -142,11 +152,12 @@ relevantDuringBootstrapSpec = do .~ SSeq.singleton (UnRegDRepTxCert drepCred drepDeposit) it "resigning a non-CC key" $ do someCred <- KeyHashObj <$> freshKeyHash - submitTx_ + submitFailingTx ( mkBasicTx mkBasicTxBody & bodyTxL . certsTxBodyL .~ SSeq.singleton (ResignCommitteeColdTxCert someCred SNothing) ) + (pure (injectFailure $ ConwayCommitteeIsUnknown someCred)) it "re-registering a CC hot key" $ do void registerInitialCommittee initialCommittee <- getCommitteeMembers diff --git a/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/UtxosSpec.hs b/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/UtxosSpec.hs index 13ffedd2500..48a36361420 100644 --- a/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/UtxosSpec.hs +++ b/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/UtxosSpec.hs @@ -402,22 +402,22 @@ conwayFeaturesPlutusV1V2FailureSpec = do testCertificateNotSupportedV2 regDepositDelegTxCert describe "AuthCommitteeHotKeyTxCert" $ do it "V1" $ do - coldKey <- KeyHashObj <$> freshKeyHash + coldKey <- elements . Set.toList =<< getCommitteeMembers hotKey <- KeyHashObj <$> freshKeyHash let authCommitteeHotKeyTxCert = AuthCommitteeHotKeyTxCert @era coldKey hotKey testCertificateNotSupportedV1 authCommitteeHotKeyTxCert it "V2" $ do - coldKey <- KeyHashObj <$> freshKeyHash + coldKey <- elements . Set.toList =<< getCommitteeMembers hotKey <- KeyHashObj <$> freshKeyHash let authCommitteeHotKeyTxCert = AuthCommitteeHotKeyTxCert @era coldKey hotKey testCertificateNotSupportedV2 authCommitteeHotKeyTxCert describe "ResignCommitteeColdTxCert" $ do it "V1" $ do - coldKey <- KeyHashObj <$> freshKeyHash + coldKey <- elements . Set.toList =<< getCommitteeMembers let resignCommitteeColdTxCert = ResignCommitteeColdTxCert @era coldKey SNothing testCertificateNotSupportedV1 resignCommitteeColdTxCert it "V2" $ do - coldKey <- KeyHashObj <$> freshKeyHash + coldKey <- elements . Set.toList =<< getCommitteeMembers let resignCommitteeColdTxCert = ResignCommitteeColdTxCert @era coldKey SNothing testCertificateNotSupportedV2 resignCommitteeColdTxCert describe "RegDRepTxCert" $ do diff --git a/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/TreeDiff.hs b/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/TreeDiff.hs index 2c9b961aa7b..4c51b6a6457 100644 --- a/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/TreeDiff.hs +++ b/eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/TreeDiff.hs @@ -234,7 +234,11 @@ instance instance ToExpr (PParams era) => ToExpr (GovEnv era) -instance ToExpr (PParams era) => ToExpr (ConwayGovCertEnv era) +instance + ( ToExpr (PParams era) + , ToExpr (PParamsHKD StrictMaybe era) + ) => + ToExpr (ConwayGovCertEnv era) instance ( ToExpr (Value era) @@ -252,7 +256,11 @@ instance ) => ToExpr (ConwayUtxowPredFailure era) -instance ToExpr (PParams era) => ToExpr (CertEnv era) +instance + ( ToExpr (PParams era) + , ToExpr (PParamsHKD StrictMaybe era) + ) => + ToExpr (CertEnv era) instance ToExpr (PParams era) => ToExpr (ConwayDelegEnv era) diff --git a/eras/conway/test-suite/cardano-ledger-conway-test.cabal b/eras/conway/test-suite/cardano-ledger-conway-test.cabal index 54d566e3cf6..2ea07af0b2d 100644 --- a/eras/conway/test-suite/cardano-ledger-conway-test.cabal +++ b/eras/conway/test-suite/cardano-ledger-conway-test.cabal @@ -1,6 +1,6 @@ cabal-version: 3.0 name: cardano-ledger-conway-test -version: 1.2.1.6 +version: 1.2.1.7 license: Apache-2.0 maintainer: operations@iohk.io author: IOHK @@ -36,7 +36,7 @@ library cardano-ledger-babbage >=1.3 && <1.9, cardano-ledger-babbage-test >=1.1.1, cardano-ledger-binary >=1.0, - cardano-ledger-conway:{cardano-ledger-conway, testlib} >=1.15 && <1.16, + cardano-ledger-conway:{cardano-ledger-conway, testlib} >=1.15 && <1.17, cardano-ledger-core:{cardano-ledger-core, testlib} >=1.11, cardano-ledger-mary >=1.4, cardano-ledger-shelley-ma-test >=1.1, diff --git a/libs/cardano-ledger-api/cardano-ledger-api.cabal b/libs/cardano-ledger-api/cardano-ledger-api.cabal index f59a4a60e31..47a8b76d9ce 100644 --- a/libs/cardano-ledger-api/cardano-ledger-api.cabal +++ b/libs/cardano-ledger-api/cardano-ledger-api.cabal @@ -1,6 +1,6 @@ cabal-version: 3.0 name: cardano-ledger-api -version: 1.9.2.0 +version: 1.9.2.1 license: Apache-2.0 maintainer: operations@iohk.io author: IOHK @@ -58,7 +58,7 @@ library cardano-ledger-alonzo ^>=1.9, cardano-ledger-babbage ^>=1.8.1, cardano-ledger-binary ^>=1.3, - cardano-ledger-conway >=1.13 && <1.16, + cardano-ledger-conway >=1.13 && <1.17, cardano-ledger-core ^>=1.13, cardano-ledger-mary >=1.5 && <1.7, cardano-ledger-shelley ^>=1.12, diff --git a/libs/cardano-ledger-api/test/Test/Cardano/Ledger/Api/State/Imp/QuerySpec.hs b/libs/cardano-ledger-api/test/Test/Cardano/Ledger/Api/State/Imp/QuerySpec.hs index efb9631190a..73c0fa6f800 100644 --- a/libs/cardano-ledger-api/test/Test/Cardano/Ledger/Api/State/Imp/QuerySpec.hs +++ b/libs/cardano-ledger-api/test/Test/Cardano/Ledger/Api/State/Imp/QuerySpec.hs @@ -24,14 +24,13 @@ import Cardano.Ledger.Conway.Governance ( ConwayEraGov (..), ConwayGovState, EraGov (..), + GovAction (..), ) import Cardano.Ledger.Conway.PParams (ppDRepActivityL) import Cardano.Ledger.Core import Cardano.Ledger.Credential (Credential (KeyHashObj)) import Cardano.Ledger.DRep -import Cardano.Ledger.Keys ( - KeyRole (..), - ) +import Cardano.Ledger.Keys (KeyRole (..)) import Cardano.Ledger.Shelley.LedgerState import Data.Default (def) import Data.Foldable (Foldable (..)) @@ -41,6 +40,7 @@ import qualified Data.Set as Set import Lens.Micro import Lens.Micro.Mtl import Test.Cardano.Ledger.Conway.ImpTest +import Test.Cardano.Ledger.Core.Rational ((%!)) import Test.Cardano.Ledger.Imp.Common spec :: @@ -128,12 +128,15 @@ spec = do isDRepExpired drep `shouldReturn` True describe "Committee members hot key pre-authorization" $ do it "authorized members not elected get removed in the next epoch" $ do - c1 <- KeyHashObj <$> freshKeyHash - hk1 <- registerCommitteeHotKey c1 - expectQueryResult (Set.singleton c1) mempty mempty $ - [(c1, CommitteeMemberState (MemberAuthorized hk1) Unrecognized Nothing ToBeRemoved)] - passEpoch - expectQueryResult (Set.singleton c1) mempty mempty Map.empty + whenPostBootstrap $ do + c1 <- KeyHashObj <$> freshKeyHash + submitGovAction_ $ + UpdateCommittee SNothing mempty (Map.singleton c1 (EpochNo 4321)) (1 %! 1) + hk1 <- registerCommitteeHotKey c1 + expectQueryResult (Set.singleton c1) mempty mempty $ + [(c1, CommitteeMemberState (MemberAuthorized hk1) Unrecognized Nothing ToBeRemoved)] + passEpoch + expectQueryResult (Set.singleton c1) mempty mempty Map.empty it "members should remain authorized if authorized during the epoch after their election" $ whenPostBootstrap $ do diff --git a/libs/cardano-ledger-conformance/src/Test/Cardano/Ledger/Conformance.hs b/libs/cardano-ledger-conformance/src/Test/Cardano/Ledger/Conformance.hs index 56e31872b29..e386572239e 100644 --- a/libs/cardano-ledger-conformance/src/Test/Cardano/Ledger/Conformance.hs +++ b/libs/cardano-ledger-conformance/src/Test/Cardano/Ledger/Conformance.hs @@ -1,12 +1,3 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE DataKinds #-} -{-# LANGUAGE FlexibleContexts #-} -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE PolyKinds #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TypeFamilyDependencies #-} -{-# LANGUAGE UndecidableInstances #-} - module Test.Cardano.Ledger.Conformance ( module Test.Cardano.Ledger.Conformance.ExecSpecRule.Core, module Test.Cardano.Ledger.Conformance.SpecTranslate.Core, diff --git a/libs/cardano-ledger-conformance/src/Test/Cardano/Ledger/Conformance/Spec/Conway.hs b/libs/cardano-ledger-conformance/src/Test/Cardano/Ledger/Conformance/Spec/Conway.hs index bb334302c23..5332eb5ad8d 100644 --- a/libs/cardano-ledger-conformance/src/Test/Cardano/Ledger/Conformance/Spec/Conway.hs +++ b/libs/cardano-ledger-conformance/src/Test/Cardano/Ledger/Conformance/Spec/Conway.hs @@ -18,7 +18,7 @@ spec = describe "Conway conformance tests" $ do prop "GOV" $ conformsToImpl @"GOV" @ConwayFn @Conway prop "CERT" $ conformsToImpl @"CERT" @ConwayFn @Conway xprop "RATIFY" $ conformsToImpl @"RATIFY" @ConwayFn @Conway - prop "GOVCERT" $ conformsToImpl @"GOVCERT" @ConwayFn @Conway + xprop "GOVCERT" $ conformsToImpl @"GOVCERT" @ConwayFn @Conway xprop "ENACT" $ conformsToImpl @"ENACT" @ConwayFn @Conway prop "DELEG" $ conformsToImpl @"DELEG" @ConwayFn @Conway prop "POOL" $ conformsToImpl @"POOL" @ConwayFn @Conway diff --git a/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Constrained/Conway/Cert.hs b/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Constrained/Conway/Cert.hs index 6ed1d8348db..c7da84415c1 100644 --- a/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Constrained/Conway/Cert.hs +++ b/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Constrained/Conway/Cert.hs @@ -25,7 +25,7 @@ certEnvSpec :: Specification fn (CertEnv (ConwayEra StandardCrypto)) certEnvSpec = constrained $ \ce -> - match ce $ \_ pp _ -> + match ce $ \_ pp _ _ _ -> satisfies pp pparamsSpec certStateSpec :: @@ -44,12 +44,12 @@ txCertSpec :: CertEnv (ConwayEra StandardCrypto) -> CertState (ConwayEra StandardCrypto) -> Specification fn (ConwayTxCert (ConwayEra StandardCrypto)) -txCertSpec (CertEnv slot pp ce) CertState {..} = +txCertSpec (CertEnv slot pp ce cc cp) CertState {..} = constrained $ \txCert -> caseOn txCert (branch $ \delegCert -> satisfies delegCert $ delegCertSpec delegEnv certDState) (branch $ \poolCert -> satisfies poolCert $ poolCertSpec (PoolEnv slot pp) certPState) - (branch $ \govCert -> satisfies govCert $ govCertSpec (ConwayGovCertEnv pp ce) certVState) + (branch $ \govCert -> satisfies govCert $ govCertSpec (ConwayGovCertEnv pp ce cc cp) certVState) where delegEnv = ConwayDelegEnv pp (psStakePoolParams certPState) diff --git a/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Constrained/Conway/GovCert.hs b/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Constrained/Conway/GovCert.hs index e30e72c0ab1..fc5d9084a9d 100644 --- a/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Constrained/Conway/GovCert.hs +++ b/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Constrained/Conway/GovCert.hs @@ -1,4 +1,5 @@ {-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards #-} -- | Specs necessary to generate, environment, state, and signal @@ -6,6 +7,7 @@ module Test.Cardano.Ledger.Constrained.Conway.GovCert where import Cardano.Ledger.CertState +import Cardano.Ledger.Conway.Governance import Cardano.Ledger.Conway.PParams import Cardano.Ledger.Conway.Rules import Cardano.Ledger.Conway.TxCert @@ -30,6 +32,14 @@ govCertSpec :: govCertSpec ConwayGovCertEnv {..} vs = let reps = lit $ Map.keysSet $ vsDReps vs deposits = lit [(k, drepDeposit dep) | (k, dep) <- Map.toList $ vsDReps vs] + getNewMembers = \case + UpdateCommittee _ _ newMembers _ -> Map.keysSet newMembers + _ -> mempty + knownColdCreds = + Map.keysSet (foldMap committeeMembers cgceCurrentCommittee) + <> foldMap (getNewMembers . pProcGovAction . gasProposalProcedure) cgceCommitteeProposals + ccCertSpec coldCred = + assert . member_ coldCred $ lit knownColdCreds in constrained $ \gc -> caseOn gc @@ -48,14 +58,14 @@ govCertSpec ConwayGovCertEnv {..} vs = member_ key reps ) -- ConwayAuthCommitteeHotKey - (branch $ \_ _ -> True) + (branch $ \coldCred _ -> ccCertSpec coldCred) -- ConwayResignCommitteeColdKey - (branch $ \_ _ -> True) + (branch $ \coldCred _ -> ccCertSpec coldCred) govCertEnvSpec :: IsConwayUniv fn => Specification fn (ConwayGovCertEnv (ConwayEra StandardCrypto)) govCertEnvSpec = constrained $ \gce -> - match gce $ \pp _ -> + match gce $ \pp _ _ _ -> satisfies pp pparamsSpec diff --git a/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Generic/PrettyCore.hs b/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Generic/PrettyCore.hs index aa52270ff08..b32d043b1e8 100644 --- a/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Generic/PrettyCore.hs +++ b/libs/cardano-ledger-test/src/Test/Cardano/Ledger/Generic/PrettyCore.hs @@ -1503,6 +1503,7 @@ ppConwayGovCertPredFailure z = case z of ConwayDRepIncorrectDeposit c1 c2 -> ppSexp "ConwayDRepIncorrectDeposit" [pcCoin c1, pcCoin c2] ConwayCommitteeHasPreviouslyResigned x -> ppSexp "ConwayCommitteeHasPreviouslyResigned" [pcCredential x] ConwayDRepIncorrectRefund c1 c2 -> ppSexp "ConwayDRepIncorrectRefund" [pcCoin c1, pcCoin c2] + ConwayCommitteeIsUnknown c -> ppSexp "ConwayCommitteeIsUnknown" [pcCredential c] instance PrettyA (ConwayGovCertPredFailure era) where prettyA = ppConwayGovCertPredFailure @@ -3539,7 +3540,14 @@ summaryMapCompact x = ppString ("Count " ++ show (Map.size x) ++ ", Total " ++ s -- ======================== pcConwayGovCertEnv :: forall era. Reflect era => ConwayGovCertEnv era -> PDoc -pcConwayGovCertEnv (ConwayGovCertEnv pp ce) = ppSexp "ConwayGovCertEnv" [pcPParams @era reify pp, ppEpochNo ce] +pcConwayGovCertEnv (ConwayGovCertEnv pp ce cc cp) = + ppSexp + "ConwayGovCertEnv" + [ pcPParams @era reify pp + , ppEpochNo ce + , ppStrictMaybe pcCommittee cc + , ppMap pcGovActionId pcGovActionState $ Map.mapKeys unGovPurposeId cp + ] instance Reflect era => PrettyA (ConwayGovCertEnv era) where prettyA = pcConwayGovCertEnv