Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow empty TreasuryWithdrawals #4630

Merged
merged 4 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eras/conway/impl/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 1.17.0.0

* Add `ZeroTreasuryWithdrawals` to `ConwayGovPredFailure`
* Add `ProtVer` argument to `TxInfo` functions:
* `transTxCert`
* `transScriptPurpose`
Expand Down
1 change: 1 addition & 0 deletions eras/conway/impl/cardano-ledger-conway.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ library testlib
Test.Cardano.Ledger.Conway.ImpTest
Test.Cardano.Ledger.Conway.Imp
Test.Cardano.Ledger.Conway.Imp.BbodySpec
Test.Cardano.Ledger.Conway.Imp.CertsSpec
Test.Cardano.Ledger.Conway.Imp.DelegSpec
Test.Cardano.Ledger.Conway.Imp.EpochSpec
Test.Cardano.Ledger.Conway.Imp.EnactSpec
Expand Down
8 changes: 8 additions & 0 deletions eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Gov.hs
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ data ConwayGovPredFailure era
(NonEmpty (Voter (EraCrypto era), GovActionId (EraCrypto era)))
| -- | Predicate failure for votes by entities that are not present in the ledger state
VotersDoNotExist (NonEmpty (Voter (EraCrypto era)))
| -- | Treasury withdrawals that sum up to zero are not allowed
ZeroTreasuryWithdrawals (GovAction era)
deriving (Eq, Show, Generic)

type instance EraRuleFailure "GOV" (ConwayEra c) = ConwayGovPredFailure (ConwayEra c)
Expand Down Expand Up @@ -222,6 +224,7 @@ instance EraPParams era => DecCBOR (ConwayGovPredFailure era) where
12 -> SumD DisallowedProposalDuringBootstrap <! From
13 -> SumD DisallowedVotesDuringBootstrap <! From
14 -> SumD VotersDoNotExist <! From
15 -> SumD ZeroTreasuryWithdrawals <! From
k -> Invalid k

instance EraPParams era => EncCBOR (ConwayGovPredFailure era) where
Expand Down Expand Up @@ -260,6 +263,8 @@ instance EraPParams era => EncCBOR (ConwayGovPredFailure era) where
Sum DisallowedVotesDuringBootstrap 13 !> To votes
VotersDoNotExist voters ->
Sum VotersDoNotExist 14 !> To voters
ZeroTreasuryWithdrawals ga ->
Sum ZeroTreasuryWithdrawals 15 !> To ga

instance EraPParams era => ToCBOR (ConwayGovPredFailure era) where
toCBOR = toEraCBOR @era
Expand Down Expand Up @@ -461,6 +466,9 @@ govTransition = do

-- Policy check
runTest $ checkPolicy @era constitutionPolicy proposalPolicy

