/
TxCert.hs
474 lines (412 loc) · 16.5 KB
/
TxCert.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Cardano.Ledger.Conway.TxCert (
ConwayTxCert (..),
ConwayDelegCert (..),
ConwayCommitteeCert (..),
Delegatee (..),
ConwayEraTxCert (..),
fromShelleyDelegCert,
toShelleyDelegCert,
getScriptWitnessConwayTxCert,
getVKeyWitnessConwayTxCert,
pattern RegDepositTxCert,
pattern UnRegDepositTxCert,
pattern DelegTxCert,
pattern RegDepositDelegTxCert,
pattern RegCommitteeHotTxCert,
pattern UnRegCommitteeHotTxCert,
)
where
import Cardano.Ledger.BaseTypes (StrictMaybe (..), invalidKey)
import Cardano.Ledger.Binary (
DecCBOR (..),
Decoder,
EncCBOR (..),
Encoding,
FromCBOR (..),
ToCBOR (..),
decodeRecordSum,
encodeListLen,
encodeWord8,
toPlainDecoder,
toPlainEncoding,
)
import Cardano.Ledger.Coin (Coin)
import Cardano.Ledger.Conway.Era (ConwayEra)
import Cardano.Ledger.Core (
Era (EraCrypto),
EraTxCert (..),
PoolCert,
ScriptHash,
Value,
eraProtVerLow,
notSupportedInThisEra,
poolCertKeyHashWitness,
)
import Cardano.Ledger.Credential (Credential, StakeCredential, credKeyHashWitness, credScriptHash)
import Cardano.Ledger.Crypto
import Cardano.Ledger.Keys (KeyHash, KeyRole (..), asWitness)
import Cardano.Ledger.Shelley.TxCert (
PoolCert (..),
ShelleyDelegCert (..),
ShelleyEraTxCert (..),
encodePoolCert,
encodeShelleyDelegCert,
poolTxCertDecoder,
shelleyTxCertDelegDecoder,
pattern DelegStakeTxCert,
pattern RegPoolTxCert,
pattern RegTxCert,
pattern RetirePoolTxCert,
pattern UnRegTxCert,
)
import Cardano.Ledger.Val (Val (..))
import Control.DeepSeq (NFData)
import GHC.Generics (Generic)
import NoThunks.Class (NoThunks)
instance Crypto c => EraTxCert (ConwayEra c) where
type TxCert (ConwayEra c) = ConwayTxCert (ConwayEra c)
getVKeyWitnessTxCert = getVKeyWitnessConwayTxCert
getScriptWitnessTxCert = getScriptWitnessConwayTxCert
mkRegPoolTxCert = ConwayTxCertPool . RegPool
getRegPoolTxCert (ConwayTxCertPool (RegPool poolParams)) = Just poolParams
getRegPoolTxCert _ = Nothing
mkRetirePoolTxCert poolId epochNo = ConwayTxCertPool $ RetirePool poolId epochNo
getRetirePoolTxCert (ConwayTxCertPool (RetirePool poolId epochNo)) = Just (poolId, epochNo)
getRetirePoolTxCert _ = Nothing
instance Crypto c => ShelleyEraTxCert (ConwayEra c) where
mkRegTxCert c = ConwayTxCertDeleg $ ConwayRegCert c SNothing
getRegTxCert (ConwayTxCertDeleg (ConwayRegCert c _)) = Just c
getRegTxCert _ = Nothing
mkUnRegTxCert c = ConwayTxCertDeleg $ ConwayUnRegCert c SNothing
getUnRegTxCert (ConwayTxCertDeleg (ConwayUnRegCert c _)) = Just c
getUnRegTxCert _ = Nothing
mkDelegStakeTxCert c kh = ConwayTxCertDeleg $ ConwayDelegCert c (DelegStake kh)
getDelegStakeTxCert (ConwayTxCertDeleg (ConwayDelegCert c (DelegStake kh))) = Just (c, kh)
getDelegStakeTxCert _ = Nothing
mkGenesisDelegTxCert = notSupportedInThisEra
getGenesisDelegTxCert _ = Nothing
mkMirTxCert = notSupportedInThisEra
getMirTxCert = const Nothing
class ShelleyEraTxCert era => ConwayEraTxCert era where
mkRegDepositTxCert :: StakeCredential (EraCrypto era) -> Coin -> TxCert era
getRegDepositTxCert :: TxCert era -> Maybe (StakeCredential (EraCrypto era), Coin)
mkUnRegDepositTxCert :: StakeCredential (EraCrypto era) -> Coin -> TxCert era
getUnRegDepositTxCert :: TxCert era -> Maybe (StakeCredential (EraCrypto era), Coin)
mkDelegTxCert ::
StakeCredential (EraCrypto era) -> Delegatee (EraCrypto era) -> TxCert era
getDelegTxCert ::
TxCert era -> Maybe (StakeCredential (EraCrypto era), Delegatee (EraCrypto era))
mkRegDepositDelegTxCert ::
StakeCredential (EraCrypto era) -> Delegatee (EraCrypto era) -> Coin -> TxCert era
getRegDepositDelegTxCert ::
TxCert era -> Maybe (StakeCredential (EraCrypto era), Delegatee (EraCrypto era), Coin)
mkRegCommitteeHotTxCert ::
KeyHash 'CommitteeColdKey (EraCrypto era) -> KeyHash 'CommitteeHotKey (EraCrypto era) -> TxCert era
getRegCommitteeHotTxCert ::
TxCert era -> Maybe (KeyHash 'CommitteeColdKey (EraCrypto era), KeyHash 'CommitteeHotKey (EraCrypto era))
mkUnRegCommitteeHotTxCert :: KeyHash 'CommitteeColdKey (EraCrypto era) -> TxCert era
getUnRegCommitteeHotTxCert :: TxCert era -> Maybe (KeyHash 'CommitteeColdKey (EraCrypto era))
instance Crypto c => ConwayEraTxCert (ConwayEra c) where
mkRegDepositTxCert cred c = ConwayTxCertDeleg $ ConwayRegCert cred $ SJust c
getRegDepositTxCert (ConwayTxCertDeleg (ConwayRegCert cred (SJust c))) = Just (cred, c)
getRegDepositTxCert _ = Nothing
mkUnRegDepositTxCert cred c = ConwayTxCertDeleg $ ConwayUnRegCert cred (SJust c)
getUnRegDepositTxCert (ConwayTxCertDeleg (ConwayUnRegCert cred (SJust c))) = Just (cred, c)
getUnRegDepositTxCert _ = Nothing
mkDelegTxCert cred d = ConwayTxCertDeleg $ ConwayDelegCert cred d
getDelegTxCert (ConwayTxCertDeleg (ConwayDelegCert cred d)) = Just (cred, d)
getDelegTxCert _ = Nothing
mkRegDepositDelegTxCert cred d c = ConwayTxCertDeleg $ ConwayRegDelegCert cred d c
getRegDepositDelegTxCert (ConwayTxCertDeleg (ConwayRegDelegCert cred d c)) = Just (cred, d, c)
getRegDepositDelegTxCert _ = Nothing
mkRegCommitteeHotTxCert ck hk = ConwayTxCertCommittee $ ConwayRegCommitteeHotKey ck hk
getRegCommitteeHotTxCert (ConwayTxCertCommittee (ConwayRegCommitteeHotKey ck hk)) = Just (ck, hk)
getRegCommitteeHotTxCert _ = Nothing
mkUnRegCommitteeHotTxCert = ConwayTxCertCommittee . ConwayUnRegCommitteeHotKey
getUnRegCommitteeHotTxCert (ConwayTxCertCommittee (ConwayUnRegCommitteeHotKey ck)) = Just ck
getUnRegCommitteeHotTxCert _ = Nothing
pattern RegDepositTxCert ::
ConwayEraTxCert era =>
StakeCredential (EraCrypto era) ->
Coin ->
TxCert era
pattern RegDepositTxCert cred c <- (getRegDepositTxCert -> Just (cred, c))
where
RegDepositTxCert cred c = mkRegDepositTxCert cred c
pattern UnRegDepositTxCert ::
ConwayEraTxCert era =>
StakeCredential (EraCrypto era) ->
Coin ->
TxCert era
pattern UnRegDepositTxCert cred c <- (getUnRegDepositTxCert -> Just (cred, c))
where
UnRegDepositTxCert cred c = mkUnRegDepositTxCert cred c
pattern DelegTxCert ::
ConwayEraTxCert era =>
StakeCredential (EraCrypto era) ->
Delegatee (EraCrypto era) ->
TxCert era
pattern DelegTxCert cred d <- (getDelegTxCert -> Just (cred, d))
where
DelegTxCert cred d = mkDelegTxCert cred d
pattern RegDepositDelegTxCert ::
ConwayEraTxCert era =>
StakeCredential (EraCrypto era) ->
Delegatee (EraCrypto era) ->
Coin ->
TxCert era
pattern RegDepositDelegTxCert cred d c <- (getRegDepositDelegTxCert -> Just (cred, d, c))
where
RegDepositDelegTxCert cred d c = mkRegDepositDelegTxCert cred d c
pattern RegCommitteeHotTxCert ::
ConwayEraTxCert era =>
KeyHash 'CommitteeColdKey (EraCrypto era) ->
KeyHash 'CommitteeHotKey (EraCrypto era) ->
TxCert era
pattern RegCommitteeHotTxCert ck hk <- (getRegCommitteeHotTxCert -> Just (ck, hk))
where
RegCommitteeHotTxCert ck hk = mkRegCommitteeHotTxCert ck hk
pattern UnRegCommitteeHotTxCert ::
ConwayEraTxCert era =>
KeyHash 'CommitteeColdKey (EraCrypto era) ->
TxCert era
pattern UnRegCommitteeHotTxCert ck <- (getUnRegCommitteeHotTxCert -> Just ck)
where
UnRegCommitteeHotTxCert ck = mkUnRegCommitteeHotTxCert ck
{-# COMPLETE
RegPoolTxCert
, RetirePoolTxCert
, RegTxCert
, UnRegTxCert
, DelegStakeTxCert
, RegDepositTxCert
, UnRegDepositTxCert
, DelegTxCert
, RegDepositDelegTxCert
, RegCommitteeHotTxCert
, UnRegCommitteeHotTxCert
#-}
-- | First type argument is the deposit
data Delegatee c
= DelegStake !(KeyHash 'StakePool c)
| DelegVote !(Credential 'Voting c)
| DelegStakeVote !(KeyHash 'StakePool c) !(Credential 'Voting c)
deriving (Show, Generic, Eq)
instance NFData (Delegatee c)
instance NoThunks (Delegatee c)
-- | Certificates for registration and delegation of stake to Pools and DReps. Comparing
-- to previous eras, there is now ability to:
--
-- * Register and delegate with a single certificate: `ConwayRegDelegCert`
--
-- * Ability to delegate to DReps with `DelegVote` and `DelegStakeVote`
--
-- * Ability to specify the deposit amount. Deposits during registration and
-- unregistration in Conway are optional, which will change in the future era. They are
-- optional only for the smooth transition from Babbage to Conway. Validity of deposits
-- is checked by the @CERT@ rule.
data ConwayDelegCert c
= -- | Register staking credential. Deposit, when present, must match the expected deposit
-- amount specified by `ppKeyDepositL` in the protocol parameters.
ConwayRegCert !(StakeCredential c) !(StrictMaybe Coin)
| -- | De-Register the staking credential. Deposit, if present, must match the amount
-- that was left as a deposit upon stake credential registration.
ConwayUnRegCert !(StakeCredential c) !(StrictMaybe Coin)
| -- | Redelegate to another delegatee. Staking credential must already be registered.
ConwayDelegCert !(StakeCredential c) !(Delegatee c)
| -- | This is a new type of certificate, which allows to register staking credential
-- and delegate within a single certificate. Deposit is required and must match the
-- expected deposit amount specified by `ppKeyDepositL` in the protocol parameters.
ConwayRegDelegCert !(StakeCredential c) !(Delegatee c) !Coin
deriving (Show, Generic, Eq)
instance NFData (ConwayDelegCert c)
instance NoThunks (ConwayDelegCert c)
data ConwayCommitteeCert c
= ConwayRegCommitteeHotKey !(KeyHash 'CommitteeColdKey c) !(KeyHash 'CommitteeHotKey c)
| ConwayUnRegCommitteeHotKey !(KeyHash 'CommitteeColdKey c)
deriving (Show, Generic, Eq)
instance NFData (ConwayCommitteeCert c)
instance NoThunks (ConwayCommitteeCert c)
committeeKeyHashWitness :: ConwayCommitteeCert c -> KeyHash 'Witness c
committeeKeyHashWitness = \case
ConwayRegCommitteeHotKey coldKeyHash _ -> asWitness coldKeyHash
ConwayUnRegCommitteeHotKey coldKeyHash -> asWitness coldKeyHash
data ConwayTxCert era
= ConwayTxCertDeleg !(ConwayDelegCert (EraCrypto era))
| ConwayTxCertPool !(PoolCert (EraCrypto era))
| ConwayTxCertCommittee !(ConwayCommitteeCert (EraCrypto era))
deriving (Show, Generic, Eq)
instance NFData (ConwayTxCert c)
instance NoThunks (ConwayTxCert c)
instance
( ShelleyEraTxCert era
, TxCert era ~ ConwayTxCert era
) =>
FromCBOR (ConwayTxCert era)
where
fromCBOR = toPlainDecoder (eraProtVerLow @era) decCBOR
instance
( ConwayEraTxCert era
, TxCert era ~ ConwayTxCert era
) =>
DecCBOR (ConwayTxCert era)
where
decCBOR = decodeRecordSum "ConwayTxCert" $ \case
t
| 0 <= t && t < 3 -> shelleyTxCertDelegDecoder t
| 3 <= t && t < 5 -> poolTxCertDecoder t
| t == 5 -> fail "Genesis delegation certificates are no longer supported"
| t == 6 -> fail "MIR certificates are no longer supported"
| 7 <= t -> conwayTxCertDelegDecoder t
t -> invalidKey t
conwayTxCertDelegDecoder :: ConwayEraTxCert era => Word -> Decoder s (Int, TxCert era)
conwayTxCertDelegDecoder = \case
7 -> do
cred <- decCBOR
deposit <- decCBOR
pure (3, RegDepositTxCert cred deposit)
8 -> do
cred <- decCBOR
deposit <- decCBOR
pure (3, UnRegDepositTxCert cred deposit)
9 -> delegCertDecoder 3 (DelegVote <$> decCBOR)
10 -> delegCertDecoder 4 (DelegStakeVote <$> decCBOR <*> decCBOR)
11 -> regDelegCertDecoder 4 (DelegStake <$> decCBOR)
12 -> regDelegCertDecoder 4 (DelegVote <$> decCBOR)
13 -> regDelegCertDecoder 5 (DelegStakeVote <$> decCBOR <*> decCBOR)
14 -> do
cred <- decCBOR
key <- decCBOR
pure (3, RegCommitteeHotTxCert cred key)
15 -> do
cred <- decCBOR
pure (2, UnRegCommitteeHotTxCert cred)
k -> invalidKey k
where
delegCertDecoder n decodeDelegatee = do
cred <- decCBOR
delegatee <- decodeDelegatee
pure (n, DelegTxCert cred delegatee)
{-# INLINE delegCertDecoder #-}
regDelegCertDecoder n decodeDelegatee = do
cred <- decCBOR
delegatee <- decodeDelegatee
deposit <- decCBOR
pure (n, RegDepositDelegTxCert cred delegatee deposit)
{-# INLINE regDelegCertDecoder #-}
{-# INLINE conwayTxCertDelegDecoder #-}
instance (Era era, Val (Value era)) => ToCBOR (ConwayTxCert era) where
toCBOR = toPlainEncoding (eraProtVerLow @era) . encCBOR
instance (Era era, Val (Value era)) => EncCBOR (ConwayTxCert era) where
encCBOR = \case
ConwayTxCertDeleg delegCert -> encodeConwayDelegCert delegCert
ConwayTxCertPool poolCert -> encodePoolCert poolCert
ConwayTxCertCommittee committeeCert -> encodeCommitteeHotKey committeeCert
encodeConwayDelegCert :: Crypto c => ConwayDelegCert c -> Encoding
encodeConwayDelegCert = \case
-- Shelley backwards compatibility
ConwayRegCert cred SNothing -> encodeShelleyDelegCert $ ShelleyRegCert cred
ConwayUnRegCert cred SNothing -> encodeShelleyDelegCert $ ShelleyUnRegCert cred
ConwayDelegCert cred (DelegStake poolId) -> encodeShelleyDelegCert $ ShelleyDelegCert cred poolId
-- New in Conway
ConwayRegCert cred (SJust deposit) ->
encodeListLen 3
<> encodeWord8 7
<> encCBOR cred
<> encCBOR deposit
ConwayUnRegCert cred (SJust deposit) ->
encodeListLen 3
<> encodeWord8 8
<> encCBOR cred
<> encCBOR deposit
ConwayDelegCert cred (DelegVote drep) ->
encodeListLen 3
<> encodeWord8 9
<> encCBOR cred
<> encCBOR drep
ConwayDelegCert cred (DelegStakeVote poolId dRep) ->
encodeListLen 4
<> encodeWord8 10
<> encCBOR cred
<> encCBOR poolId
<> encCBOR dRep
ConwayRegDelegCert cred (DelegStake poolId) deposit ->
encodeListLen 4
<> encodeWord8 11
<> encCBOR cred
<> encCBOR poolId
<> encCBOR deposit
ConwayRegDelegCert cred (DelegVote drep) deposit ->
encodeListLen 4
<> encodeWord8 12
<> encCBOR cred
<> encCBOR drep
<> encCBOR deposit
ConwayRegDelegCert cred (DelegStakeVote poolId dRep) deposit ->
encodeListLen 5
<> encodeWord8 13
<> encCBOR cred
<> encCBOR poolId
<> encCBOR dRep
<> encCBOR deposit
encodeCommitteeHotKey :: Crypto c => ConwayCommitteeCert c -> Encoding
encodeCommitteeHotKey = \case
ConwayRegCommitteeHotKey cred key ->
encodeListLen 3
<> encodeWord8 14
<> encCBOR cred
<> encCBOR key
ConwayUnRegCommitteeHotKey cred ->
encodeListLen 2
<> encodeWord8 15
<> encCBOR cred
fromShelleyDelegCert :: ShelleyDelegCert c -> ConwayDelegCert c
fromShelleyDelegCert = \case
ShelleyRegCert cred -> ConwayRegCert cred SNothing
ShelleyUnRegCert cred -> ConwayUnRegCert cred SNothing
ShelleyDelegCert cred poolId -> ConwayDelegCert cred (DelegStake poolId)
toShelleyDelegCert :: ConwayDelegCert c -> Maybe (ShelleyDelegCert c)
toShelleyDelegCert = \case
ConwayRegCert cred SNothing -> Just $ ShelleyRegCert cred
ConwayUnRegCert cred SNothing -> Just $ ShelleyUnRegCert cred
ConwayDelegCert cred (DelegStake poolId) -> Just $ ShelleyDelegCert cred poolId
_ -> Nothing
-- For both of the functions `getScriptWitnessConwayTxCert` and
-- `getVKeyWitnessConwayTxCert` we preserve the old behavior of not requiring a witness,
-- but only during the transitional period of Conway era and only for registration
-- cdertificates without a deposit. Future eras will require a witness for registration
-- certificates, because the one without a deposit will be removed.
getScriptWitnessConwayTxCert ::
ConwayTxCert era ->
Maybe (ScriptHash (EraCrypto era))
getScriptWitnessConwayTxCert = \case
ConwayTxCertDeleg delegCert ->
case delegCert of
ConwayRegCert _ SNothing -> Nothing
ConwayRegCert cred (SJust _) -> credScriptHash cred
ConwayUnRegCert cred _ -> credScriptHash cred
ConwayDelegCert cred _ -> credScriptHash cred
ConwayRegDelegCert cred _ _ -> credScriptHash cred
_ -> Nothing
getVKeyWitnessConwayTxCert :: ConwayTxCert era -> Maybe (KeyHash 'Witness (EraCrypto era))
getVKeyWitnessConwayTxCert = \case
ConwayTxCertDeleg delegCert ->
case delegCert of
ConwayRegCert _ SNothing -> Nothing
ConwayRegCert cred (SJust _) -> credKeyHashWitness cred
ConwayUnRegCert cred _ -> credKeyHashWitness cred
ConwayDelegCert cred _ -> credKeyHashWitness cred
ConwayRegDelegCert cred _ _ -> credKeyHashWitness cred
ConwayTxCertPool poolCert -> Just $ poolCertKeyHashWitness poolCert
ConwayTxCertCommittee committeeCert -> Just $ committeeKeyHashWitness committeeCert