Skip to content

Commit 8b75109

Browse files
committed
Add IncompleteWithdrawalsCERTS to ConwayPredFailure
Conditional upon protocol version 11. Adjust the relevant tests.
1 parent 95bf46b commit 8b75109

File tree

6 files changed

+88
-10
lines changed

6 files changed

+88
-10
lines changed

eras/conway/impl/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## 1.20.0.0
44

5+
* Add `IncompleteWithdrawalsCERTS` to `ConwayPredFailure`.
56
* Decoupled `ConwayEraTxCert` from `ShelleyEraTxCert`, so added `ShelleyEraTxCert` constraint to:
67
* `DecCBOR ConwayTxCert`
78
* `transTxCert`

eras/conway/impl/src/Cardano/Ledger/Conway.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module Cardano.Ledger.Conway (
1111
hardforkConwayBootstrapPhase,
1212
hardforkConwayDisallowUnelectedCommitteeFromVoting,
1313
hardforkConwayDELEGIncorrectDepositsAndRefunds,
14+
hardforkConwayCERTSIncompleteWithdrawals,
1415
Tx (..),
1516
) where
1617

@@ -19,6 +20,7 @@ import Cardano.Ledger.Conway.BlockBody ()
1920
import Cardano.Ledger.Conway.Era (
2021
ConwayEra,
2122
hardforkConwayBootstrapPhase,
23+
hardforkConwayCERTSIncompleteWithdrawals,
2224
hardforkConwayDELEGIncorrectDepositsAndRefunds,
2325
hardforkConwayDisallowUnelectedCommitteeFromVoting,
2426
)

eras/conway/impl/src/Cardano/Ledger/Conway/Era.hs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ module Cardano.Ledger.Conway.Era (
2929
hardforkConwayBootstrapPhase,
3030
hardforkConwayDisallowUnelectedCommitteeFromVoting,
3131
hardforkConwayDELEGIncorrectDepositsAndRefunds,
32+
hardforkConwayCERTSIncompleteWithdrawals,
3233
) where
3334

3435
import Cardano.Ledger.BaseTypes (ProtVer (pvMajor), natVersion)
@@ -179,3 +180,7 @@ hardforkConwayDisallowUnelectedCommitteeFromVoting pv = pvMajor pv > natVersion
179180
-- | Starting with protocol version 11, we report incorrect deposit and refunds better
180181
hardforkConwayDELEGIncorrectDepositsAndRefunds :: ProtVer -> Bool
181182
hardforkConwayDELEGIncorrectDepositsAndRefunds pv = pvMajor pv > natVersion @10
183+
184+
-- | Starting with protocol version 11, we report incomplete withdrawals better
185+
hardforkConwayCERTSIncompleteWithdrawals :: ProtVer -> Bool
186+
hardforkConwayCERTSIncompleteWithdrawals pv = pvMajor pv > natVersion @10