-- The sum of all withdrawals must be positive
F.fold wdrls /= mempty ?! ZeroTreasuryWithdrawals pProcGovAction
UpdateCommittee _mPrevGovActionId membersToRemove membersToAdd _qrm -> do
checkConflictingUpdate
checkExpirationEpoch
Expand Down
4 changes: 4 additions & 0 deletions eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Cardano.Ledger.BaseTypes (Inject, natVersion)
import Cardano.Ledger.Conway.Core
import Cardano.Ledger.Conway.Rules (
ConwayBbodyPredFailure,
ConwayCertsPredFailure,
ConwayDelegPredFailure,
ConwayEpochEvent,
ConwayGovCertPredFailure,
Expand All @@ -33,6 +34,7 @@ import Data.Typeable (Typeable)
import qualified Test.Cardano.Ledger.Babbage.Imp as BabbageImp
import Test.Cardano.Ledger.Common
import qualified Test.Cardano.Ledger.Conway.Imp.BbodySpec as Bbody
import qualified Test.Cardano.Ledger.Conway.Imp.CertsSpec as Certs
import qualified Test.Cardano.Ledger.Conway.Imp.DelegSpec as Deleg
import qualified Test.Cardano.Ledger.Conway.Imp.EnactSpec as Enact
import qualified Test.Cardano.Ledger.Conway.Imp.EpochSpec as Epoch
Expand All @@ -50,6 +52,7 @@ spec ::
, ConwayEraImp era
, EraSegWits era
, InjectRuleFailure "LEDGER" ConwayGovPredFailure era
, InjectRuleFailure "LEDGER" ConwayCertsPredFailure era
, Inject (BabbageContextError era) (ContextError era)
, Inject (ConwayContextError era) (ContextError era)
, InjectRuleFailure "LEDGER" BabbageUtxoPredFailure era
Expand Down Expand Up @@ -89,6 +92,7 @@ spec = do
describe "ConwayImpSpec - bootstrap phase (protocol version 9)" $
withImpState @era $ do
describe "BBODY" $ Bbody.spec @era
describe "CERTS" $ Certs.spec @era
describe "DELEG" $ Deleg.spec @era
describe "ENACT" $ Enact.relevantDuringBootstrapSpec @era
describe "EPOCH" $ Epoch.relevantDuringBootstrapSpec @era
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NumericUnderscores #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}

module Test.Cardano.Ledger.Conway.Imp.CertsSpec (spec) where

import Cardano.Ledger.BaseTypes (EpochInterval (..))
import Cardano.Ledger.Coin (Coin (..))
import Cardano.Ledger.Conway.Core
import Cardano.Ledger.Conway.Rules (ConwayCertsPredFailure (..))
import Cardano.Ledger.Credential (Credential (..))
import Cardano.Ledger.Val (Val (..))
import Lens.Micro ((&), (.~))
import Test.Cardano.Ledger.Conway.Arbitrary ()
import Test.Cardano.Ledger.Conway.ImpTest
import Test.Cardano.Ledger.Imp.Common

spec ::
forall era.
( ConwayEraImp era
, InjectRuleFailure "LEDGER" ConwayCertsPredFailure era
) =>
SpecWith (ImpTestState era)
spec = do
describe "Withdrawals" $ do
it "Withdrawing from an unregistered reward account" $ do
modifyPParams $ ppGovActionLifetimeL .~ EpochInterval 2

rwdAccount <- KeyHashObj <$> freshKeyHash >>= getRewardAccountFor
submitFailingTx
( mkBasicTx $
mkBasicTxBody
& withdrawalsTxBodyL
.~ Withdrawals
[(rwdAccount, Coin 20)]
)
[injectFailure $ WithdrawalsNotInRewardsCERTS [(rwdAccount, Coin 20)]]

(registeredRwdAccount, reward) <- setupRewardAccount
submitFailingTx
( mkBasicTx $
mkBasicTxBody
& withdrawalsTxBodyL
.~ Withdrawals
[(rwdAccount, zero), (registeredRwdAccount, reward)]
)
[injectFailure $ WithdrawalsNotInRewardsCERTS [(rwdAccount, zero)]]

it "Withdrawing the wrong amount" $ do
modifyPParams $ ppGovActionLifetimeL .~ EpochInterval 2

(rwdAccount1, reward1) <- setupRewardAccount
(rwdAccount2, reward2) <- setupRewardAccount
submitFailingTx
( mkBasicTx $
mkBasicTxBody
& withdrawalsTxBodyL
.~ Withdrawals
[ (rwdAccount1, reward1 <+> Coin 1)
, (rwdAccount2, reward2)
]
)
[injectFailure $ WithdrawalsNotInRewardsCERTS [(rwdAccount1, reward1 <+> Coin 1)]]

submitFailingTx
( mkBasicTx $
mkBasicTxBody
& withdrawalsTxBodyL
.~ Withdrawals
[(rwdAccount1, zero)]
)
[injectFailure $ WithdrawalsNotInRewardsCERTS [(rwdAccount1, zero)]]
teodanciu marked this conversation as resolved.
Show resolved Hide resolved
where
setupRewardAccount = do
cred <- KeyHashObj <$> freshKeyHash
ra <- registerStakeCredential cred
submitAndExpireProposalToMakeReward cred
rw <- lookupReward cred
pure (ra, rw)
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ treasuryWithdrawalsSpec =
it "Withdrawals exceeding treasury submitted in several proposals within the same epoch" $ do
committeeCs <- registerInitialCommittee
(drepC, _, _) <- setupSingleDRep 1_000_000
donateToTreasury $ Coin 5_000_000
initialTreasury <- getTreasury
numWithdrawals <- choose (1, 10)
withdrawals <- genWithdrawalsExceeding initialTreasury numWithdrawals
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import Cardano.Ledger.Coin (Coin (Coin))
import Cardano.Ledger.Conway.Core
import Cardano.Ledger.Conway.Governance
import Cardano.Ledger.Conway.Rules (ConwayGovPredFailure (..))
import Cardano.Ledger.Credential (Credential (KeyHashObj))
import Cardano.Ledger.Credential (Credential (KeyHashObj), StakeCredential)
import Cardano.Ledger.Plutus.CostModels (updateCostModels)
import qualified Cardano.Ledger.Shelley.HardForks as HF
import Cardano.Ledger.Shelley.LedgerState
Expand All @@ -31,8 +31,10 @@ import Cardano.Ledger.Shelley.Scripts (
pattern RequireSignature,
)
import Cardano.Ledger.Val (zero, (<->))
import Control.Monad (forM)
import Data.Default.Class (Default (..))
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NE
import qualified Data.Map.Strict as Map
import Data.Maybe (fromJust)
import qualified Data.OMap.Strict as OMap
Expand All @@ -57,7 +59,7 @@ spec = do
proposalsWithVotingSpec
votingSpec
policySpec
networkIdWithdrawalsSpec
withdrawalsSpec
predicateFailuresSpec
unknownCostModelsSpec

Expand Down Expand Up @@ -489,7 +491,17 @@ proposalsWithVotingSpec =
returnAddr <- registerRewardAccount
deposit <- getsNES $ nesEsL . curPParamsEpochStateL . ppGovActionDepositL
ens <- getEnactState
withdrawals <- arbitrary
withdrawals <- do
creds <- arbitrary :: ImpTestM era (NonEmpty (StakeCredential (EraCrypto era)))
pairs <-
forM
creds
( \cred -> do
Positive n <- arbitrary
ac <- getRewardAccountFor cred
pure (ac, Coin n)
)
pure $ Map.fromList (NE.toList pairs)
let
mkProp name action = do
ProposalProcedure
Expand Down Expand Up @@ -1133,14 +1145,14 @@ networkIdSpec =
Testnet
]

