611 lines
19 KiB
Go
611 lines
19 KiB
Go
package keeper
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"time"
|
|
|
|
gogotypes "github.com/cosmos/gogoproto/types"
|
|
|
|
"cosmossdk.io/collections"
|
|
corestore "cosmossdk.io/core/store"
|
|
errorsmod "cosmossdk.io/errors"
|
|
"cosmossdk.io/math"
|
|
storetypes "cosmossdk.io/store/types"
|
|
"cosmossdk.io/x/staking/types"
|
|
|
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
)
|
|
|
|
var timeBzKeySize = uint64(29) // time bytes key size is 29 by default
|
|
|
|
// GetValidator gets a single validator
|
|
func (k Keeper) GetValidator(ctx context.Context, addr sdk.ValAddress) (validator types.Validator, err error) {
|
|
validator, err = k.Validators.Get(ctx, addr)
|
|
if err != nil {
|
|
if errors.Is(err, collections.ErrNotFound) {
|
|
return types.Validator{}, types.ErrNoValidatorFound
|
|
}
|
|
return validator, err
|
|
}
|
|
return validator, nil
|
|
}
|
|
|
|
// GetValidatorByConsAddr gets a single validator by consensus address
|
|
func (k Keeper) GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (validator types.Validator, err error) {
|
|
opAddr, err := k.ValidatorByConsensusAddress.Get(ctx, consAddr)
|
|
if err != nil {
|
|
// if the validator not found try to find it in the map of `OldToNewConsAddrMap` because validator may've rotated it's key.
|
|
if !errors.Is(err, collections.ErrNotFound) {
|
|
return types.Validator{}, err
|
|
}
|
|
|
|
newConsAddr, err := k.OldToNewConsAddrMap.Get(ctx, consAddr.Bytes())
|
|
if err != nil {
|
|
if errors.Is(err, collections.ErrNotFound) {
|
|
return types.Validator{}, types.ErrNoValidatorFound
|
|
}
|
|
return types.Validator{}, err
|
|
}
|
|
|
|
operatorAddr, err := k.ValidatorByConsensusAddress.Get(ctx, newConsAddr)
|
|
if err != nil {
|
|
if errors.Is(err, collections.ErrNotFound) {
|
|
return types.Validator{}, types.ErrNoValidatorFound
|
|
}
|
|
return types.Validator{}, err
|
|
}
|
|
|
|
opAddr = operatorAddr
|
|
}
|
|
|
|
if opAddr == nil {
|
|
return types.Validator{}, types.ErrNoValidatorFound
|
|
}
|
|
|
|
return k.GetValidator(ctx, opAddr)
|
|
}
|
|
|
|
// SetValidator sets the main record holding validator details
|
|
func (k Keeper) SetValidator(ctx context.Context, validator types.Validator) error {
|
|
valBz, err := k.ValidatorAddressCodec().StringToBytes(validator.GetOperator())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return k.Validators.Set(ctx, sdk.ValAddress(valBz), validator)
|
|
}
|
|
|
|
// SetValidatorByConsAddr sets a validator by conesensus address
|
|
func (k Keeper) SetValidatorByConsAddr(ctx context.Context, validator types.Validator) error {
|
|
consPk, err := validator.GetConsAddr()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
bz, err := k.validatorAddressCodec.StringToBytes(validator.GetOperator())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return k.ValidatorByConsensusAddress.Set(ctx, consPk, bz)
|
|
}
|
|
|
|
// SetValidatorByPowerIndex sets a validator by power index
|
|
func (k Keeper) SetValidatorByPowerIndex(ctx context.Context, validator types.Validator) error {
|
|
// jailed validators are not kept in the power index
|
|
if validator.Jailed {
|
|
return nil
|
|
}
|
|
|
|
store := k.KVStoreService.OpenKVStore(ctx)
|
|
str, err := k.validatorAddressCodec.StringToBytes(validator.GetOperator())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return store.Set(types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx), k.validatorAddressCodec), str)
|
|
}
|
|
|
|
// DeleteValidatorByPowerIndex deletes a record by power index
|
|
func (k Keeper) DeleteValidatorByPowerIndex(ctx context.Context, validator types.Validator) error {
|
|
store := k.KVStoreService.OpenKVStore(ctx)
|
|
return store.Delete(types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx), k.validatorAddressCodec))
|
|
}
|
|
|
|
// SetNewValidatorByPowerIndex adds new entry by power index
|
|
func (k Keeper) SetNewValidatorByPowerIndex(ctx context.Context, validator types.Validator) error {
|
|
store := k.KVStoreService.OpenKVStore(ctx)
|
|
str, err := k.validatorAddressCodec.StringToBytes(validator.GetOperator())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return store.Set(types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx), k.validatorAddressCodec), str)
|
|
}
|
|
|
|
// AddValidatorTokensAndShares updates the tokens of an existing validator, updates the validators power index key
|
|
func (k Keeper) AddValidatorTokensAndShares(ctx context.Context, validator types.Validator,
|
|
tokensToAdd math.Int,
|
|
) (valOut types.Validator, addedShares math.LegacyDec, err error) {
|
|
err = k.DeleteValidatorByPowerIndex(ctx, validator)
|
|
if err != nil {
|
|
return valOut, addedShares, err
|
|
}
|
|
|
|
validator, addedShares = validator.AddTokensFromDel(tokensToAdd)
|
|
err = k.SetValidator(ctx, validator)
|
|
if err != nil {
|
|
return validator, addedShares, err
|
|
}
|
|
|
|
err = k.SetValidatorByPowerIndex(ctx, validator)
|
|
return validator, addedShares, err
|
|
}
|
|
|
|
// RemoveValidatorTokensAndShares updates the tokens of an existing validator, updates the validators power index key
|
|
func (k Keeper) RemoveValidatorTokensAndShares(ctx context.Context, validator types.Validator,
|
|
sharesToRemove math.LegacyDec,
|
|
) (valOut types.Validator, removedTokens math.Int, err error) {
|
|
err = k.DeleteValidatorByPowerIndex(ctx, validator)
|
|
if err != nil {
|
|
return valOut, removedTokens, err
|
|
}
|
|
validator, removedTokens = validator.RemoveDelShares(sharesToRemove)
|
|
err = k.SetValidator(ctx, validator)
|
|
if err != nil {
|
|
return validator, removedTokens, err
|
|
}
|
|
|
|
err = k.SetValidatorByPowerIndex(ctx, validator)
|
|
return validator, removedTokens, err
|
|
}
|
|
|
|
// RemoveValidatorTokens updates the tokens of an existing validator, updates the validators power index key
|
|
func (k Keeper) RemoveValidatorTokens(ctx context.Context,
|
|
validator types.Validator, tokensToRemove math.Int,
|
|
) (types.Validator, error) {
|
|
if err := k.DeleteValidatorByPowerIndex(ctx, validator); err != nil {
|
|
return validator, err
|
|
}
|
|
|
|
validator = validator.RemoveTokens(tokensToRemove)
|
|
if err := k.SetValidator(ctx, validator); err != nil {
|
|
return validator, err
|
|
}
|
|
|
|
if err := k.SetValidatorByPowerIndex(ctx, validator); err != nil {
|
|
return validator, err
|
|
}
|
|
|
|
return validator, nil
|
|
}
|
|
|
|
// UpdateValidatorCommission attempts to update a validator's commission rate.
|
|
// An error is returned if the new commission rate is invalid.
|
|
func (k Keeper) UpdateValidatorCommission(ctx context.Context,
|
|
validator types.Validator, newRate math.LegacyDec,
|
|
) (types.Commission, error) {
|
|
commission := validator.Commission
|
|
blockTime := k.HeaderService.HeaderInfo(ctx).Time
|
|
|
|
if err := commission.ValidateNewRate(newRate, blockTime); err != nil {
|
|
return commission, err
|
|
}
|
|
|
|
minCommissionRate, err := k.MinCommissionRate(ctx)
|
|
if err != nil {
|
|
return commission, err
|
|
}
|
|
|
|
if newRate.LT(minCommissionRate) {
|
|
return commission, fmt.Errorf("cannot set validator commission to less than minimum rate of %s", minCommissionRate)
|
|
}
|
|
|
|
commission.Rate = newRate
|
|
commission.UpdateTime = blockTime
|
|
|
|
return commission, nil
|
|
}
|
|
|
|
// RemoveValidator removes the validator record and associated indexes
|
|
// except for the bonded validator index which is only handled in ApplyAndReturnTendermintUpdates
|
|
func (k Keeper) RemoveValidator(ctx context.Context, address sdk.ValAddress) error {
|
|
// first retrieve the old validator record
|
|
validator, err := k.GetValidator(ctx, address)
|
|
if errors.Is(err, types.ErrNoValidatorFound) {
|
|
return nil
|
|
}
|
|
|
|
if !validator.IsUnbonded() {
|
|
return types.ErrBadRemoveValidator.Wrap("cannot call RemoveValidator on bonded or unbonding validators")
|
|
}
|
|
|
|
if validator.Tokens.IsPositive() {
|
|
return types.ErrBadRemoveValidator.Wrap("attempting to remove a validator which still contains tokens")
|
|
}
|
|
|
|
valConsAddr, err := validator.GetConsAddr()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// delete the old validator record
|
|
store := k.KVStoreService.OpenKVStore(ctx)
|
|
if err = k.Validators.Remove(ctx, address); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = k.ValidatorByConsensusAddress.Remove(ctx, valConsAddr); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err = store.Delete(types.GetValidatorsByPowerIndexKey(validator, k.PowerReduction(ctx), k.validatorAddressCodec)); err != nil {
|
|
return err
|
|
}
|
|
|
|
str, err := k.validatorAddressCodec.StringToBytes(validator.GetOperator())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := k.Hooks().AfterValidatorRemoved(ctx, valConsAddr, str); err != nil {
|
|
return fmt.Errorf("error in after validator removed hook: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// get groups of validators
|
|
|
|
// GetAllValidators gets the set of all validators with no limits, used during genesis dump
|
|
func (k Keeper) GetAllValidators(ctx context.Context) (validators []types.Validator, err error) {
|
|
store := k.KVStoreService.OpenKVStore(ctx)
|
|
|
|
iterator, err := store.Iterator(types.ValidatorsKey, storetypes.PrefixEndBytes(types.ValidatorsKey))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer iterator.Close()
|
|
|
|
for ; iterator.Valid(); iterator.Next() {
|
|
validator, err := types.UnmarshalValidator(k.cdc, iterator.Value())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
validators = append(validators, validator)
|
|
}
|
|
|
|
return validators, nil
|
|
}
|
|
|
|
// GetValidators returns a given amount of all the validators
|
|
func (k Keeper) GetValidators(ctx context.Context, maxRetrieve uint32) (validators []types.Validator, err error) {
|
|
store := k.KVStoreService.OpenKVStore(ctx)
|
|
validators = make([]types.Validator, maxRetrieve)
|
|
|
|
iterator, err := store.Iterator(types.ValidatorsKey, storetypes.PrefixEndBytes(types.ValidatorsKey))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
i := 0
|
|
for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() {
|
|
validator, err := types.UnmarshalValidator(k.cdc, iterator.Value())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
validators[i] = validator
|
|
i++
|
|
}
|
|
|
|
return validators[:i], nil // trim if the array length < maxRetrieve
|
|
}
|
|
|
|
// GetBondedValidatorsByPower gets the current group of bonded validators sorted by power-rank
|
|
func (k Keeper) GetBondedValidatorsByPower(ctx context.Context) ([]types.Validator, error) {
|
|
maxValidators, err := k.MaxValidators(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
validators := make([]types.Validator, maxValidators)
|
|
|
|
iterator, err := k.ValidatorsPowerStoreIterator(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer iterator.Close()
|
|
|
|
i := 0
|
|
for ; iterator.Valid() && i < int(maxValidators); iterator.Next() {
|
|
address := iterator.Value()
|
|
validator, err := k.GetValidator(ctx, address)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("validator record not found for address: %X", address)
|
|
}
|
|
|
|
if validator.IsBonded() {
|
|
validators[i] = validator
|
|
i++
|
|
}
|
|
}
|
|
|
|
return validators[:i], nil // trim
|
|
}
|
|
|
|
// ValidatorsPowerStoreIterator returns an iterator for the current validator power store
|
|
func (k Keeper) ValidatorsPowerStoreIterator(ctx context.Context) (corestore.Iterator, error) {
|
|
store := k.KVStoreService.OpenKVStore(ctx)
|
|
return store.ReverseIterator(types.ValidatorsByPowerIndexKey, storetypes.PrefixEndBytes(types.ValidatorsByPowerIndexKey))
|
|
}
|
|
|
|
// Last Validator Index
|
|
|
|
// GetLastValidatorPower loads the last validator power.
|
|
// Returns zero if the operator was not a validator last block.
|
|
func (k Keeper) GetLastValidatorPower(ctx context.Context, operator sdk.ValAddress) (power int64, err error) {
|
|
intV, err := k.LastValidatorPower.Get(ctx, operator)
|
|
return intV.GetValue(), err
|
|
}
|
|
|
|
// SetLastValidatorPower sets the last validator power.
|
|
func (k Keeper) SetLastValidatorPower(ctx context.Context, operator sdk.ValAddress, power int64) error {
|
|
return k.LastValidatorPower.Set(ctx, operator, gogotypes.Int64Value{Value: power})
|
|
}
|
|
|
|
// DeleteLastValidatorPower deletes the last validator power.
|
|
func (k Keeper) DeleteLastValidatorPower(ctx context.Context, operator sdk.ValAddress) error {
|
|
return k.LastValidatorPower.Remove(ctx, operator)
|
|
}
|
|
|
|
// IterateLastValidatorPowers iterates over last validator powers.
|
|
func (k Keeper) IterateLastValidatorPowers(ctx context.Context, handler func(operator sdk.ValAddress, power int64) (stop bool)) error {
|
|
err := k.LastValidatorPower.Walk(ctx, nil, func(key []byte, value gogotypes.Int64Value) (bool, error) {
|
|
addr := sdk.ValAddress(key)
|
|
|
|
if handler(addr, value.GetValue()) {
|
|
return true, nil
|
|
}
|
|
return false, nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetLastValidators gets the group of the bonded validators
|
|
func (k Keeper) GetLastValidators(ctx context.Context) (validators []types.Validator, err error) {
|
|
// add the actual validator power sorted store
|
|
maxValidators, err := k.MaxValidators(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
i := 0
|
|
validators = make([]types.Validator, maxValidators)
|
|
|
|
err = k.LastValidatorPower.Walk(ctx, nil, func(key []byte, _ gogotypes.Int64Value) (bool, error) {
|
|
// Note, we do NOT error here as the MaxValidators param may change via on-chain
|
|
// governance. In cases where the param is increased, this case should never
|
|
// be hit. In cases where the param is decreased, we will simply not return
|
|
// the remainder of the validator set, as the ApplyAndReturnValidatorSetUpdates
|
|
// call should ensure the validators past the cliff will be moved to the
|
|
// unbonding set.
|
|
if i >= int(maxValidators) {
|
|
return true, nil
|
|
}
|
|
|
|
validator, err := k.GetValidator(ctx, key)
|
|
if err != nil {
|
|
return true, err
|
|
}
|
|
|
|
validators[i] = validator
|
|
i++
|
|
|
|
return false, nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return validators[:i], nil // trim
|
|
}
|
|
|
|
// GetUnbondingValidators returns a slice of mature validator addresses that
|
|
// complete their unbonding at a given time and height.
|
|
func (k Keeper) GetUnbondingValidators(ctx context.Context, endTime time.Time, endHeight int64) ([]string, error) {
|
|
timeSize := sdk.TimeKey.Size(endTime)
|
|
valAddrs, err := k.ValidatorQueue.Get(ctx, collections.Join3(uint64(timeSize), endTime, uint64(endHeight)))
|
|
if err != nil && !errors.Is(err, collections.ErrNotFound) {
|
|
return []string{}, err
|
|
}
|
|
|
|
return valAddrs.Addresses, nil
|
|
}
|
|
|
|
// SetUnbondingValidatorsQueue sets a given slice of validator addresses into
|
|
// the unbonding validator queue by a given height and time.
|
|
func (k Keeper) SetUnbondingValidatorsQueue(ctx context.Context, endTime time.Time, endHeight int64, addrs []string) error {
|
|
valAddrs := types.ValAddresses{Addresses: addrs}
|
|
return k.ValidatorQueue.Set(ctx, collections.Join3(timeBzKeySize, endTime, uint64(endHeight)), valAddrs)
|
|
}
|
|
|
|
// InsertUnbondingValidatorQueue inserts a given unbonding validator address into
|
|
// the unbonding validator queue for a given height and time.
|
|
func (k Keeper) InsertUnbondingValidatorQueue(ctx context.Context, val types.Validator) error {
|
|
addrs, err := k.GetUnbondingValidators(ctx, val.UnbondingTime, val.UnbondingHeight)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
addrs = append(addrs, val.OperatorAddress)
|
|
return k.SetUnbondingValidatorsQueue(ctx, val.UnbondingTime, val.UnbondingHeight, addrs)
|
|
}
|
|
|
|
// DeleteValidatorQueueTimeSlice deletes all entries in the queue indexed by a
|
|
// given height and time.
|
|
func (k Keeper) DeleteValidatorQueueTimeSlice(ctx context.Context, endTime time.Time, endHeight int64) error {
|
|
return k.ValidatorQueue.Remove(ctx, collections.Join3(timeBzKeySize, endTime, uint64(endHeight)))
|
|
}
|
|
|
|
// DeleteValidatorQueue removes a validator by address from the unbonding queue
|
|
// indexed by a given height and time.
|
|
func (k Keeper) DeleteValidatorQueue(ctx context.Context, val types.Validator) error {
|
|
addrs, err := k.GetUnbondingValidators(ctx, val.UnbondingTime, val.UnbondingHeight)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
newAddrs := []string{}
|
|
|
|
// since address string may change due to Bech32 prefix change, we parse the addresses into bytes
|
|
// format for normalization
|
|
deletingAddr, err := k.validatorAddressCodec.StringToBytes(val.OperatorAddress)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, addr := range addrs {
|
|
storedAddr, err := k.validatorAddressCodec.StringToBytes(addr)
|
|
if err != nil {
|
|
// even if we don't error here, it will error in UnbondAllMatureValidators at unbond time
|
|
return err
|
|
}
|
|
if !bytes.Equal(storedAddr, deletingAddr) {
|
|
newAddrs = append(newAddrs, addr)
|
|
}
|
|
}
|
|
|
|
if len(newAddrs) == 0 {
|
|
return k.DeleteValidatorQueueTimeSlice(ctx, val.UnbondingTime, val.UnbondingHeight)
|
|
}
|
|
|
|
return k.SetUnbondingValidatorsQueue(ctx, val.UnbondingTime, val.UnbondingHeight, newAddrs)
|
|
}
|
|
|
|
// UnbondAllMatureValidators unbonds all the mature unbonding validators that
|
|
// have finished their unbonding period.
|
|
func (k Keeper) UnbondAllMatureValidators(ctx context.Context) error {
|
|
headerInfo := k.HeaderService.HeaderInfo(ctx)
|
|
blockTime := headerInfo.Time
|
|
blockHeight := uint64(headerInfo.Height)
|
|
|
|
rng := new(collections.Range[collections.Triple[uint64, time.Time, uint64]]).
|
|
EndInclusive(collections.Join3(uint64(29), blockTime, blockHeight))
|
|
|
|
// get all the values before performing any delete operations
|
|
iter, err := k.ValidatorQueue.Iterate(ctx, rng)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
kvs, err := iter.KeyValues()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, kv := range kvs {
|
|
if err := k.unbondMatureValidators(ctx, blockHeight, blockTime, kv.Key, kv.Value); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (k Keeper) unbondMatureValidators(
|
|
ctx context.Context,
|
|
blockHeight uint64,
|
|
blockTime time.Time,
|
|
key collections.Triple[uint64, time.Time, uint64],
|
|
addrs types.ValAddresses,
|
|
) error {
|
|
keyTime, keyHeight := key.K2(), key.K3()
|
|
|
|
// All addresses for the given key have the same unbonding height and time.
|
|
// We only unbond if the height and time are less than the current height
|
|
// and time.
|
|
if keyHeight > blockHeight || keyTime.After(blockTime) {
|
|
return nil
|
|
}
|
|
|
|
// finalize unbonding
|
|
for _, valAddr := range addrs.Addresses {
|
|
addr, err := k.validatorAddressCodec.StringToBytes(valAddr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
val, err := k.GetValidator(ctx, addr)
|
|
if err != nil {
|
|
return errorsmod.Wrap(err, "validator in the unbonding queue was not found")
|
|
}
|
|
|
|
if !val.IsUnbonding() {
|
|
return errors.New("unexpected validator in unbonding queue; status was not unbonding")
|
|
}
|
|
|
|
// if the ref count is not zero, early exit.
|
|
if val.UnbondingOnHoldRefCount != 0 {
|
|
return nil
|
|
}
|
|
|
|
// otherwise do proper unbonding
|
|
for _, id := range val.UnbondingIds {
|
|
if err = k.DeleteUnbondingIndex(ctx, id); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
val, err = k.UnbondingToUnbonded(ctx, val)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if val.GetDelegatorShares().IsZero() {
|
|
str, err := k.validatorAddressCodec.StringToBytes(val.GetOperator())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err = k.RemoveValidator(ctx, str); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
// remove unbonding ids
|
|
val.UnbondingIds = []uint64{}
|
|
}
|
|
|
|
// remove validator from queue
|
|
if err = k.DeleteValidatorQueue(ctx, val); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IsValidatorJailed checks and returns boolean of a validator status jailed or not.
|
|
func (k Keeper) IsValidatorJailed(ctx context.Context, addr sdk.ConsAddress) (bool, error) {
|
|
v, err := k.GetValidatorByConsAddr(ctx, addr)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return v.Jailed, nil
|
|
}
|
|
|
|
// GetPubKeyByConsAddr returns the consensus public key by consensus address.
|
|
// Caller receives a Cosmos SDK Pubkey type and must cast it to a comet type
|
|
func (k Keeper) GetPubKeyByConsAddr(ctx context.Context, addr sdk.ConsAddress) (cryptotypes.PubKey, error) {
|
|
v, err := k.GetValidatorByConsAddr(ctx, addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pubkey, err := v.ConsPubKey()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return pubkey, nil
|
|
}
|