eras/conway/impl/src/Cardano/Ledger/Conway/Rules/Certs.hs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,12 @@ import Cardano.Ledger.Binary.Coders (
4242
(<!),
4343
)
4444
import Cardano.Ledger.Conway.Core
45-
import Cardano.Ledger.Conway.Era (ConwayCERT, ConwayCERTS, ConwayEra)
45+
import Cardano.Ledger.Conway.Era (
46+
ConwayCERT,
47+
ConwayCERTS,
48+
ConwayEra,
49+
hardforkConwayCERTSIncompleteWithdrawals,
50+
)
4651
import Cardano.Ledger.Conway.Governance (
4752
Committee,
4853
GovActionPurpose (..),
@@ -68,6 +73,7 @@ import Control.State.Transition.Extended (
6873
judgmentContext,
6974
liftSTS,
7075
trans,
76+
(?!),
7177
)
7278
import qualified Data.Map.Strict as Map
7379
import qualified Data.OSet.Strict as OSet
@@ -104,10 +110,14 @@ deriving instance (EraPParams era, Show (Tx era)) => Show (CertsEnv era)
104110
instance (EraPParams era, NFData (Tx era)) => NFData (CertsEnv era)
105111

106112
data ConwayCertsPredFailure era
107-
= -- | Withdrawals that are missing or do not withdraw the entire amount
113+
= -- | Withdrawals that are missing reward accounts. Before PV 11, this was
114+
-- also wrongly used in place of IncompleteWithdrawalsCERTS for withdrawals
115+
-- that didn't match the account balance exactly.
108116
WithdrawalsNotInRewardsCERTS Withdrawals
109117
| -- | CERT rule subtransition Failures
110118
CertFailure (PredicateFailure (EraRule "CERT" era))
119+
| -- | Withdrawals that do not withdraw the entire amount
120+
IncompleteWithdrawalsCERTS Withdrawals
111121
deriving (Generic)
112122

113123
type instance EraRuleFailure "CERTS" ConwayEra = ConwayCertsPredFailure ConwayEra
@@ -161,6 +171,7 @@ instance
161171
encode . \case
162172
WithdrawalsNotInRewardsCERTS rs -> Sum (WithdrawalsNotInRewardsCERTS @era) 0 !> To rs
163173
CertFailure x -> Sum (CertFailure @era) 1 !> To x
174+
IncompleteWithdrawalsCERTS ws -> Sum (IncompleteWithdrawalsCERTS @era) 2 !> To ws
164175

165176
instance
166177
( Era era
@@ -171,6 +182,7 @@ instance
171182
decCBOR = decode $ Summands "ConwayGovPredFailure" $ \case
172183
0 -> SumD WithdrawalsNotInRewardsCERTS <! From
173184
1 -> SumD CertFailure <! From
185+
2 -> SumD IncompleteWithdrawalsCERTS <! From
174186
k -> Invalid k
175187

176188
instance
@@ -252,12 +264,19 @@ conwayCertsTransition = do
252264
-- Final CertState with updates to DRep expiry based on new proposals and votes on existing proposals
253265
let certStateWithDRepExpiryUpdated = certState' & certVStateL . vsDRepsL %~ updateVSDReps
254266
dState = certStateWithDRepExpiryUpdated ^. certDStateL
267+
accounts = dState ^. accountsL
255268
withdrawals = tx ^. bodyTxL . withdrawalsTxBodyL
256269

257-
-- Validate withdrawals and rewards and drain withdrawals
258-
failOnJust
259-
(withdrawalsThatDoNotDrainAccounts withdrawals network (dState ^. accountsL))
260-
WithdrawalsNotInRewardsCERTS
270+
if hardforkConwayCERTSIncompleteWithdrawals (pp ^. ppProtocolVersionL)
271+
then do
272+
let (invalidWithdrawals, incompleteWithdrawals) =
273+
invalidAndIncompleteWithdrawals withdrawals network accounts
274+
null invalidWithdrawals ?! WithdrawalsNotInRewardsCERTS (Withdrawals invalidWithdrawals)
275+
null incompleteWithdrawals ?! IncompleteWithdrawalsCERTS (Withdrawals incompleteWithdrawals)
276+
else do
277+
failOnJust
278+
(withdrawalsThatDoNotDrainAccounts withdrawals network accounts)
279+
WithdrawalsNotInRewardsCERTS
261280

262281
pure $ certStateWithDRepExpiryUpdated & certDStateL . accountsL %~ drainAccounts withdrawals
263282
gamma :|> txCert -> do

eras/conway/impl/testlib/Test/Cardano/Ledger/Conway/Imp/CertsSpec.hs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module Test.Cardano.Ledger.Conway.Imp.CertsSpec (spec) where
1212

1313
import Cardano.Ledger.BaseTypes (EpochInterval (..))
1414
import Cardano.Ledger.Coin (Coin (..))
15+
import Cardano.Ledger.Conway (hardforkConwayCERTSIncompleteWithdrawals)
1516
import Cardano.Ledger.Conway.Core
1617
import Cardano.Ledger.Conway.Rules (ConwayCertsPredFailure (..), ConwayLedgerPredFailure (..))
1718
import Cardano.Ledger.Credential (Credential (..))
@@ -83,6 +84,7 @@ spec = do
8384

8485
it "Withdrawing the wrong amount" $ do
8586
modifyPParams $ ppGovActionLifetimeL .~ EpochInterval 2
87+
pv <- getsPParams @era ppProtocolVersionL
8688

8789
(rwdAccount1, reward1, _stakeKey1) <- setupRewardAccount (Coin 1_000_000) DRepAlwaysAbstain
8890
(rwdAccount2, reward2, _stakeKey2) <- setupRewardAccount (Coin 1_000_000) DRepAlwaysAbstain
@@ -95,9 +97,12 @@ spec = do
9597
, (rwdAccount2, reward2)
9698
]
9799
)
98-
[ injectFailure $
99-
WithdrawalsNotInRewardsCERTS $
100-
Withdrawals [(rwdAccount1, reward1 <+> Coin 1)]
100+
[ injectFailure
101+
$ ( if hardforkConwayCERTSIncompleteWithdrawals pv
102+
then IncompleteWithdrawalsCERTS @era
103+
else WithdrawalsNotInRewardsCERTS @era
104+
)
105+
$ Withdrawals [(rwdAccount1, reward1 <+> Coin 1)]
101106
]
102107

103108
submitFailingTx
@@ -107,7 +112,13 @@ spec = do
107112
.~ Withdrawals
108113
[(rwdAccount1, zero)]
109114
)
110-
[injectFailure $ WithdrawalsNotInRewardsCERTS $ Withdrawals [(rwdAccount1, zero)]]
115+
[ injectFailure
116+
$ ( if hardforkConwayCERTSIncompleteWithdrawals pv
117+
then IncompleteWithdrawalsCERTS @era
118+
else WithdrawalsNotInRewardsCERTS @era
119+
)
120+
$ Withdrawals [(rwdAccount1, zero)]
121+
]
111122
where
112123
setupRewardAccount stake dRep = do
113124
kh <- freshKeyHash

