-
Notifications
You must be signed in to change notification settings - Fork 137
/
validators.go
249 lines (208 loc) · 8.27 KB
/
validators.go
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
package keeper
import (
"time"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/interchain-security/x/ccv/consumer/types"
abci "github.com/tendermint/tendermint/abci/types"
)
// ApplyCCValidatorChanges applies the given changes to the cross-chain validators states
// and returns updates to forward to tendermint.
func (k Keeper) ApplyCCValidatorChanges(ctx sdk.Context, changes []abci.ValidatorUpdate) []abci.ValidatorUpdate {
ret := []abci.ValidatorUpdate{}
for _, change := range changes {
// convert TM pubkey to SDK pubkey
pubkey, err := cryptocodec.FromTmProtoPublicKey(change.GetPubKey())
if err != nil {
// An error here would indicate that the validator updates
// received from the provider are invalid.
panic(err)
}
addr := pubkey.Address()
val, found := k.GetCCValidator(ctx, addr)
if found {
// update or delete an existing validator
if change.Power < 1 {
k.DeleteCCValidator(ctx, addr)
} else {
val.Power = change.Power
k.SetCCValidator(ctx, val)
}
} else if 0 < change.Power {
// create a new validator
consAddr := sdk.ConsAddress(addr)
ccVal, err := types.NewCCValidator(addr, change.Power, pubkey)
if err != nil {
// An error here would indicate that the validator updates
// received from the provider are invalid.
panic(err)
}
k.SetCCValidator(ctx, ccVal)
k.AfterValidatorBonded(ctx, consAddr, nil)
} else {
// edge case: we received an update for 0 power
// but the validator is already deleted. Do not forward
// to tendermint.
continue
}
ret = append(ret, change)
}
return ret
}
// IterateValidators - unimplemented on CCV keeper but perform a no-op in order to pass the slashing module InitGenesis.
// It is allowed since the condition verifying validator public keys in HandleValidatorSignature (x/slashing/keeper/infractions.go) is removed
// therefore it isn't required to store any validator public keys to the slashing states during genesis.
func (k Keeper) IterateValidators(sdk.Context, func(index int64, validator stakingtypes.ValidatorI) (stop bool)) {
}
// Validator - unimplemented on CCV keeper
func (k Keeper) Validator(ctx sdk.Context, addr sdk.ValAddress) stakingtypes.ValidatorI {
panic("unimplemented on CCV keeper")
}
// IsJailed returns the outstanding slashing flag for the given validator adddress
func (k Keeper) IsValidatorJailed(ctx sdk.Context, addr sdk.ConsAddress) bool {
return k.OutstandingDowntime(ctx, addr)
}
// ValidatorByConsAddr returns an empty validator
func (k Keeper) ValidatorByConsAddr(sdk.Context, sdk.ConsAddress) stakingtypes.ValidatorI {
/*
NOTE:
The evidence module will call this function when it handles equivocation evidence.
The returned value must not be nil and must not have an UNBONDED validator status,
or evidence will reject it.
Also, the slashing module will cal lthis function when it observes downtime. In that case
the only requirement on the returned value is that it isn't null.
*/
return stakingtypes.Validator{}
}
// Slash queues a slashing request for the the provider chain
// All queued slashing requests will be cleared in EndBlock
func (k Keeper) Slash(ctx sdk.Context, addr sdk.ConsAddress, infractionHeight, power int64, _ sdk.Dec, infraction stakingtypes.InfractionType) {
if infraction == stakingtypes.InfractionEmpty {
return
}
// get VSC ID for infraction height
vscID := k.GetHeightValsetUpdateID(ctx, uint64(infractionHeight))
k.Logger(ctx).Debug("vscID obtained from mapped infraction height",
"infraction height", infractionHeight,
"vscID", vscID,
)
k.QueueSlashPacket(
ctx,
abci.Validator{
Address: addr.Bytes(),
Power: power},
vscID,
infraction,
)
}
// Jail - unimplemented on CCV keeper
func (k Keeper) Jail(ctx sdk.Context, addr sdk.ConsAddress) {}
// Unjail - unimplemented on CCV keeper
func (k Keeper) Unjail(sdk.Context, sdk.ConsAddress) {}
// Delegation - unimplemented on CCV keeper
func (k Keeper) Delegation(sdk.Context, sdk.AccAddress, sdk.ValAddress) stakingtypes.DelegationI {
panic("unimplemented on CCV keeper")
}
// MaxValidators - unimplemented on CCV keeper
func (k Keeper) MaxValidators(sdk.Context) uint32 {
panic("unimplemented on CCV keeper")
}
// UnbondingTime returns consumer unbonding period, satisfying the staking keeper interface
func (k Keeper) UnbondingTime(ctx sdk.Context) time.Duration {
return k.GetUnbondingPeriod(ctx)
}
// GetHistoricalInfo gets the historical info at a given height
func (k Keeper) GetHistoricalInfo(ctx sdk.Context, height int64) (stakingtypes.HistoricalInfo, bool) {
store := ctx.KVStore(k.storeKey)
key := types.HistoricalInfoKey(height)
value := store.Get(key)
if value == nil {
return stakingtypes.HistoricalInfo{}, false
}
return stakingtypes.MustUnmarshalHistoricalInfo(k.cdc, value), true
}
// SetHistoricalInfo sets the historical info at a given height
func (k Keeper) SetHistoricalInfo(ctx sdk.Context, height int64, hi *stakingtypes.HistoricalInfo) {
store := ctx.KVStore(k.storeKey)
key := types.HistoricalInfoKey(height)
value := k.cdc.MustMarshal(hi)
store.Set(key, value)
}
// DeleteHistoricalInfo deletes the historical info at a given height
func (k Keeper) DeleteHistoricalInfo(ctx sdk.Context, height int64) {
store := ctx.KVStore(k.storeKey)
key := types.HistoricalInfoKey(height)
store.Delete(key)
}
// TrackHistoricalInfo saves the latest historical-info and deletes the oldest
// heights that are below pruning height
func (k Keeper) TrackHistoricalInfo(ctx sdk.Context) {
numHistoricalEntries := k.GetHistoricalEntries(ctx)
// Prune store to ensure we only have parameter-defined historical entries.
// In most cases, this will involve removing a single historical entry.
// In the rare scenario when the historical entries gets reduced to a lower value k'
// from the original value k. k - k' entries must be deleted from the store.
// Since the entries to be deleted are always in a continuous range, we can iterate
// over the historical entries starting from the most recent version to be pruned
// and then return at the first empty entry.
for i := ctx.BlockHeight() - int64(numHistoricalEntries); i >= 0; i-- {
_, found := k.GetHistoricalInfo(ctx, i)
if found {
k.DeleteHistoricalInfo(ctx, i)
} else {
break
}
}
// if there is no need to persist historicalInfo, return
if numHistoricalEntries == 0 {
return
}
// Create HistoricalInfo struct
lastVals := []stakingtypes.Validator{}
for _, v := range k.GetAllCCValidator(ctx) {
pk, err := v.ConsPubKey()
if err != nil {
// This should never happen as the pubkey is assumed
// to be stored correctly in ApplyCCValidatorChanges.
panic(err)
}
val, err := stakingtypes.NewValidator(nil, pk, stakingtypes.Description{})
if err != nil {
// This should never happen as the pubkey is assumed
// to be stored correctly in ApplyCCValidatorChanges.
panic(err)
}
// Set validator to bonded status
val.Status = stakingtypes.Bonded
// Compute tokens from voting power
val.Tokens = sdk.TokensFromConsensusPower(v.Power, sdk.DefaultPowerReduction)
lastVals = append(lastVals, val)
}
// Create historical info entry which sorts the validator set by voting power
historicalEntry := stakingtypes.NewHistoricalInfo(ctx.BlockHeader(), lastVals, sdk.DefaultPowerReduction)
// Set latest HistoricalInfo at current height
k.SetHistoricalInfo(ctx, ctx.BlockHeight(), &historicalEntry)
}
// MustGetCurrentValidatorsAsABCIUpdates gets all cross-chain validators converted
// to the ABCI validator update type. It panics in case of failure.
func (k Keeper) MustGetCurrentValidatorsAsABCIUpdates(ctx sdk.Context) []abci.ValidatorUpdate {
vals := k.GetAllCCValidator(ctx)
valUpdates := make([]abci.ValidatorUpdate, 0, len(vals))
for _, v := range vals {
pk, err := v.ConsPubKey()
if err != nil {
// This should never happen as the pubkey is assumed
// to be stored correctly in ApplyCCValidatorChanges.
panic(err)
}
tmPK, err := cryptocodec.ToTmProtoPublicKey(pk)
if err != nil {
// This should never happen as the pubkey is assumed
// to be stored correctly in ApplyCCValidatorChanges.
panic(err)
}
valUpdates = append(valUpdates, abci.ValidatorUpdate{PubKey: tmPK, Power: v.Power})
}
return valUpdates
}