Skip to content

Commit

Permalink
Disallow empty treasury withdrawals
Browse files Browse the repository at this point in the history
  • Loading branch information
teodanciu committed Sep 18, 2024
1 parent ef820ed commit 649f002
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 5 deletions.
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 `EmptyTreasuryWithdrawals` to `ConwayGovPredFailure`
* Add `ProtVer` argument to `TxInfo` functions:
* `transTxCert`
* `transScriptPurpose`
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
EmptyTreasuryWithdrawals
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 EmptyTreasuryWithdrawals
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
EmptyTreasuryWithdrawals ->
Sum EmptyTreasuryWithdrawals 15

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
mconcat (Map.elems wdrls) /= mempty ?! EmptyTreasuryWithdrawals
UpdateCommittee _mPrevGovActionId membersToRemove membersToAdd _qrm -> do
checkConflictingUpdate
checkExpirationEpoch
Expand Down
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
42 changes: 37 additions & 5 deletions eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/GovSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import Cardano.Ledger.Shelley.Scripts (
import Cardano.Ledger.Val (zero, (<->))
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 +58,7 @@ spec = do
proposalsWithVotingSpec
votingSpec
policySpec
networkIdWithdrawalsSpec
withdrawalsSpec
predicateFailuresSpec
unknownCostModelsSpec

Expand Down Expand Up @@ -489,7 +490,16 @@ proposalsWithVotingSpec =
returnAddr <- registerRewardAccount
deposit <- getsNES $ nesEsL . curPParamsEpochStateL . ppGovActionDepositL
ens <- getEnactState
withdrawals <- arbitrary
withdrawals <- do
accounts <- arbitrary :: ImpTestM era (NonEmpty (RewardAccount (EraCrypto era)))
pairs <-
traverse
( \ac -> do
Positive n <- arbitrary
pure (ac, Coin n)
)
accounts
pure $ Map.fromList (NE.toList pairs)
let
mkProp name action = do
ProposalProcedure
Expand Down Expand Up @@ -1133,14 +1143,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 +1176,28 @@ networkIdWithdrawalsSpec =
Testnet
]

it "Fails for empty withdrawals" $ do
rwdAccount1 <- KeyHashObj <$> freshKeyHash >>= getRewardAccountFor
rwdAccount2 <- KeyHashObj <$> freshKeyHash >>= getRewardAccountFor
submitFailingGovAction
(TreasuryWithdrawals Map.empty SNothing)
[injectFailure $ EmptyTreasuryWithdrawals]

submitFailingGovAction
(TreasuryWithdrawals [(rwdAccount1, zero)] SNothing)
[injectFailure $ EmptyTreasuryWithdrawals]

submitFailingGovAction
(TreasuryWithdrawals [(rwdAccount1, zero), (rwdAccount2, zero)] SNothing)
[injectFailure $ EmptyTreasuryWithdrawals]

rwdAccountRegistered <- registerRewardAccount
submitFailingGovAction
(TreasuryWithdrawals [(rwdAccountRegistered, zero)] SNothing)
[injectFailure $ EmptyTreasuryWithdrawals]

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 @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import Lens.Micro

import Constrained

import Cardano.Ledger.Coin (Coin (..))
import Cardano.Ledger.Conway (ConwayEra)
import Cardano.Ledger.Conway.Core
import Cardano.Ledger.Crypto (StandardCrypto)
Expand Down Expand Up @@ -344,6 +345,7 @@ wfGovAction GovEnv {gePPolicy, geEpoch, gePParams} ps govAction =
( branch $ \withdrawMap policy ->
[ forAll (dom_ withdrawMap) $ \rewAcnt ->
match rewAcnt $ \net _ -> net ==. lit Testnet
, assert $ sum_ (rng_ withdrawMap) >. (lit (Coin 0))
, assert $ policy ==. lit gePPolicy
, assert $ not $ HardForks.bootstrapPhase (gePParams ^. ppProtocolVersionL)
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1552,6 +1552,7 @@ ppConwayGovPredFailure x = case x of
ppSexp "DisallowedProposalDuringBootstrap" [pcProposalProcedure p]
DisallowedVotesDuringBootstrap m -> ppSexp "DisallowedVotesDuringBootstrap" [prettyA m]
VotersDoNotExist m -> ppSexp "VotersDoNotExist" [prettyA m]
EmptyTreasuryWithdrawals -> ppString "EmptyTreasuryWithdrawals"

instance PrettyA (ConwayGovPredFailure era) where
prettyA = ppConwayGovPredFailure
Expand Down

0 comments on commit 649f002

Please sign in to comment.