-
Notifications
You must be signed in to change notification settings - Fork 289
/
keeper_valset.go
193 lines (178 loc) · 7.2 KB
/
keeper_valset.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
package keeper
import (
"fmt"
"math/big"
cosmosmath "cosmossdk.io/math"
"github.com/celestiaorg/celestia-app/x/qgb/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// GetLatestValset returns the latest validator set in store. This is different
// from the CurrentValset because this one has been saved and is therefore *the*
// latest valset saved in store. GetCurrentValset shows you what could be, if
// you chose to save it, this function shows you what is the latest valset that
// was saved. If not found, returns the current valset in case no valset exists
// in store after pruning. Otherwise panics.
func (k Keeper) GetLatestValset(ctx sdk.Context) (*types.Valset, error) {
if !k.CheckLatestAttestationNonce(ctx) {
return nil, types.ErrLatestAttestationNonceStillNotInitialized
}
if !k.CheckEarliestAvailableAttestationNonce(ctx) {
return nil, types.ErrEarliestAvailableNonceStillNotInitialized
}
latestNonce := k.GetLatestAttestationNonce(ctx)
earliestAvailableNonce := k.GetEarliestAvailableAttestationNonce(ctx)
for i := latestNonce; i >= earliestAvailableNonce; i-- {
at, found, err := k.GetAttestationByNonce(ctx, i)
if err != nil {
return nil, err
}
if !found {
panic(errors.Wrap(
types.ErrNilAttestation,
fmt.Sprintf("stumbled upon nil attestation for nonce %d", i),
))
}
valset, ok := at.(*types.Valset)
if ok {
return valset, nil
}
}
if earliestAvailableNonce == 1 {
// this means that the no pruning happened, but still the valset is
// missing from the store
panic(errors.Wrap(sdkerrors.ErrNotFound, "couldn't find latest valset"))
}
// this means that the latest valset was pruned and we can return the
// current one as no significant changes to it happened
currentVs, err := k.GetCurrentValset(ctx)
return ¤tVs, err
}
// SetLatestUnBondingBlockHeight sets the latest unbonding block height. Note
// this value is not saved to state or loaded at genesis. This value is reset to
// zero on chain upgrade.
func (k Keeper) SetLatestUnBondingBlockHeight(ctx sdk.Context, unbondingBlockHeight uint64) {
store := ctx.KVStore(k.storeKey)
store.Set([]byte(types.LatestUnBondingBlockHeight), types.UInt64Bytes(unbondingBlockHeight))
}
// GetLatestUnBondingBlockHeight returns the latest unbonding block height or
// zero if not set. This value is not saved or loaded at genesis. This value is
// reset to zero on chain upgrade.
func (k Keeper) GetLatestUnBondingBlockHeight(ctx sdk.Context) uint64 {
store := ctx.KVStore(k.storeKey)
bytes := store.Get([]byte(types.LatestUnBondingBlockHeight))
if len(bytes) == 0 {
return 0
}
return UInt64FromBytes(bytes)
}
func (k Keeper) GetCurrentValset(ctx sdk.Context) (types.Valset, error) {
validators := k.StakingKeeper.GetBondedValidatorsByPower(ctx)
if len(validators) == 0 {
return types.Valset{}, types.ErrNoValidators
}
// allocate enough space for all validators, but len zero, we then append so
// that we have an array with extra capacity but the correct length
// depending on how many validators have keys set.
bridgeValidators := make([]*types.InternalBridgeValidator, 0, len(validators))
totalPower := sdk.NewInt(0)
// TODO someone with in depth info on Cosmos staking should determine if
// this is doing what I think it's doing
for _, validator := range validators {
val := validator.GetOperator()
if err := sdk.VerifyAddressFormat(val); err != nil {
return types.Valset{}, errors.Wrap(err, types.ErrInvalidValAddress.Error())
}
p := sdk.NewInt(k.StakingKeeper.GetLastValidatorPower(ctx, val))
// TODO make sure this is always the case
bv := types.BridgeValidator{Power: p.Uint64(), EvmAddress: validator.EvmAddress}
ibv, err := types.NewInternalBridgeValidator(bv)
if err != nil {
return types.Valset{}, errors.Wrapf(err, types.ErrInvalidEVMAddress.Error(), val)
}
bridgeValidators = append(bridgeValidators, ibv)
totalPower = totalPower.Add(p)
}
// normalize power values to the maximum bridge power which is 2^32
for i := range bridgeValidators {
bridgeValidators[i].Power = normalizeValidatorPower(bridgeValidators[i].Power, totalPower)
}
// increment the nonce, since this potential future valset should be after
// the current valset
if !k.CheckLatestAttestationNonce(ctx) {
return types.Valset{}, types.ErrLatestAttestationNonceStillNotInitialized
}
valsetNonce := k.GetLatestAttestationNonce(ctx) + 1
valset, err := types.NewValset(valsetNonce, uint64(ctx.BlockHeight()), bridgeValidators, ctx.BlockTime())
if err != nil {
return types.Valset{}, (errors.Wrap(err, types.ErrInvalidValset.Error()))
}
return *valset, nil
}
// normalizeValidatorPower scales rawPower with respect to totalValidatorPower
// to take a value between 0 and 2^32 Uses BigInt operations to avoid overflow
// errors Example: rawPower = max (2^63 - 1), totalValidatorPower = 1 validator:
// (2^63 - 1)
//
// result: (2^63 - 1) * 2^32 / (2^63 - 1) = 2^32 = 4294967296 [this is the multiplier value below, our max output]
//
// Example: rawPower = max (2^63 - 1), totalValidatorPower = 1000 validators with the same power: 1000*(2^63 - 1)
//
// result: (2^63 - 1) * 2^32 / (1000(2^63 - 1)) = 2^32 / 1000 = 4294967
func normalizeValidatorPower(rawPower uint64, totalValidatorPower cosmosmath.Int) uint64 {
// Compute rawPower * multiplier / quotient Set the upper limit to 2^32,
// which would happen if there is a single validator with all the power
multiplier := new(big.Int).SetUint64(4294967296)
// Scale by current validator powers, a particularly low-power validator (1
// out of over 2^32) would have 0 power
quotient := new(big.Int).Set(totalValidatorPower.BigInt())
power := new(big.Int).SetUint64(rawPower)
power.Mul(power, multiplier)
power.Quo(power, quotient)
return power.Uint64()
}
// GetLatestValsetBeforeNonce returns the previous valset before the provided
// `nonce`. the `nonce` can be a valset, but this method will return the valset
// before it. If the provided nonce is 1, it will return an error, because,
// there is no valset before nonce 1.
func (k Keeper) GetLatestValsetBeforeNonce(ctx sdk.Context, nonce uint64) (*types.Valset, error) {
if !k.CheckLatestAttestationNonce(ctx) {
return nil, types.ErrLatestAttestationNonceStillNotInitialized
}
if !k.CheckEarliestAvailableAttestationNonce(ctx) {
return nil, types.ErrEarliestAvailableNonceStillNotInitialized
}
if nonce == 1 {
return nil, types.ErrNoValsetBeforeNonceOne
}
earliestAvailableNonce := k.GetEarliestAvailableAttestationNonce(ctx)
if nonce < earliestAvailableNonce {
return nil, types.ErrRequestedNonceWasPruned
}
if nonce > k.GetLatestAttestationNonce(ctx) {
return nil, types.ErrNonceHigherThanLatestAttestationNonce
}
// starting at nonce-1 because the current nonce can be a valset and we need
// the previous one.
for i := nonce - 1; i >= earliestAvailableNonce; i-- {
at, found, err := k.GetAttestationByNonce(ctx, i)
if err != nil {
return nil, err
}
if !found {
return nil, errors.Wrap(
types.ErrNilAttestation,
fmt.Sprintf("nonce=%d", i),
)
}
valset, ok := at.(*types.Valset)
if ok {
return valset, nil
}
}
return nil, errors.Wrap(
sdkerrors.ErrNotFound,
fmt.Sprintf("couldn't find valset before nonce %d", nonce),
)
}