-
Notifications
You must be signed in to change notification settings - Fork 156
/
Copy pathUpec.hs
152 lines (141 loc) · 4.49 KB
/
Upec.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
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
-- | Epoch change registration.
--
-- The rules of this module determine how the update subsystem of the ledger
-- handles the epoch transitions.
module Cardano.Ledger.Shelley.Rules.Upec (
ShelleyUPEC,
UpecState (..),
ShelleyUpecPredFailure (..),
votedValue,
) where
import Cardano.Ledger.BaseTypes (Globals (..), ShelleyBase)
import Cardano.Ledger.Core
import Cardano.Ledger.Shelley.Era (ShelleyUPEC)
import Cardano.Ledger.Shelley.Governance
import Cardano.Ledger.Shelley.LedgerState (
EpochState,
UTxOState (..),
esLState,
lsCertState,
lsUTxOState,
pattern CertState,
pattern EpochState,
)
import Cardano.Ledger.Shelley.PParams (ProposedPPUpdates (..))
import Cardano.Ledger.Shelley.Rules.Newpp (
NewppEnv (..),
ShelleyNEWPP,
ShelleyNewppState (..),
)
import Control.Monad.Trans.Reader (asks)
import Control.State.Transition (
Embed (..),
STS (..),
TRC (..),
judgmentContext,
liftSTS,
trans,
)
import Data.Default.Class (Default)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map
import GHC.Generics (Generic)
import NoThunks.Class (NoThunks (..))
data UpecState era = UpecState
{ currentPp :: !(PParams era)
-- ^ Current protocol parameters.
, ppupState :: !(ShelleyGovState era)
-- ^ State of the protocol update transition system.
}
deriving stock instance
(Show (PParams era), Show (PParamsUpdate era)) =>
Show (UpecState era)
newtype ShelleyUpecPredFailure era
= NewPpFailure (PredicateFailure (ShelleyNEWPP era))
deriving (Eq, Show, Generic)
instance NoThunks (ShelleyUpecPredFailure era)
instance
( EraGov era
, Default (PParams era)
, GovState era ~ ShelleyGovState era
) =>
STS (ShelleyUPEC era)
where
type State (ShelleyUPEC era) = UpecState era
type Signal (ShelleyUPEC era) = ()
type Environment (ShelleyUPEC era) = EpochState era
type BaseM (ShelleyUPEC era) = ShelleyBase
type PredicateFailure (ShelleyUPEC era) = ShelleyUpecPredFailure era
initialRules = []
transitionRules =
[ do
TRC
( EpochState
{ esLState = ls
}
, UpecState pp ppupSt
, _
) <-
judgmentContext
coreNodeQuorum <- liftSTS $ asks quorum
let utxoSt = lsUTxOState ls
CertState _ pstate dstate = lsCertState ls
pup = proposals . utxosGovState $ utxoSt
ppNew = votedValue pup pp (fromIntegral coreNodeQuorum)
NewppState pp' ppupSt' <-
trans @(ShelleyNEWPP era) $
TRC (NewppEnv dstate pstate utxoSt, NewppState pp ppupSt, ppNew)
pure $
UpecState pp' ppupSt'
]
-- | If at least @n@ nodes voted to change __the same__ protocol parameters to
-- __the same__ values, return the given protocol parameters updated to these
-- values. Here @n@ is the quorum needed.
votedValue ::
forall era.
EraPParams era =>
ProposedPPUpdates era ->
-- | Protocol parameters to which the change will be applied.
PParams era ->
-- | Quorum needed to change the protocol parameters.
Int ->
Maybe (PParams era)
votedValue (ProposedPPUpdates pup) pps quorumN =
let incrGov vote gov = 1 + Map.findWithDefault 0 vote gov
votes =
Map.foldr
(\vote gov -> Map.insert vote (incrGov vote gov) gov)
(Map.empty :: Map (PParamsUpdate era) Int)
pup
consensus = Map.filter (>= quorumN) votes
in case length consensus of
-- NOTE that `quorumN` is a global constant, and that we require
-- it to be strictly greater than half the number of genesis nodes.
-- The keys in the `pup` correspond to the genesis nodes,
-- and therefore either:
-- 1) `consensus` is empty, or
-- 2) `consensus` has exactly one element.
1 ->
(Just . applyPPUpdates pps . fst . head . Map.toList)
consensus
-- NOTE that `updatePParams` corresponds to the union override right
-- operation in the formal spec.
_ -> Nothing
instance
(Era era, STS (ShelleyNEWPP era)) =>
Embed (ShelleyNEWPP era) (ShelleyUPEC era)
where
wrapFailed = NewPpFailure