2018-06-26 19:00:12 -07:00
|
|
|
package keeper
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-08-31 00:37:25 -07:00
|
|
|
"container/list"
|
2018-06-26 19:00:12 -07:00
|
|
|
"fmt"
|
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
|
|
"github.com/tendermint/tendermint/crypto"
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
"github.com/cosmos/cosmos-sdk/x/stake/types"
|
|
|
|
)
|
|
|
|
|
2018-09-01 13:21:42 -07:00
|
|
|
// Cache the amino decoding of validators, as it can be the case that repeated slashing calls
|
|
|
|
// cause many calls to GetValidator, which were shown to throttle the state machine in our
|
|
|
|
// simulation. Note this is quite biased though, as the simulator does more slashes than a
|
|
|
|
// live chain should, however we require the slashing to be fast as noone pays gas for it.
|
2018-08-31 00:37:25 -07:00
|
|
|
type cachedValidator struct {
|
|
|
|
val types.Validator
|
2018-09-02 12:42:25 -07:00
|
|
|
marshalled string // marshalled amino bytes for the validator object (not operator address)
|
2018-08-31 00:37:25 -07:00
|
|
|
}
|
|
|
|
|
2018-09-02 12:42:25 -07:00
|
|
|
// validatorCache-key: validator amino bytes
|
2018-09-01 13:21:42 -07:00
|
|
|
var validatorCache = make(map[string]cachedValidator, 500)
|
2018-08-31 00:37:25 -07:00
|
|
|
var validatorCacheList = list.New()
|
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
// get a single validator
|
2018-08-30 21:06:44 -07:00
|
|
|
func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator types.Validator, found bool) {
|
2018-06-26 19:00:12 -07:00
|
|
|
store := ctx.KVStore(k.storeKey)
|
2018-07-03 22:32:49 -07:00
|
|
|
value := store.Get(GetValidatorKey(addr))
|
|
|
|
if value == nil {
|
2018-06-26 19:00:12 -07:00
|
|
|
return validator, false
|
|
|
|
}
|
2018-09-02 12:42:25 -07:00
|
|
|
|
2018-09-01 13:21:42 -07:00
|
|
|
// If these amino encoded bytes are in the cache, return the cached validator
|
2018-08-31 00:37:25 -07:00
|
|
|
strValue := string(value)
|
|
|
|
if val, ok := validatorCache[strValue]; ok {
|
|
|
|
valToReturn := val.val
|
|
|
|
// Doesn't mutate the cache's value
|
2018-09-08 01:44:58 -07:00
|
|
|
valToReturn.OperatorAddr = addr
|
2018-08-31 00:37:25 -07:00
|
|
|
return valToReturn, true
|
|
|
|
}
|
2018-09-02 12:42:25 -07:00
|
|
|
|
2018-09-01 13:21:42 -07:00
|
|
|
// amino bytes weren't found in cache, so amino unmarshal and add it to the cache
|
2018-08-31 08:29:32 -07:00
|
|
|
validator = types.MustUnmarshalValidator(k.cdc, addr, value)
|
|
|
|
cachedVal := cachedValidator{validator, strValue}
|
|
|
|
validatorCache[strValue] = cachedValidator{validator, strValue}
|
|
|
|
validatorCacheList.PushBack(cachedVal)
|
2018-09-02 12:42:25 -07:00
|
|
|
|
2018-09-01 13:21:42 -07:00
|
|
|
// if the cache is too big, pop off the last element from it
|
2018-08-31 08:29:32 -07:00
|
|
|
if validatorCacheList.Len() > 500 {
|
|
|
|
valToRemove := validatorCacheList.Remove(validatorCacheList.Front()).(cachedValidator)
|
|
|
|
delete(validatorCache, valToRemove.marshalled)
|
|
|
|
}
|
|
|
|
|
2018-07-04 14:07:06 -07:00
|
|
|
validator = types.MustUnmarshalValidator(k.cdc, addr, value)
|
2018-06-26 19:00:12 -07:00
|
|
|
return validator, true
|
|
|
|
}
|
|
|
|
|
|
|
|
// get a single validator by pubkey
|
|
|
|
func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (validator types.Validator, found bool) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
addr := store.Get(GetValidatorByPubKeyIndexKey(pubkey))
|
|
|
|
if addr == nil {
|
|
|
|
return validator, false
|
|
|
|
}
|
|
|
|
return k.GetValidator(ctx, addr)
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the main record holding validator details
|
|
|
|
func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
2018-07-04 14:07:06 -07:00
|
|
|
bz := types.MustMarshalValidator(k.cdc, validator)
|
2018-09-08 01:44:58 -07:00
|
|
|
store.Set(GetValidatorKey(validator.OperatorAddr), bz)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// validator index
|
|
|
|
func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
2018-09-08 01:44:58 -07:00
|
|
|
store.Set(GetValidatorByPubKeyIndexKey(validator.ConsPubKey), validator.OperatorAddr)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// validator index
|
|
|
|
func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Validator, pool types.Pool) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
2018-09-08 01:44:58 -07:00
|
|
|
store.Set(GetValidatorsByPowerIndexKey(validator, pool), validator.OperatorAddr)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// validator index
|
|
|
|
func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
2018-09-08 01:44:58 -07:00
|
|
|
store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{})
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// used in testing
|
|
|
|
func (k Keeper) validatorByPowerIndexExists(ctx sdk.Context, power []byte) bool {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
return store.Get(power) != nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the set of all validators with no limits, used during genesis dump
|
|
|
|
func (k Keeper) GetAllValidators(ctx sdk.Context) (validators []types.Validator) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey)
|
|
|
|
|
|
|
|
i := 0
|
|
|
|
for ; ; i++ {
|
|
|
|
if !iterator.Valid() {
|
|
|
|
break
|
|
|
|
}
|
2018-07-03 22:32:49 -07:00
|
|
|
addr := iterator.Key()[1:]
|
2018-07-04 14:07:06 -07:00
|
|
|
validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
|
2018-06-26 19:00:12 -07:00
|
|
|
validators = append(validators, validator)
|
|
|
|
iterator.Next()
|
|
|
|
}
|
|
|
|
iterator.Close()
|
|
|
|
return validators
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the set of all validators, retrieve a maxRetrieve number of records
|
|
|
|
func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators []types.Validator) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
iterator := sdk.KVStorePrefixIterator(store, ValidatorsKey)
|
|
|
|
|
|
|
|
validators = make([]types.Validator, maxRetrieve)
|
|
|
|
i := 0
|
|
|
|
for ; ; i++ {
|
|
|
|
if !iterator.Valid() || i > int(maxRetrieve-1) {
|
|
|
|
break
|
|
|
|
}
|
2018-07-03 22:32:49 -07:00
|
|
|
addr := iterator.Key()[1:]
|
2018-07-04 14:07:06 -07:00
|
|
|
validator := types.MustUnmarshalValidator(k.cdc, addr, iterator.Value())
|
2018-06-26 19:00:12 -07:00
|
|
|
validators[i] = validator
|
|
|
|
iterator.Next()
|
|
|
|
}
|
|
|
|
iterator.Close()
|
|
|
|
return validators[:i] // trim
|
|
|
|
}
|
|
|
|
|
|
|
|
//___________________________________________________________________________
|
|
|
|
|
|
|
|
// get the group of the bonded validators
|
|
|
|
func (k Keeper) GetValidatorsBonded(ctx sdk.Context) (validators []types.Validator) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
|
|
|
|
// add the actual validator power sorted store
|
|
|
|
maxValidators := k.GetParams(ctx).MaxValidators
|
|
|
|
validators = make([]types.Validator, maxValidators)
|
|
|
|
|
|
|
|
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
|
|
|
|
i := 0
|
|
|
|
for ; iterator.Valid(); iterator.Next() {
|
|
|
|
|
|
|
|
// sanity check
|
|
|
|
if i > int(maxValidators-1) {
|
|
|
|
panic("maxValidators is less than the number of records in ValidatorsBonded Store, store should have been updated")
|
|
|
|
}
|
2018-07-02 17:58:22 -07:00
|
|
|
address := GetAddressFromValBondedIndexKey(iterator.Key())
|
2018-06-26 19:00:12 -07:00
|
|
|
validator, found := k.GetValidator(ctx, address)
|
2018-09-11 02:12:35 -07:00
|
|
|
ensureValidatorFound(found, address)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
validators[i] = validator
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
iterator.Close()
|
|
|
|
return validators[:i] // trim
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the group of bonded validators sorted by power-rank
|
2018-08-08 15:57:59 -07:00
|
|
|
//
|
|
|
|
// TODO: Rename to GetBondedValidatorsByPower or GetValidatorsByPower(ctx, status)
|
2018-06-26 19:00:12 -07:00
|
|
|
func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
maxValidators := k.GetParams(ctx).MaxValidators
|
|
|
|
validators := make([]types.Validator, maxValidators)
|
|
|
|
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) // largest to smallest
|
|
|
|
i := 0
|
|
|
|
for {
|
|
|
|
if !iterator.Valid() || i > int(maxValidators-1) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
address := iterator.Value()
|
|
|
|
validator, found := k.GetValidator(ctx, address)
|
2018-09-11 02:12:35 -07:00
|
|
|
ensureValidatorFound(found, address)
|
|
|
|
|
2018-07-13 13:46:14 -07:00
|
|
|
if validator.Status == sdk.Bonded {
|
2018-06-26 19:00:12 -07:00
|
|
|
validators[i] = validator
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
iterator.Next()
|
|
|
|
}
|
|
|
|
iterator.Close()
|
|
|
|
return validators[:i] // trim
|
|
|
|
}
|
|
|
|
|
|
|
|
//_________________________________________________________________________
|
|
|
|
// Accumulated updates to the active/bonded validator set for tendermint
|
|
|
|
|
|
|
|
// get the most recently updated validators
|
2018-09-12 00:16:28 -07:00
|
|
|
//
|
|
|
|
// CONTRACT: Only validators with non-zero power or zero-power that were bonded
|
|
|
|
// at the previous block height or were removed from the validator set entirely
|
|
|
|
// are returned to Tendermint.
|
|
|
|
func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) {
|
2018-09-12 21:53:55 -07:00
|
|
|
tstore := ctx.TransientStore(k.storeTKey)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-09-12 21:53:55 -07:00
|
|
|
iterator := sdk.KVStorePrefixIterator(tstore, TendermintUpdatesTKey)
|
2018-06-26 19:00:12 -07:00
|
|
|
for ; iterator.Valid(); iterator.Next() {
|
2018-09-12 00:16:28 -07:00
|
|
|
var abciVal abci.Validator
|
|
|
|
|
|
|
|
abciValBytes := iterator.Value()
|
|
|
|
k.cdc.MustUnmarshalBinary(abciValBytes, &abciVal)
|
|
|
|
|
|
|
|
val, found := k.GetValidator(ctx, abciVal.GetAddress())
|
|
|
|
if found {
|
|
|
|
// The validator is new or already exists in the store and must adhere to
|
|
|
|
// Tendermint invariants.
|
|
|
|
prevBonded := val.BondHeight < ctx.BlockHeight() && val.BondHeight > val.UnbondingHeight
|
|
|
|
zeroPower := val.GetPower().Equal(sdk.ZeroDec())
|
|
|
|
|
|
|
|
if !zeroPower || zeroPower && prevBonded {
|
|
|
|
updates = append(updates, abciVal)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Add the ABCI validator in such a case where the validator was removed
|
|
|
|
// from the store as it must have existed before.
|
|
|
|
updates = append(updates, abciVal)
|
|
|
|
}
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
2018-09-12 00:16:28 -07:00
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
iterator.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
//___________________________________________________________________________
|
|
|
|
|
2018-08-08 15:57:59 -07:00
|
|
|
// Perform all the necessary steps for when a validator changes its power. This
|
2018-07-10 15:36:57 -07:00
|
|
|
// function updates all validator stores as well as tendermint update store.
|
2018-07-27 21:42:07 -07:00
|
|
|
// It may kick out validators if a new validator is entering the bonded validator
|
2018-07-10 15:36:57 -07:00
|
|
|
// group.
|
|
|
|
//
|
2018-07-09 16:08:35 -07:00
|
|
|
// nolint: gocyclo
|
2018-08-08 15:57:59 -07:00
|
|
|
// TODO: Remove above nolint, function needs to be simplified!
|
2018-06-26 19:00:12 -07:00
|
|
|
func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
2018-09-12 21:53:55 -07:00
|
|
|
tstore := ctx.TransientStore(k.storeTKey)
|
2018-06-26 19:00:12 -07:00
|
|
|
pool := k.GetPool(ctx)
|
2018-09-08 01:44:58 -07:00
|
|
|
oldValidator, oldFound := k.GetValidator(ctx, validator.OperatorAddr)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-08-22 08:56:13 -07:00
|
|
|
validator = k.updateForJailing(ctx, oldFound, oldValidator, validator)
|
2018-07-09 23:38:09 -07:00
|
|
|
powerIncreasing := k.getPowerIncreasing(ctx, oldFound, oldValidator, validator)
|
2018-09-12 00:16:28 -07:00
|
|
|
validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator)
|
2018-07-09 23:38:09 -07:00
|
|
|
valPower := k.updateValidatorPower(ctx, oldFound, oldValidator, validator, pool)
|
|
|
|
cliffPower := k.GetCliffValidatorPower(ctx)
|
2018-09-11 02:14:32 -07:00
|
|
|
cliffValExists := (cliffPower != nil)
|
|
|
|
var valPowerLTcliffPower bool
|
|
|
|
if cliffValExists {
|
|
|
|
valPowerLTcliffPower = (bytes.Compare(valPower, cliffPower) == -1)
|
|
|
|
}
|
2018-07-09 23:38:09 -07:00
|
|
|
|
|
|
|
switch {
|
2018-08-24 18:47:31 -07:00
|
|
|
|
2018-08-08 15:57:59 -07:00
|
|
|
// if the validator is already bonded and the power is increasing, we need
|
|
|
|
// perform the following:
|
|
|
|
// a) update Tendermint
|
|
|
|
// b) check if the cliff validator needs to be updated
|
2018-08-22 08:56:13 -07:00
|
|
|
case powerIncreasing && !validator.Jailed &&
|
2018-07-13 13:46:14 -07:00
|
|
|
(oldFound && oldValidator.Status == sdk.Bonded):
|
2018-07-09 23:38:09 -07:00
|
|
|
|
|
|
|
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
2018-09-12 21:53:55 -07:00
|
|
|
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz)
|
2018-07-09 23:38:09 -07:00
|
|
|
|
2018-09-11 02:14:32 -07:00
|
|
|
if cliffValExists {
|
2018-08-30 21:06:44 -07:00
|
|
|
cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx))
|
2018-09-08 01:44:58 -07:00
|
|
|
if bytes.Equal(cliffAddr, validator.OperatorAddr) {
|
2018-08-08 15:57:59 -07:00
|
|
|
k.updateCliffValidator(ctx, validator)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 07:23:31 -07:00
|
|
|
// if is a new validator and the new power is less than the cliff validator
|
2018-09-11 02:14:32 -07:00
|
|
|
case cliffValExists && !oldFound && valPowerLTcliffPower:
|
2018-07-10 07:23:31 -07:00
|
|
|
// skip to completion
|
|
|
|
|
2018-08-08 15:57:59 -07:00
|
|
|
// if was unbonded and the new power is less than the cliff validator
|
2018-09-11 02:14:32 -07:00
|
|
|
case cliffValExists &&
|
2018-07-13 13:46:14 -07:00
|
|
|
(oldFound && oldValidator.Status == sdk.Unbonded) &&
|
2018-09-11 02:14:32 -07:00
|
|
|
valPowerLTcliffPower: //(valPower < cliffPower
|
2018-07-09 23:38:09 -07:00
|
|
|
// skip to completion
|
|
|
|
|
2018-08-24 18:47:31 -07:00
|
|
|
default:
|
|
|
|
// default case - validator was either:
|
2018-07-10 16:27:39 -07:00
|
|
|
// a) not-bonded and now has power-rank greater than cliff validator
|
|
|
|
// b) bonded and now has decreased in power
|
2018-08-24 18:47:31 -07:00
|
|
|
|
2018-07-09 23:38:09 -07:00
|
|
|
// update the validator set for this validator
|
2018-07-10 15:36:57 -07:00
|
|
|
updatedVal, updated := k.UpdateBondedValidators(ctx, validator)
|
2018-08-08 15:57:59 -07:00
|
|
|
if updated {
|
|
|
|
// the validator has changed bonding status
|
2018-07-09 23:38:09 -07:00
|
|
|
validator = updatedVal
|
2018-07-13 13:46:14 -07:00
|
|
|
break
|
|
|
|
}
|
2018-07-09 23:38:09 -07:00
|
|
|
|
2018-07-13 13:46:14 -07:00
|
|
|
// if decreased in power but still bonded, update Tendermint validator
|
|
|
|
if oldFound && oldValidator.BondedTokens().GT(validator.BondedTokens()) {
|
|
|
|
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
2018-09-12 21:53:55 -07:00
|
|
|
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bz)
|
2018-07-09 23:38:09 -07:00
|
|
|
}
|
|
|
|
}
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-07-09 23:38:09 -07:00
|
|
|
k.SetValidator(ctx, validator)
|
|
|
|
return validator
|
|
|
|
}
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-08-08 15:57:59 -07:00
|
|
|
// updateCliffValidator determines if the current cliff validator needs to be
|
|
|
|
// updated or swapped. If the provided affected validator is the current cliff
|
|
|
|
// validator before it's power was increased, either the cliff power key will
|
|
|
|
// be updated or if it's power is greater than the next bonded validator by
|
|
|
|
// power, it'll be swapped.
|
|
|
|
func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validator) {
|
|
|
|
var newCliffVal types.Validator
|
|
|
|
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
pool := k.GetPool(ctx)
|
2018-08-30 21:06:44 -07:00
|
|
|
cliffAddr := sdk.ValAddress(k.GetCliffValidator(ctx))
|
2018-08-08 15:57:59 -07:00
|
|
|
|
|
|
|
oldCliffVal, found := k.GetValidator(ctx, cliffAddr)
|
|
|
|
if !found {
|
2018-09-12 00:16:28 -07:00
|
|
|
panic(fmt.Sprintf("cliff validator record not found for address: %X\n", cliffAddr))
|
2018-08-08 15:57:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a validator iterator ranging from smallest to largest by power
|
|
|
|
// starting the current cliff validator's power.
|
|
|
|
start := GetValidatorsByPowerIndexKey(oldCliffVal, pool)
|
|
|
|
end := sdk.PrefixEndBytes(ValidatorsByPowerIndexKey)
|
|
|
|
iterator := store.Iterator(start, end)
|
|
|
|
|
|
|
|
if iterator.Valid() {
|
|
|
|
ownerAddr := iterator.Value()
|
|
|
|
currVal, found := k.GetValidator(ctx, ownerAddr)
|
2018-09-11 02:12:35 -07:00
|
|
|
ensureValidatorFound(found, ownerAddr)
|
2018-08-08 15:57:59 -07:00
|
|
|
|
2018-08-22 08:56:13 -07:00
|
|
|
if currVal.Status != sdk.Bonded || currVal.Jailed {
|
2018-09-12 00:16:28 -07:00
|
|
|
panic(fmt.Sprintf("unexpected jailed or unbonded validator for address: %X\n", ownerAddr))
|
2018-08-08 15:57:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
newCliffVal = currVal
|
|
|
|
iterator.Close()
|
|
|
|
} else {
|
|
|
|
panic("failed to create valid validator power iterator")
|
|
|
|
}
|
|
|
|
|
2018-08-17 08:33:13 -07:00
|
|
|
affectedValRank := GetValidatorsByPowerIndexKey(affectedVal, pool)
|
|
|
|
newCliffValRank := GetValidatorsByPowerIndexKey(newCliffVal, pool)
|
|
|
|
|
2018-09-08 01:44:58 -07:00
|
|
|
if bytes.Equal(affectedVal.OperatorAddr, newCliffVal.OperatorAddr) {
|
2018-08-08 15:57:59 -07:00
|
|
|
// The affected validator remains the cliff validator, however, since
|
2018-08-17 08:33:13 -07:00
|
|
|
// the store does not contain the new power, update the new power rank.
|
|
|
|
store.Set(ValidatorPowerCliffKey, affectedValRank)
|
|
|
|
} else if bytes.Compare(affectedValRank, newCliffValRank) > 0 {
|
2018-08-08 15:57:59 -07:00
|
|
|
// The affected validator no longer remains the cliff validator as it's
|
2018-08-17 08:33:13 -07:00
|
|
|
// power is greater than the new cliff validator.
|
2018-08-08 15:57:59 -07:00
|
|
|
k.setCliffValidator(ctx, newCliffVal, pool)
|
2018-08-17 08:33:13 -07:00
|
|
|
} else {
|
|
|
|
panic("invariant broken: the cliff validator should change or it should remain the same")
|
2018-08-08 15:57:59 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-22 08:56:13 -07:00
|
|
|
func (k Keeper) updateForJailing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) types.Validator {
|
|
|
|
if newValidator.Jailed && oldFound && oldValidator.Status == sdk.Bonded {
|
2018-08-24 18:47:31 -07:00
|
|
|
newValidator = k.beginUnbondingValidator(ctx, newValidator)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-08-22 08:56:13 -07:00
|
|
|
// need to also clear the cliff validator spot because the jail has
|
2018-06-26 19:00:12 -07:00
|
|
|
// opened up a new spot which will be filled when
|
|
|
|
// updateValidatorsBonded is called
|
|
|
|
k.clearCliffValidator(ctx)
|
|
|
|
}
|
2018-07-09 23:38:09 -07:00
|
|
|
return newValidator
|
|
|
|
}
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-08-31 15:22:37 -07:00
|
|
|
// nolint: unparam
|
2018-07-09 23:38:09 -07:00
|
|
|
func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator, newValidator types.Validator) bool {
|
2018-07-13 13:46:14 -07:00
|
|
|
if oldFound && oldValidator.BondedTokens().LT(newValidator.BondedTokens()) {
|
2018-07-09 23:38:09 -07:00
|
|
|
return true
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
2018-07-09 23:38:09 -07:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2018-07-10 15:36:57 -07:00
|
|
|
// get the bond height and incremented intra-tx counter
|
2018-08-31 15:22:37 -07:00
|
|
|
// nolint: unparam
|
2018-09-12 00:16:28 -07:00
|
|
|
func (k Keeper) bondIncrement(
|
|
|
|
ctx sdk.Context, found bool, oldValidator types.Validator) (height int64, intraTxCounter int16) {
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-09-12 00:16:28 -07:00
|
|
|
// if already a validator, copy the old block height and counter
|
|
|
|
if found && oldValidator.Status == sdk.Bonded {
|
2018-07-09 23:38:09 -07:00
|
|
|
height = oldValidator.BondHeight
|
|
|
|
intraTxCounter = oldValidator.BondIntraTxCounter
|
|
|
|
return
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
2018-09-12 00:16:28 -07:00
|
|
|
|
2018-07-09 23:38:09 -07:00
|
|
|
height = ctx.BlockHeight()
|
|
|
|
counter := k.GetIntraTxCounter(ctx)
|
|
|
|
intraTxCounter = counter
|
2018-09-12 00:16:28 -07:00
|
|
|
|
2018-07-09 23:38:09 -07:00
|
|
|
k.SetIntraTxCounter(ctx, counter+1)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (k Keeper) updateValidatorPower(ctx sdk.Context, oldFound bool, oldValidator,
|
|
|
|
newValidator types.Validator, pool types.Pool) (valPower []byte) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
// update the list ordered by voting power
|
|
|
|
if oldFound {
|
|
|
|
store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool))
|
|
|
|
}
|
2018-07-09 23:38:09 -07:00
|
|
|
valPower = GetValidatorsByPowerIndexKey(newValidator, pool)
|
2018-09-08 01:44:58 -07:00
|
|
|
store.Set(valPower, newValidator.OperatorAddr)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-07-09 23:38:09 -07:00
|
|
|
return valPower
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
2018-07-10 15:36:57 -07:00
|
|
|
// Update the bonded validator group based on a change to the validator
|
|
|
|
// affectedValidator. This function potentially adds the affectedValidator to
|
|
|
|
// the bonded validator group which kicks out the cliff validator. Under this
|
|
|
|
// situation this function returns the updated affectedValidator.
|
2018-06-26 19:00:12 -07:00
|
|
|
//
|
2018-07-10 15:36:57 -07:00
|
|
|
// The correct bonded subset of validators is retrieved by iterating through an
|
|
|
|
// index of the validators sorted by power, stored using the
|
|
|
|
// ValidatorsByPowerIndexKey. Simultaneously the current validator records are
|
|
|
|
// updated in store with the ValidatorsBondedIndexKey. This store is used to
|
|
|
|
// determine if a validator is a validator without needing to iterate over all
|
|
|
|
// validators.
|
2018-07-10 07:23:31 -07:00
|
|
|
//
|
2018-07-09 16:16:43 -07:00
|
|
|
// nolint: gocyclo
|
|
|
|
// TODO: Remove the above golint
|
2018-08-08 15:57:59 -07:00
|
|
|
func (k Keeper) UpdateBondedValidators(
|
|
|
|
ctx sdk.Context, affectedValidator types.Validator) (
|
|
|
|
updatedVal types.Validator, updated bool) {
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
|
2018-07-03 15:08:37 -07:00
|
|
|
oldCliffValidatorAddr := k.GetCliffValidator(ctx)
|
2018-06-26 19:00:12 -07:00
|
|
|
maxValidators := k.GetParams(ctx).MaxValidators
|
|
|
|
bondedValidatorsCount := 0
|
2018-07-10 07:23:31 -07:00
|
|
|
var validator, validatorToBond types.Validator
|
2018-07-10 15:36:57 -07:00
|
|
|
newValidatorBonded := false
|
2018-07-10 07:23:31 -07:00
|
|
|
|
2018-08-08 15:57:59 -07:00
|
|
|
// create a validator iterator ranging from largest to smallest by power
|
|
|
|
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
|
2018-06-26 19:00:12 -07:00
|
|
|
for {
|
|
|
|
if !iterator.Valid() || bondedValidatorsCount > int(maxValidators-1) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// either retrieve the original validator from the store, or under the
|
2018-07-10 07:23:31 -07:00
|
|
|
// situation that this is the "affected validator" just use the
|
|
|
|
// validator provided because it has not yet been updated in the store
|
2018-06-26 19:00:12 -07:00
|
|
|
ownerAddr := iterator.Value()
|
2018-09-08 01:44:58 -07:00
|
|
|
if bytes.Equal(ownerAddr, affectedValidator.OperatorAddr) {
|
2018-07-06 16:53:07 -07:00
|
|
|
validator = affectedValidator
|
2018-06-26 19:00:12 -07:00
|
|
|
} else {
|
|
|
|
var found bool
|
|
|
|
validator, found = k.GetValidator(ctx, ownerAddr)
|
2018-09-11 02:12:35 -07:00
|
|
|
ensureValidatorFound(found, ownerAddr)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
2018-08-24 18:47:31 -07:00
|
|
|
// if we've reached jailed validators no further bonded validators exist
|
|
|
|
if validator.Jailed {
|
2018-09-12 00:16:28 -07:00
|
|
|
if validator.Status == sdk.Bonded {
|
|
|
|
panic(fmt.Sprintf("jailed validator cannot be bonded, address: %X\n", ownerAddr))
|
|
|
|
}
|
|
|
|
|
2018-08-24 18:47:31 -07:00
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2018-09-12 00:16:28 -07:00
|
|
|
// increment the total number of bonded validators and potentially mark
|
|
|
|
// the validator to bond
|
2018-08-24 18:47:31 -07:00
|
|
|
if validator.Status != sdk.Bonded {
|
|
|
|
validatorToBond = validator
|
|
|
|
if newValidatorBonded {
|
|
|
|
panic("already decided to bond a validator, can't bond another!")
|
2018-07-06 16:53:07 -07:00
|
|
|
}
|
2018-08-24 18:47:31 -07:00
|
|
|
newValidatorBonded = true
|
2018-08-15 11:51:19 -07:00
|
|
|
}
|
2018-07-10 07:23:31 -07:00
|
|
|
|
2018-08-15 11:51:19 -07:00
|
|
|
bondedValidatorsCount++
|
2018-06-26 19:00:12 -07:00
|
|
|
iterator.Next()
|
|
|
|
}
|
2018-08-08 15:57:59 -07:00
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
iterator.Close()
|
|
|
|
|
2018-09-08 01:44:58 -07:00
|
|
|
if newValidatorBonded && bytes.Equal(oldCliffValidatorAddr, validator.OperatorAddr) {
|
2018-08-16 08:36:15 -07:00
|
|
|
panic("cliff validator has not been changed, yet we bonded a new validator")
|
|
|
|
}
|
|
|
|
|
2018-07-10 07:23:31 -07:00
|
|
|
// clear or set the cliff validator
|
|
|
|
if bondedValidatorsCount == int(maxValidators) {
|
|
|
|
k.setCliffValidator(ctx, validator, k.GetPool(ctx))
|
|
|
|
} else if len(oldCliffValidatorAddr) > 0 {
|
|
|
|
k.clearCliffValidator(ctx)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
2018-08-08 15:57:59 -07:00
|
|
|
// swap the cliff validator for a new validator if the affected validator
|
|
|
|
// was bonded
|
2018-07-10 15:36:57 -07:00
|
|
|
if newValidatorBonded {
|
2018-07-10 07:23:31 -07:00
|
|
|
if oldCliffValidatorAddr != nil {
|
2018-08-18 04:41:12 -07:00
|
|
|
oldCliffVal, found := k.GetValidator(ctx, oldCliffValidatorAddr)
|
2018-09-11 02:12:35 -07:00
|
|
|
ensureValidatorFound(found, oldCliffValidatorAddr)
|
2018-07-10 07:23:31 -07:00
|
|
|
|
2018-09-08 01:44:58 -07:00
|
|
|
if bytes.Equal(validatorToBond.OperatorAddr, affectedValidator.OperatorAddr) {
|
2018-08-24 18:47:31 -07:00
|
|
|
|
|
|
|
// begin unbonding the old cliff validator iff the affected
|
|
|
|
// validator was newly bonded and has greater power
|
|
|
|
k.beginUnbondingValidator(ctx, oldCliffVal)
|
2018-08-18 04:41:12 -07:00
|
|
|
} else {
|
2018-08-24 18:47:31 -07:00
|
|
|
// otherwise begin unbonding the affected validator, which must
|
|
|
|
// have been kicked out
|
|
|
|
affectedValidator = k.beginUnbondingValidator(ctx, affectedValidator)
|
2018-08-18 04:41:12 -07:00
|
|
|
}
|
2018-07-10 07:23:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
validator = k.bondValidator(ctx, validatorToBond)
|
2018-09-08 01:44:58 -07:00
|
|
|
if bytes.Equal(validator.OperatorAddr, affectedValidator.OperatorAddr) {
|
2018-07-10 15:36:57 -07:00
|
|
|
return validator, true
|
2018-07-10 07:23:31 -07:00
|
|
|
}
|
2018-08-18 04:41:12 -07:00
|
|
|
|
|
|
|
return affectedValidator, true
|
2018-07-10 07:23:31 -07:00
|
|
|
}
|
2018-08-08 15:57:59 -07:00
|
|
|
|
2018-07-10 15:39:52 -07:00
|
|
|
return types.Validator{}, false
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// full update of the bonded validator set, many can be added/kicked
|
|
|
|
func (k Keeper) UpdateBondedValidatorsFull(ctx sdk.Context) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
|
|
|
|
// clear the current validators store, add to the ToKickOut temp store
|
|
|
|
toKickOut := make(map[string]byte)
|
|
|
|
iterator := sdk.KVStorePrefixIterator(store, ValidatorsBondedIndexKey)
|
|
|
|
for ; iterator.Valid(); iterator.Next() {
|
2018-07-02 17:58:22 -07:00
|
|
|
ownerAddr := GetAddressFromValBondedIndexKey(iterator.Key())
|
2018-08-15 11:51:19 -07:00
|
|
|
toKickOut[string(ownerAddr)] = 0
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
2018-08-15 11:51:19 -07:00
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
iterator.Close()
|
|
|
|
|
2018-08-15 11:51:19 -07:00
|
|
|
var validator types.Validator
|
|
|
|
|
2018-07-10 07:23:31 -07:00
|
|
|
oldCliffValidatorAddr := k.GetCliffValidator(ctx)
|
2018-06-26 19:00:12 -07:00
|
|
|
maxValidators := k.GetParams(ctx).MaxValidators
|
|
|
|
bondedValidatorsCount := 0
|
2018-07-10 07:23:31 -07:00
|
|
|
|
2018-08-15 11:51:19 -07:00
|
|
|
iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey)
|
2018-06-26 19:00:12 -07:00
|
|
|
for {
|
|
|
|
if !iterator.Valid() || bondedValidatorsCount > int(maxValidators-1) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
var found bool
|
2018-08-15 11:51:19 -07:00
|
|
|
|
|
|
|
ownerAddr := iterator.Value()
|
2018-06-26 19:00:12 -07:00
|
|
|
validator, found = k.GetValidator(ctx, ownerAddr)
|
2018-09-11 02:12:35 -07:00
|
|
|
ensureValidatorFound(found, ownerAddr)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
_, found = toKickOut[string(ownerAddr)]
|
|
|
|
if found {
|
|
|
|
delete(toKickOut, string(ownerAddr))
|
|
|
|
} else {
|
2018-08-15 11:51:19 -07:00
|
|
|
// If the validator wasn't in the toKickOut group it means it wasn't
|
|
|
|
// previously a validator, therefor update the validator to enter
|
|
|
|
// the validator group.
|
2018-06-26 19:00:12 -07:00
|
|
|
validator = k.bondValidator(ctx, validator)
|
|
|
|
}
|
|
|
|
|
2018-08-22 08:56:13 -07:00
|
|
|
if validator.Jailed {
|
2018-08-15 11:51:19 -07:00
|
|
|
// we should no longer consider jailed validators as they are ranked
|
|
|
|
// lower than any non-jailed/bonded validators
|
2018-07-13 13:46:14 -07:00
|
|
|
if validator.Status == sdk.Bonded {
|
2018-08-22 08:56:13 -07:00
|
|
|
panic(fmt.Sprintf("jailed validator cannot be bonded for address: %s\n", ownerAddr))
|
2018-07-06 17:29:39 -07:00
|
|
|
}
|
2018-08-15 11:51:19 -07:00
|
|
|
|
|
|
|
break
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
2018-07-06 17:29:39 -07:00
|
|
|
|
2018-08-15 11:51:19 -07:00
|
|
|
bondedValidatorsCount++
|
2018-06-26 19:00:12 -07:00
|
|
|
iterator.Next()
|
|
|
|
}
|
2018-08-15 11:51:19 -07:00
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
iterator.Close()
|
|
|
|
|
2018-07-10 07:23:31 -07:00
|
|
|
// clear or set the cliff validator
|
|
|
|
if bondedValidatorsCount == int(maxValidators) {
|
|
|
|
k.setCliffValidator(ctx, validator, k.GetPool(ctx))
|
|
|
|
} else if len(oldCliffValidatorAddr) > 0 {
|
|
|
|
k.clearCliffValidator(ctx)
|
|
|
|
}
|
|
|
|
|
2018-07-09 14:21:29 -07:00
|
|
|
kickOutValidators(k, ctx, toKickOut)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func kickOutValidators(k Keeper, ctx sdk.Context, toKickOut map[string]byte) {
|
2018-06-26 19:00:12 -07:00
|
|
|
for key := range toKickOut {
|
|
|
|
ownerAddr := []byte(key)
|
|
|
|
validator, found := k.GetValidator(ctx, ownerAddr)
|
2018-09-11 02:12:35 -07:00
|
|
|
ensureValidatorFound(found, ownerAddr)
|
2018-08-24 18:47:31 -07:00
|
|
|
k.beginUnbondingValidator(ctx, validator)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// perform all the store operations for when a validator status becomes unbonded
|
2018-08-24 18:47:31 -07:00
|
|
|
func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
pool := k.GetPool(ctx)
|
2018-08-24 18:47:31 -07:00
|
|
|
params := k.GetParams(ctx)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
// sanity check
|
2018-08-24 18:47:31 -07:00
|
|
|
if validator.Status == sdk.Unbonded ||
|
|
|
|
validator.Status == sdk.Unbonding {
|
|
|
|
panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator))
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// set the status
|
2018-08-24 18:47:31 -07:00
|
|
|
validator, pool = validator.UpdateStatus(pool, sdk.Unbonding)
|
2018-06-26 19:00:12 -07:00
|
|
|
k.SetPool(ctx, pool)
|
|
|
|
|
2018-08-24 18:47:31 -07:00
|
|
|
validator.UnbondingMinTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
|
|
|
|
validator.UnbondingHeight = ctx.BlockHeader().Height
|
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
// save the now unbonded validator record
|
2018-07-03 22:32:49 -07:00
|
|
|
k.SetValidator(ctx, validator)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
// add to accumulated changes for tendermint
|
2018-06-29 15:22:24 -07:00
|
|
|
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero())
|
2018-09-12 21:53:55 -07:00
|
|
|
tstore := ctx.TransientStore(k.storeTKey)
|
|
|
|
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
// also remove from the Bonded types.Validators Store
|
2018-09-08 01:44:58 -07:00
|
|
|
store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr))
|
2018-08-31 17:01:23 -07:00
|
|
|
|
|
|
|
// call the unbond hook if present
|
|
|
|
if k.validatorHooks != nil {
|
|
|
|
k.validatorHooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())
|
|
|
|
}
|
|
|
|
|
|
|
|
// return updated validator
|
2018-06-26 19:00:12 -07:00
|
|
|
return validator
|
|
|
|
}
|
|
|
|
|
|
|
|
// perform all the store operations for when a validator status becomes bonded
|
|
|
|
func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
|
|
|
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
pool := k.GetPool(ctx)
|
|
|
|
|
|
|
|
// sanity check
|
2018-07-13 13:46:14 -07:00
|
|
|
if validator.Status == sdk.Bonded {
|
2018-06-26 19:00:12 -07:00
|
|
|
panic(fmt.Sprintf("should not already be bonded, validator: %v\n", validator))
|
|
|
|
}
|
|
|
|
|
2018-09-12 00:16:28 -07:00
|
|
|
validator.BondHeight = ctx.BlockHeight()
|
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
// set the status
|
|
|
|
validator, pool = validator.UpdateStatus(pool, sdk.Bonded)
|
|
|
|
k.SetPool(ctx, pool)
|
|
|
|
|
|
|
|
// save the now bonded validator record to the three referenced stores
|
2018-07-03 22:32:49 -07:00
|
|
|
k.SetValidator(ctx, validator)
|
2018-09-08 01:44:58 -07:00
|
|
|
store.Set(GetValidatorsBondedIndexKey(validator.OperatorAddr), []byte{})
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
// add to accumulated changes for tendermint
|
2018-06-29 15:22:24 -07:00
|
|
|
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
2018-09-12 21:53:55 -07:00
|
|
|
tstore := ctx.TransientStore(k.storeTKey)
|
|
|
|
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI)
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-08-31 17:01:23 -07:00
|
|
|
// call the bond hook if present
|
|
|
|
if k.validatorHooks != nil {
|
|
|
|
k.validatorHooks.OnValidatorBonded(ctx, validator.ConsAddress())
|
|
|
|
}
|
|
|
|
|
|
|
|
// return updated validator
|
2018-06-26 19:00:12 -07:00
|
|
|
return validator
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove the validator record and associated indexes
|
2018-08-30 21:06:44 -07:00
|
|
|
func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) {
|
2018-06-26 19:00:12 -07:00
|
|
|
|
|
|
|
// first retrieve the old validator record
|
|
|
|
validator, found := k.GetValidator(ctx, address)
|
|
|
|
if !found {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete the old validator record
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
pool := k.GetPool(ctx)
|
|
|
|
store.Delete(GetValidatorKey(address))
|
2018-09-08 01:44:58 -07:00
|
|
|
store.Delete(GetValidatorByPubKeyIndexKey(validator.ConsPubKey))
|
2018-06-26 19:00:12 -07:00
|
|
|
store.Delete(GetValidatorsByPowerIndexKey(validator, pool))
|
|
|
|
|
|
|
|
// delete from the current and power weighted validator groups if the validator
|
|
|
|
// is bonded - and add validator with zero power to the validator updates
|
2018-09-08 01:44:58 -07:00
|
|
|
if store.Get(GetValidatorsBondedIndexKey(validator.OperatorAddr)) == nil {
|
2018-06-26 19:00:12 -07:00
|
|
|
return
|
|
|
|
}
|
2018-09-08 01:44:58 -07:00
|
|
|
store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr))
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-06-29 15:22:24 -07:00
|
|
|
bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero())
|
2018-09-12 21:53:55 -07:00
|
|
|
tstore := ctx.TransientStore(k.storeTKey)
|
|
|
|
tstore.Set(GetTendermintUpdatesTKey(address), bz)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
//__________________________________________________________________________
|
|
|
|
|
|
|
|
// get the current validator on the cliff
|
2018-07-03 15:08:37 -07:00
|
|
|
func (k Keeper) GetCliffValidator(ctx sdk.Context) []byte {
|
2018-06-26 19:00:12 -07:00
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
return store.Get(ValidatorCliffIndexKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the current power of the validator on the cliff
|
2018-07-03 15:08:37 -07:00
|
|
|
func (k Keeper) GetCliffValidatorPower(ctx sdk.Context) []byte {
|
2018-06-26 19:00:12 -07:00
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
return store.Get(ValidatorPowerCliffKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the current validator and power of the validator on the cliff
|
|
|
|
func (k Keeper) setCliffValidator(ctx sdk.Context, validator types.Validator, pool types.Pool) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
bz := GetValidatorsByPowerIndexKey(validator, pool)
|
|
|
|
store.Set(ValidatorPowerCliffKey, bz)
|
2018-09-08 01:44:58 -07:00
|
|
|
store.Set(ValidatorCliffIndexKey, validator.OperatorAddr)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// clear the current validator and power of the validator on the cliff
|
|
|
|
func (k Keeper) clearCliffValidator(ctx sdk.Context) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
store.Delete(ValidatorPowerCliffKey)
|
|
|
|
store.Delete(ValidatorCliffIndexKey)
|
|
|
|
}
|
2018-09-11 02:12:35 -07:00
|
|
|
|
|
|
|
func ensureValidatorFound(found bool, ownerAddr []byte) {
|
|
|
|
if !found {
|
|
|
|
panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr))
|
|
|
|
}
|
|
|
|
}
|