libs/cardano-ledger-core/src/Cardano/Ledger/State/Account.hs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE BangPatterns #-}
12
{-# LANGUAGE DataKinds #-}
23
{-# LANGUAGE DefaultSignatures #-}
34
{-# LANGUAGE FlexibleContexts #-}
@@ -24,6 +25,7 @@ module Cardano.Ledger.State.Account (
2425
withdrawalsThatDoNotDrainAccounts,
2526
drainAccounts,
2627
removeStakePoolDelegations,
28+
invalidAndIncompleteWithdrawals,
2729
) where
2830

2931
import Cardano.Ledger.Address (RewardAccount (..), Withdrawals (..))
@@ -36,6 +38,7 @@ import Cardano.Ledger.Credential
3638
import Control.DeepSeq (NFData)
3739
import Control.Exception (assert)
3840
import Data.Aeson (ToJSON)
41+
import Data.Bifunctor (Bifunctor (..))
3942
import Data.Default (Default)
4043
import Data.Foldable (foldMap')
4144
import Data.Kind (Type)
@@ -175,6 +178,43 @@ lookupStakePoolDelegation cred accounts =
175178
lookupAccountState cred accounts
176179
>>= (^. stakePoolDelegationAccountStateL)
177180

181+
-- | This function returns 2-tuple where the `fst` are withdrawals with missing
182+
-- reward accounts and `snd` are incomplete withdrawal-maps. At the call site we
183+
-- check for whether they are empty.
184+
invalidAndIncompleteWithdrawals ::
185+
EraAccounts era =>
186+
Withdrawals ->
187+
Network ->
188+
Accounts era ->
189+
(Map RewardAccount Coin, Map RewardAccount Coin)
190+
invalidAndIncompleteWithdrawals (Withdrawals givenWithdrawals) networkId accounts = do
191+
-- @givenWithdrawals@ are less and @accounts@ many, better to traverse the
192+
-- former than the latter.
193+
Map.foldrWithKey collectBadWithdrawals (mempty, mempty) givenWithdrawals
194+
where
195+
-- invalid withdrawal = that which does not have a reward account or is in
196+
-- the wrong network.
197+
-- incomplete withdrawal = that which does not withdraw the exact account
198+
-- balance.
199+
collectBadWithdrawals ::
200+
RewardAccount ->
201+
Coin ->
202+
(Map RewardAccount Coin, Map RewardAccount Coin) ->
203+
(Map RewardAccount Coin, Map RewardAccount Coin)
204+
collectBadWithdrawals
205+
ra@RewardAccount {raCredential, raNetwork}
206+
withdrawalAmount
207+
accum@(!_, !_) =
208+
case Map.lookup raCredential (accounts ^. accountsMapL) of
209+
Nothing ->
210+
first (Map.insert ra withdrawalAmount) accum
211+
Just accountState
212+
| raNetwork /= networkId ->
213+
first (Map.insert ra withdrawalAmount) accum
214+
| fromCompact (accountState ^. balanceAccountStateL) /= withdrawalAmount ->
215+
second (Map.insert ra withdrawalAmount) accum
216+
| otherwise -> accum
217+
178218
-- | This function returns `Nothing` iff all of the accounts that withdrawals are trying to drain are
179219
-- indeed registered and all of the amounts in the withdrawals match the respective balances exactly.
180220
withdrawalsThatDoNotDrainAccounts ::

0 commit comments

Comments
 (0)