networkIdWithdrawalsSpec ::
withdrawalsSpec ::
forall era.
( ConwayEraImp era
, InjectRuleFailure "LEDGER" ConwayGovPredFailure era
) =>
SpecWith (ImpTestState era)
networkIdWithdrawalsSpec =
describe "Network ID" $ do
withdrawalsSpec =
describe "Withdrawals" $ do
it "Fails with invalid network ID in withdrawal addresses" $ do
rewardAccount <- registerRewardAccount
rewardCredential <- KeyHashObj <$> freshKeyHash
Expand All @@ -1166,6 +1178,32 @@ networkIdWithdrawalsSpec =
Testnet
]

it "Fails for empty withdrawals" $ do
rwdAccount1 <- freshKeyHash >>= getRewardAccountFor . KeyHashObj
rwdAccount2 <- freshKeyHash >>= getRewardAccountFor . KeyHashObj
let wdrl = TreasuryWithdrawals Map.empty SNothing
in submitFailingGovAction
wdrl
[injectFailure $ ZeroTreasuryWithdrawals wdrl]

let wdrl = TreasuryWithdrawals [(rwdAccount1, zero)] SNothing
in submitFailingGovAction
wdrl
[injectFailure $ ZeroTreasuryWithdrawals wdrl]

let wdrl = TreasuryWithdrawals [(rwdAccount1, zero), (rwdAccount2, zero)] SNothing
in submitFailingGovAction
wdrl
[injectFailure $ ZeroTreasuryWithdrawals wdrl]

rwdAccountRegistered <- registerRewardAccount
let wdrl = TreasuryWithdrawals [(rwdAccountRegistered, zero)] SNothing
in submitFailingGovAction
wdrl
[injectFailure $ ZeroTreasuryWithdrawals wdrl]

void $ submitTreasuryWithdrawals [(rwdAccount1, zero), (rwdAccount2, Coin 100000)]

