2018-06-26 19:00:12 -07:00
|
|
|
package keeper
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"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"
|
|
|
|
)
|
|
|
|
|
|
|
|
// get a single validator
|
|
|
|
func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.Address) (validator types.Validator, found bool) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
b := store.Get(GetValidatorKey(addr))
|
|
|
|
if b == nil {
|
|
|
|
return validator, false
|
|
|
|
}
|
|
|
|
k.cdc.MustUnmarshalBinary(b, &validator)
|
|
|
|
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)
|
|
|
|
// set main store
|
|
|
|
bz := k.cdc.MustMarshalBinary(validator)
|
|
|
|
store.Set(GetValidatorKey(validator.Owner), bz)
|
|
|
|
}
|
|
|
|
|
|
|
|
// validator index
|
|
|
|
func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
// set pointer by pubkey
|
|
|
|
store.Set(GetValidatorByPubKeyIndexKey(validator.PubKey), validator.Owner)
|
|
|
|
}
|
|
|
|
|
|
|
|
// validator index
|
|
|
|
func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Validator, pool types.Pool) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
store.Set(GetValidatorsByPowerIndexKey(validator, pool), validator.Owner)
|
|
|
|
}
|
|
|
|
|
|
|
|
// validator index
|
|
|
|
func (k Keeper) SetValidatorBondedIndex(ctx sdk.Context, validator types.Validator) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
2018-07-02 17:58:22 -07:00
|
|
|
store.Set(GetValidatorsBondedIndexKey(validator.Owner), []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
|
|
|
|
}
|
|
|
|
bz := iterator.Value()
|
|
|
|
var validator types.Validator
|
|
|
|
k.cdc.MustUnmarshalBinary(bz, &validator)
|
|
|
|
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
|
|
|
|
}
|
|
|
|
bz := iterator.Value()
|
|
|
|
var validator types.Validator
|
|
|
|
k.cdc.MustUnmarshalBinary(bz, &validator)
|
|
|
|
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)
|
|
|
|
if !found {
|
|
|
|
panic(fmt.Sprintf("validator record not found for address: %v\n", address))
|
|
|
|
}
|
|
|
|
|
|
|
|
validators[i] = validator
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
iterator.Close()
|
|
|
|
return validators[:i] // trim
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the group of bonded validators sorted by power-rank
|
|
|
|
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)
|
|
|
|
if !found {
|
|
|
|
panic(fmt.Sprintf("validator record not found for address: %v\n", address))
|
|
|
|
}
|
|
|
|
if validator.Status() == sdk.Bonded {
|
|
|
|
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
|
|
|
|
func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
|
|
|
|
iterator := sdk.KVStorePrefixIterator(store, TendermintUpdatesKey) //smallest to largest
|
|
|
|
for ; iterator.Valid(); iterator.Next() {
|
|
|
|
valBytes := iterator.Value()
|
|
|
|
var val abci.Validator
|
|
|
|
k.cdc.MustUnmarshalBinary(valBytes, &val)
|
|
|
|
updates = append(updates, val)
|
|
|
|
}
|
|
|
|
iterator.Close()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove all validator update entries after applied to Tendermint
|
|
|
|
func (k Keeper) ClearTendermintUpdates(ctx sdk.Context) {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
|
|
|
|
// delete subspace
|
|
|
|
iterator := sdk.KVStorePrefixIterator(store, TendermintUpdatesKey)
|
|
|
|
for ; iterator.Valid(); iterator.Next() {
|
|
|
|
store.Delete(iterator.Key())
|
|
|
|
}
|
|
|
|
iterator.Close()
|
|
|
|
}
|
|
|
|
|
|
|
|
//___________________________________________________________________________
|
|
|
|
|
|
|
|
// perfom all the nessisary steps for when a validator changes its power
|
|
|
|
// updates all validator stores as well as tendermint update store
|
|
|
|
// may kick out validators if new validator is entering the bonded validator group
|
|
|
|
func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
pool := k.GetPool(ctx)
|
|
|
|
ownerAddr := validator.Owner
|
|
|
|
|
|
|
|
// always update the main list ordered by owner address before exiting
|
|
|
|
defer func() {
|
|
|
|
bz := k.cdc.MustMarshalBinary(validator)
|
|
|
|
store.Set(GetValidatorKey(ownerAddr), bz)
|
|
|
|
}()
|
|
|
|
|
|
|
|
// retrieve the old validator record
|
|
|
|
oldValidator, oldFound := k.GetValidator(ctx, ownerAddr)
|
|
|
|
|
|
|
|
if validator.Revoked && oldValidator.Status() == sdk.Bonded {
|
|
|
|
validator = k.unbondValidator(ctx, validator)
|
|
|
|
|
|
|
|
// need to also clear the cliff validator spot because the revoke has
|
|
|
|
// opened up a new spot which will be filled when
|
|
|
|
// updateValidatorsBonded is called
|
|
|
|
k.clearCliffValidator(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
powerIncreasing := false
|
|
|
|
if oldFound && oldValidator.PoolShares.Bonded().LT(validator.PoolShares.Bonded()) {
|
|
|
|
powerIncreasing = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// if already a validator, copy the old block height and counter, else set them
|
|
|
|
if oldFound && oldValidator.Status() == sdk.Bonded {
|
|
|
|
validator.BondHeight = oldValidator.BondHeight
|
|
|
|
validator.BondIntraTxCounter = oldValidator.BondIntraTxCounter
|
|
|
|
} else {
|
|
|
|
validator.BondHeight = ctx.BlockHeight()
|
|
|
|
counter := k.GetIntraTxCounter(ctx)
|
|
|
|
validator.BondIntraTxCounter = counter
|
|
|
|
k.SetIntraTxCounter(ctx, counter+1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// update the list ordered by voting power
|
|
|
|
if oldFound {
|
|
|
|
store.Delete(GetValidatorsByPowerIndexKey(oldValidator, pool))
|
|
|
|
}
|
|
|
|
valPower := GetValidatorsByPowerIndexKey(validator, pool)
|
|
|
|
store.Set(valPower, validator.Owner)
|
|
|
|
|
|
|
|
// efficiency case:
|
|
|
|
// if already bonded and power increasing only need to update tendermint
|
|
|
|
if powerIncreasing && !validator.Revoked && oldValidator.Status() == sdk.Bonded {
|
2018-06-29 15:22:24 -07:00
|
|
|
bz := k.cdc.MustMarshalBinary(validator.ABCIValidator())
|
2018-06-26 19:00:12 -07:00
|
|
|
store.Set(GetTendermintUpdatesKey(ownerAddr), bz)
|
|
|
|
return validator
|
|
|
|
}
|
|
|
|
|
|
|
|
// efficiency case:
|
|
|
|
// if was unbonded/or is a new validator - and the new power is less than the cliff validator
|
|
|
|
cliffPower := k.getCliffValidatorPower(ctx)
|
|
|
|
if cliffPower != nil &&
|
|
|
|
(!oldFound || (oldFound && oldValidator.Status() == sdk.Unbonded)) &&
|
|
|
|
bytes.Compare(valPower, cliffPower) == -1 { //(valPower < cliffPower
|
|
|
|
return validator
|
|
|
|
}
|
|
|
|
|
|
|
|
// update the validator set for this validator
|
|
|
|
updatedVal := k.UpdateBondedValidators(ctx, validator)
|
|
|
|
if updatedVal.Owner != nil { // updates to validator occurred to be updated
|
|
|
|
validator = updatedVal
|
|
|
|
}
|
|
|
|
return validator
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the validator group and kick out any old validators. In addition this
|
|
|
|
// function adds (or doesn't add) a validator which has updated its bonded
|
|
|
|
// tokens to the validator group. -> this validator is specified through the
|
|
|
|
// updatedValidatorAddr term.
|
|
|
|
//
|
|
|
|
// The correct subset 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 the subspace as we do in
|
|
|
|
// GetValidators.
|
|
|
|
//
|
|
|
|
// Optionally also return the validator from a retrieve address if the validator has been bonded
|
|
|
|
func (k Keeper) UpdateBondedValidators(ctx sdk.Context,
|
|
|
|
newValidator types.Validator) (updatedVal types.Validator) {
|
|
|
|
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
|
|
|
|
kickCliffValidator := false
|
|
|
|
oldCliffValidatorAddr := k.getCliffValidator(ctx)
|
|
|
|
|
|
|
|
// add the actual validator power sorted store
|
|
|
|
maxValidators := k.GetParams(ctx).MaxValidators
|
|
|
|
iterator := sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) // largest to smallest
|
|
|
|
bondedValidatorsCount := 0
|
|
|
|
var validator types.Validator
|
|
|
|
for {
|
|
|
|
if !iterator.Valid() || bondedValidatorsCount > int(maxValidators-1) {
|
|
|
|
|
|
|
|
// TODO benchmark if we should read the current power and not write if it's the same
|
|
|
|
if bondedValidatorsCount == int(maxValidators) { // is cliff validator
|
|
|
|
k.setCliffValidator(ctx, validator, k.GetPool(ctx))
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// either retrieve the original validator from the store, or under the
|
|
|
|
// situation that this is the "new validator" just use the validator
|
|
|
|
// provided because it has not yet been updated in the main validator
|
|
|
|
// store
|
|
|
|
ownerAddr := iterator.Value()
|
|
|
|
if bytes.Equal(ownerAddr, newValidator.Owner) {
|
|
|
|
validator = newValidator
|
|
|
|
} else {
|
|
|
|
var found bool
|
|
|
|
validator, found = k.GetValidator(ctx, ownerAddr)
|
|
|
|
if !found {
|
|
|
|
panic(fmt.Sprintf("validator record not found for address: %v\n", ownerAddr))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// if not previously a validator (and unrevoked),
|
|
|
|
// kick the cliff validator / bond this new validator
|
|
|
|
if validator.Status() != sdk.Bonded && !validator.Revoked {
|
|
|
|
kickCliffValidator = true
|
|
|
|
|
|
|
|
validator = k.bondValidator(ctx, validator)
|
|
|
|
if bytes.Equal(ownerAddr, newValidator.Owner) {
|
|
|
|
updatedVal = validator
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if validator.Revoked && validator.Status() == sdk.Bonded {
|
|
|
|
panic(fmt.Sprintf("revoked validator cannot be bonded, address: %v\n", ownerAddr))
|
|
|
|
} else {
|
|
|
|
bondedValidatorsCount++
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator.Next()
|
|
|
|
}
|
|
|
|
iterator.Close()
|
|
|
|
|
|
|
|
// perform the actual kicks
|
|
|
|
if oldCliffValidatorAddr != nil && kickCliffValidator {
|
|
|
|
validator, found := k.GetValidator(ctx, oldCliffValidatorAddr)
|
|
|
|
if !found {
|
|
|
|
panic(fmt.Sprintf("validator record not found for address: %v\n", oldCliffValidatorAddr))
|
|
|
|
}
|
|
|
|
k.unbondValidator(ctx, validator)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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-06-26 19:00:12 -07:00
|
|
|
toKickOut[string(ownerAddr)] = 0 // set anything
|
|
|
|
}
|
|
|
|
iterator.Close()
|
|
|
|
|
|
|
|
// add the actual validator power sorted store
|
|
|
|
maxValidators := k.GetParams(ctx).MaxValidators
|
|
|
|
iterator = sdk.KVStoreReversePrefixIterator(store, ValidatorsByPowerIndexKey) // largest to smallest
|
|
|
|
bondedValidatorsCount := 0
|
|
|
|
var validator types.Validator
|
|
|
|
for {
|
|
|
|
if !iterator.Valid() || bondedValidatorsCount > int(maxValidators-1) {
|
|
|
|
|
|
|
|
if bondedValidatorsCount == int(maxValidators) { // is cliff validator
|
|
|
|
k.setCliffValidator(ctx, validator, k.GetPool(ctx))
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
// either retrieve the original validator from the store,
|
|
|
|
// or under the situation that this is the "new validator" just
|
|
|
|
// use the validator provided because it has not yet been updated
|
|
|
|
// in the main validator store
|
|
|
|
ownerAddr := iterator.Value()
|
|
|
|
var found bool
|
|
|
|
validator, found = k.GetValidator(ctx, ownerAddr)
|
|
|
|
if !found {
|
|
|
|
panic(fmt.Sprintf("validator record not found for address: %v\n", ownerAddr))
|
|
|
|
}
|
|
|
|
|
|
|
|
_, found = toKickOut[string(ownerAddr)]
|
|
|
|
if found {
|
|
|
|
delete(toKickOut, string(ownerAddr))
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// if it wasn't in the toKickOut group it means
|
|
|
|
// this wasn't a previously a validator, therefor
|
|
|
|
// update the validator to enter the validator group
|
|
|
|
validator = k.bondValidator(ctx, validator)
|
|
|
|
}
|
|
|
|
|
|
|
|
if validator.Revoked && validator.Status() == sdk.Bonded {
|
|
|
|
panic(fmt.Sprintf("revoked validator cannot be bonded, address: %v\n", ownerAddr))
|
|
|
|
} else {
|
|
|
|
bondedValidatorsCount++
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator.Next()
|
|
|
|
}
|
|
|
|
iterator.Close()
|
|
|
|
|
|
|
|
// perform the actual kicks
|
|
|
|
for key := range toKickOut {
|
|
|
|
ownerAddr := []byte(key)
|
|
|
|
validator, found := k.GetValidator(ctx, ownerAddr)
|
|
|
|
if !found {
|
|
|
|
panic(fmt.Sprintf("validator record not found for address: %v\n", ownerAddr))
|
|
|
|
}
|
|
|
|
k.unbondValidator(ctx, validator)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// perform all the store operations for when a validator status becomes unbonded
|
|
|
|
func (k Keeper) unbondValidator(ctx sdk.Context, validator types.Validator) types.Validator {
|
|
|
|
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
pool := k.GetPool(ctx)
|
|
|
|
|
|
|
|
// sanity check
|
|
|
|
if validator.Status() == sdk.Unbonded {
|
|
|
|
panic(fmt.Sprintf("should not already be unbonded, validator: %v\n", validator))
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the status
|
|
|
|
validator, pool = validator.UpdateStatus(pool, sdk.Unbonded)
|
|
|
|
k.SetPool(ctx, pool)
|
|
|
|
|
|
|
|
// save the now unbonded validator record
|
|
|
|
bzVal := k.cdc.MustMarshalBinary(validator)
|
|
|
|
store.Set(GetValidatorKey(validator.Owner), bzVal)
|
|
|
|
|
|
|
|
// add to accumulated changes for tendermint
|
2018-06-29 15:22:24 -07:00
|
|
|
bzABCI := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero())
|
2018-06-26 19:00:12 -07:00
|
|
|
store.Set(GetTendermintUpdatesKey(validator.Owner), bzABCI)
|
|
|
|
|
|
|
|
// also remove from the Bonded types.Validators Store
|
|
|
|
store.Delete(GetValidatorsBondedIndexKey(validator.Owner))
|
|
|
|
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
|
|
|
|
if validator.Status() == sdk.Bonded {
|
|
|
|
panic(fmt.Sprintf("should not already be bonded, validator: %v\n", validator))
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
bzVal := k.cdc.MustMarshalBinary(validator)
|
|
|
|
store.Set(GetValidatorKey(validator.Owner), bzVal)
|
2018-07-02 17:58:22 -07:00
|
|
|
store.Set(GetValidatorsBondedIndexKey(validator.Owner), []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-06-26 19:00:12 -07:00
|
|
|
store.Set(GetTendermintUpdatesKey(validator.Owner), bzABCI)
|
|
|
|
|
|
|
|
return validator
|
|
|
|
}
|
|
|
|
|
|
|
|
// remove the validator record and associated indexes
|
|
|
|
func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.Address) {
|
|
|
|
|
|
|
|
// 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))
|
|
|
|
store.Delete(GetValidatorByPubKeyIndexKey(validator.PubKey))
|
|
|
|
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
|
|
|
|
if store.Get(GetValidatorsBondedIndexKey(validator.Owner)) == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
store.Delete(GetValidatorsBondedIndexKey(validator.Owner))
|
|
|
|
|
2018-06-29 15:22:24 -07:00
|
|
|
bz := k.cdc.MustMarshalBinary(validator.ABCIValidatorZero())
|
2018-06-26 19:00:12 -07:00
|
|
|
store.Set(GetTendermintUpdatesKey(address), bz)
|
|
|
|
}
|
|
|
|
|
|
|
|
//__________________________________________________________________________
|
|
|
|
|
|
|
|
// get the current validator on the cliff
|
|
|
|
func (k Keeper) getCliffValidator(ctx sdk.Context) []byte {
|
|
|
|
store := ctx.KVStore(k.storeKey)
|
|
|
|
return store.Get(ValidatorCliffIndexKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the current power of the validator on the cliff
|
|
|
|
func (k Keeper) getCliffValidatorPower(ctx sdk.Context) []byte {
|
|
|
|
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)
|
|
|
|
store.Set(ValidatorCliffIndexKey, validator.Owner)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|