-
Notifications
You must be signed in to change notification settings - Fork 174
/
keeper.go
347 lines (291 loc) · 9.74 KB
/
keeper.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
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
package bor
import (
"errors"
"math/big"
"strconv"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tendermint/tendermint/libs/log"
"github.com/maticnetwork/bor/common"
"github.com/maticnetwork/heimdall/bor/types"
chainmanager "github.com/maticnetwork/heimdall/chainmanager"
"github.com/maticnetwork/heimdall/helper"
"github.com/maticnetwork/heimdall/params/subspace"
"github.com/maticnetwork/heimdall/staking"
hmTypes "github.com/maticnetwork/heimdall/types"
)
var (
DefaultValue = []byte{0x01} // Value to store in CacheCheckpoint and CacheCheckpointACK & ValidatorSetChange Flag
SpanDurationKey = []byte{0x24} // Key to store span duration for Bor
SprintDurationKey = []byte{0x25} // Key to store span duration for Bor
LastSpanIDKey = []byte{0x35} // Key to store last span start block
SpanPrefixKey = []byte{0x36} // prefix key to store span
SpanCacheKey = []byte{0x37} // key to store Cache for span
LastProcessedEthBlock = []byte{0x38} // key to store last processed eth block for seed
)
// Keeper stores all related data
type Keeper struct {
cdc *codec.Codec
sk staking.Keeper
// The (unexposed) keys used to access the stores from the Context.
storeKey sdk.StoreKey
// codespace
codespace sdk.CodespaceType
// param space
paramSpace subspace.Subspace
// contract caller
contractCaller helper.ContractCaller
// chain manager keeper
chainKeeper chainmanager.Keeper
}
// NewKeeper create new keeper
func NewKeeper(
cdc *codec.Codec,
storeKey sdk.StoreKey,
paramSpace subspace.Subspace,
codespace sdk.CodespaceType,
chainKeeper chainmanager.Keeper,
stakingKeeper staking.Keeper,
caller helper.ContractCaller,
) Keeper {
// create keeper
keeper := Keeper{
cdc: cdc,
storeKey: storeKey,
paramSpace: paramSpace.WithKeyTable(types.ParamKeyTable()),
codespace: codespace,
chainKeeper: chainKeeper,
sk: stakingKeeper,
contractCaller: caller,
}
return keeper
}
// Codespace returns the codespace
func (k Keeper) Codespace() sdk.CodespaceType {
return k.codespace
}
// Logger returns a module-specific logger
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", types.ModuleName)
}
// GetSpanKey appends prefix to start block
func GetSpanKey(id uint64) []byte {
return append(SpanPrefixKey, []byte(strconv.FormatUint(id, 10))...)
}
// AddNewSpan adds new span for bor to store
func (k *Keeper) AddNewSpan(ctx sdk.Context, span hmTypes.Span) error {
store := ctx.KVStore(k.storeKey)
out, err := k.cdc.MarshalBinaryBare(span)
if err != nil {
k.Logger(ctx).Error("Error marshalling span", "error", err)
return err
}
// store set span id
store.Set(GetSpanKey(span.ID), out)
// update last span
k.UpdateLastSpan(ctx, span.ID)
return nil
}
// AddNewRawSpan adds new span for bor to store
func (k *Keeper) AddNewRawSpan(ctx sdk.Context, span hmTypes.Span) error {
store := ctx.KVStore(k.storeKey)
out, err := k.cdc.MarshalBinaryBare(span)
if err != nil {
k.Logger(ctx).Error("Error marshalling span", "error", err)
return err
}
store.Set(GetSpanKey(span.ID), out)
return nil
}
// GetSpan fetches span indexed by id from store
func (k *Keeper) GetSpan(ctx sdk.Context, id uint64) (*hmTypes.Span, error) {
store := ctx.KVStore(k.storeKey)
spanKey := GetSpanKey(id)
// If we are starting from 0 there will be no spanKey present
if !store.Has(spanKey) {
return nil, errors.New("span not found for id")
}
var span hmTypes.Span
if err := k.cdc.UnmarshalBinaryBare(store.Get(spanKey), &span); err != nil {
return nil, err
}
return &span, nil
}
func (k *Keeper) HasSpan(ctx sdk.Context, id uint64) bool {
store := ctx.KVStore(k.storeKey)
spanKey := GetSpanKey(id)
return store.Has(spanKey)
}
// GetAllSpans fetches all indexed by id from store
func (k *Keeper) GetAllSpans(ctx sdk.Context) (spans []*hmTypes.Span) {
// iterate through spans and create span update array
k.IterateSpansAndApplyFn(ctx, func(span hmTypes.Span) error {
// append to list of validatorUpdates
spans = append(spans, &span)
return nil
})
return
}
// GetSpanList returns all spans with params like page and limit
func (k *Keeper) GetSpanList(ctx sdk.Context, page uint64, limit uint64) ([]hmTypes.Span, error) {
store := ctx.KVStore(k.storeKey)
// create spans
var spans []hmTypes.Span
// have max limit
if limit > 20 {
limit = 20
}
// get paginated iterator
iterator := hmTypes.KVStorePrefixIteratorPaginated(store, SpanPrefixKey, uint(page), uint(limit))
// loop through validators to get valid validators
for ; iterator.Valid(); iterator.Next() {
var span hmTypes.Span
if err := k.cdc.UnmarshalBinaryBare(iterator.Value(), &span); err == nil {
spans = append(spans, span)
}
}
return spans, nil
}
// GetLastSpan fetches last span using lastStartBlock
func (k *Keeper) GetLastSpan(ctx sdk.Context) (*hmTypes.Span, error) {
store := ctx.KVStore(k.storeKey)
var lastSpanID uint64
if store.Has(LastSpanIDKey) {
// get last span id
var err error
lastSpanID, err = strconv.ParseUint(string(store.Get(LastSpanIDKey)), 10, 64)
if err != nil {
return nil, err
}
}
return k.GetSpan(ctx, lastSpanID)
}
// FreezeSet freezes validator set for next span
func (k *Keeper) FreezeSet(ctx sdk.Context, id uint64, startBlock uint64, endBlock uint64, borChainID string, seed common.Hash) error {
// select next producers
newProducers, err := k.SelectNextProducers(ctx, seed)
if err != nil {
return err
}
// increment last eth block
k.IncrementLastEthBlock(ctx)
// generate new span
newSpan := hmTypes.NewSpan(
id,
startBlock,
endBlock,
k.sk.GetValidatorSet(ctx),
newProducers,
borChainID,
)
return k.AddNewSpan(ctx, newSpan)
}
// SelectNextProducers selects producers for next span
func (k *Keeper) SelectNextProducers(ctx sdk.Context, seed common.Hash) (vals []hmTypes.Validator, err error) {
// spanEligibleVals are current validators who are not getting deactivated in between next span
spanEligibleVals := k.sk.GetSpanEligibleValidators(ctx)
producerCount := k.GetParams(ctx).ProducerCount
if err != nil {
return vals, err
}
// if producers to be selected is more than current validators no need to select/shuffle
if len(spanEligibleVals) <= int(producerCount) {
return spanEligibleVals, nil
}
// TODO remove old selection algorigthm
// select next producers using seed as blockheader hash
fn := SelectNextProducers
if ctx.BlockHeight() < helper.NewSelectionAlgoHeight {
fn = XXXSelectNextProducers
}
newProducersIds, err := fn(seed, spanEligibleVals, producerCount)
if err != nil {
return vals, err
}
IDToPower := make(map[uint64]uint64)
for _, ID := range newProducersIds {
IDToPower[ID] = IDToPower[ID] + 1
}
for key, value := range IDToPower {
if val, ok := k.sk.GetValidatorFromValID(ctx, hmTypes.NewValidatorID(key)); ok {
val.VotingPower = int64(value)
vals = append(vals, val)
}
} // sort by address
vals = hmTypes.SortValidatorByAddress(vals)
return vals, nil
}
// UpdateLastSpan updates the last span start block
func (k *Keeper) UpdateLastSpan(ctx sdk.Context, id uint64) {
store := ctx.KVStore(k.storeKey)
store.Set(LastSpanIDKey, []byte(strconv.FormatUint(id, 10)))
}
// IncrementLastEthBlock increment last eth block
func (k *Keeper) IncrementLastEthBlock(ctx sdk.Context) {
store := ctx.KVStore(k.storeKey)
lastEthBlock := big.NewInt(0)
if store.Has(LastProcessedEthBlock) {
lastEthBlock = lastEthBlock.SetBytes(store.Get(LastProcessedEthBlock))
}
store.Set(LastProcessedEthBlock, lastEthBlock.Add(lastEthBlock, big.NewInt(1)).Bytes())
}
// SetLastEthBlock sets last eth block number
func (k *Keeper) SetLastEthBlock(ctx sdk.Context, blockNumber *big.Int) {
store := ctx.KVStore(k.storeKey)
store.Set(LastProcessedEthBlock, blockNumber.Bytes())
}
// GetLastEthBlock get last processed Eth block for seed
func (k *Keeper) GetLastEthBlock(ctx sdk.Context) *big.Int {
store := ctx.KVStore(k.storeKey)
lastEthBlock := big.NewInt(0)
if store.Has(LastProcessedEthBlock) {
lastEthBlock = lastEthBlock.SetBytes(store.Get(LastProcessedEthBlock))
}
return lastEthBlock
}
func (k Keeper) GetNextSpanSeed(ctx sdk.Context) (common.Hash, error) {
lastEthBlock := k.GetLastEthBlock(ctx)
// increment last processed header block number
newEthBlock := lastEthBlock.Add(lastEthBlock, big.NewInt(1))
k.Logger(ctx).Debug("newEthBlock to generate seed", "newEthBlock", newEthBlock)
// fetch block header from mainchain
blockHeader, err := k.contractCaller.GetMainChainBlock(newEthBlock)
if err != nil {
k.Logger(ctx).Error("Error fetching block header from mainchain while calculating next span seed", "error", err)
return common.Hash{}, err
}
return blockHeader.Hash(), nil
}
// -----------------------------------------------------------------------------
// Params
// SetParams sets the bor module's parameters.
func (k *Keeper) SetParams(ctx sdk.Context, params types.Params) {
k.paramSpace.SetParamSet(ctx, ¶ms)
}
// GetParams gets the bor module's parameters.
func (k *Keeper) GetParams(ctx sdk.Context) (params types.Params) {
k.paramSpace.GetParamSet(ctx, ¶ms)
return
}
//
// Utils
//
// IterateSpansAndApplyFn interate spans and apply the given function.
func (k *Keeper) IterateSpansAndApplyFn(ctx sdk.Context, f func(span hmTypes.Span) error) {
store := ctx.KVStore(k.storeKey)
// get span iterator
iterator := sdk.KVStorePrefixIterator(store, SpanPrefixKey)
defer iterator.Close()
// loop through spans to get valid spans
for ; iterator.Valid(); iterator.Next() {
// unmarshall span
var result hmTypes.Span
if err := k.cdc.UnmarshalBinaryBare(iterator.Value(), &result); err != nil {
k.Logger(ctx).Error("Error UnmarshalBinaryBare", "error", err)
}
// call function and return if required
if err := f(result); err != nil {
return
}
}
}