proposalWithRewardAccount ::
forall era.
ConwayEraImp era =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Cardano.Ledger.DRep
import Cardano.Ledger.Plutus (SLanguage (..), hashPlutusScript)
import Cardano.Ledger.SafeHash (originalBytesSize)
import qualified Cardano.Ledger.Shelley.HardForks as HF (bootstrapPhase)
import Data.Default.Class (def)
import qualified Data.Set as Set
import Lens.Micro ((&), (.~))
import Test.Cardano.Ledger.Conway.ImpTest
Expand Down Expand Up @@ -73,6 +74,82 @@ spec = do
.~ Withdrawals
[(ra, if HF.bootstrapPhase pv then mempty else reward)]

it "Withdraw from a key delegated to an unregistered DRep" $ do
modifyPParams $ ppGovActionLifetimeL .~ EpochInterval 2
kh <- freshKeyHash
let cred = KeyHashObj kh
ra <- registerStakeCredential cred
submitAndExpireProposalToMakeReward cred
reward <- lookupReward cred

(drep, _, _) <- setupSingleDRep 1_000_000

_ <- delegateToDRep cred (Coin 1_000_000) (DRepCredential drep)

unRegisterDRep drep
expectDRepNotRegistered drep

submitTx_ $
mkBasicTx $
mkBasicTxBody
& withdrawalsTxBodyL
.~ Withdrawals
[(ra, reward)]

it "Withdraw from a key delegated to an expired DRep" $ do
modifyPParams $ \pp ->
pp
& ppGovActionLifetimeL .~ EpochInterval 4
& ppDRepActivityL .~ EpochInterval 1
kh <- freshKeyHash
let cred = KeyHashObj kh
ra <- registerStakeCredential cred
submitAndExpireProposalToMakeReward cred
reward <- lookupReward cred

(drep, _, _) <- setupSingleDRep 1_000_000

-- expire the drep before delegation
void $ submitParameterChange SNothing $ def & ppuMinFeeAL .~ SJust (Coin 3000)
passNEpochs 4
isDRepExpired drep `shouldReturn` True

_ <- delegateToDRep cred (Coin 1_000_000) (DRepCredential drep)

submitTx_ $
mkBasicTx $
mkBasicTxBody
& withdrawalsTxBodyL
.~ Withdrawals
[(ra, reward)]

it "Withdraw from a key delegated to a DRep that expired after delegation" $ do
modifyPParams $ \pp ->
pp
& ppGovActionLifetimeL .~ EpochInterval 4
& ppDRepActivityL .~ EpochInterval 1
kh <- freshKeyHash
let cred = KeyHashObj kh
ra <- registerStakeCredential cred
submitAndExpireProposalToMakeReward cred
reward <- lookupReward cred

(drep, _, _) <- setupSingleDRep 1_000_000

_ <- delegateToDRep cred (Coin 1_000_000) (DRepCredential drep)

-- expire the drep after delegation
void $ submitParameterChange SNothing $ def & ppuMinFeeAL .~ SJust (Coin 3000)
passNEpochs 4
isDRepExpired drep `shouldReturn` True

submitTx_ $
mkBasicTx $
mkBasicTxBody
& withdrawalsTxBodyL
.~ Withdrawals
[(ra, reward)]

it "Withdraw from delegated and non-delegated staking script" $ do
modifyPParams $ ppGovActionLifetimeL .~ EpochInterval 2
let scriptHash = hashPlutusScript $ alwaysSucceedsNoDatum SPlutusV3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,8 @@ votingSpec =
it "AlwaysAbstain" $ do
let getTreasury = getsNES (nesEsL . esAccountStateL . asTreasuryL)

donateToTreasury $ Coin 5_000_000

(drep1, comMember, _) <- electBasicCommittee
initialTreasury <- getTreasury

Expand Down
1 change: 0 additions & 1 deletion libs/cardano-ledger-api/cardano-ledger-api.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ test-suite cardano-ledger-api-test
bytestring,
cardano-ledger-api,
cardano-ledger-byron,
data-default,
data-default-class,
testlib,
cardano-crypto-class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import Cardano.Ledger.DRep
import Cardano.Ledger.Keys (KeyRole (..))
import qualified Cardano.Ledger.Shelley.HardForks as HF
import Cardano.Ledger.Shelley.LedgerState
import Data.Default (def)
import Data.Default.Class (def)
import Data.Foldable (Foldable (..))
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
Expand Down
Loading