feat(x/staking): implement RotateConsPubKey method (#18188)

This commit is contained in:
atheeshp
2023-11-15 06:59:50 +00:00
committed by GitHub
parent e269c6d5db
commit 0f8c6c2c12
15 changed files with 496 additions and 231 deletions
+74 -2
View File
@@ -2,6 +2,7 @@ package keeper
import (
"context"
"errors"
"strconv"
"time"
@@ -9,6 +10,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"cosmossdk.io/collections"
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/math"
"cosmossdk.io/x/staking/types"
@@ -605,6 +607,76 @@ func (k msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams)
return &types.MsgUpdateParamsResponse{}, nil
}
func (k msgServer) RotateConsPubKey(_ context.Context, _ *types.MsgRotateConsPubKey) (*types.MsgRotateConsPubKeyResponse, error) {
return nil, nil
func (k msgServer) RotateConsPubKey(ctx context.Context, msg *types.MsgRotateConsPubKey) (res *types.MsgRotateConsPubKeyResponse, err error) {
cv := msg.NewPubkey.GetCachedValue()
pk, ok := cv.(cryptotypes.PubKey)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expecting cryptotypes.PubKey, got %T", cv)
}
// check cons key is already present in the key rotation history.
rotatedTo, err := k.RotatedConsKeyMapIndex.Get(ctx, pk.Address())
if err != nil && !errors.Is(err, collections.ErrNotFound) {
return nil, err
}
if rotatedTo != nil {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidAddress,
"the new public key is already present in rotation history, please try with a different one")
}
newConsAddr := sdk.ConsAddress(pk.Address())
// checks if NewPubKey is not duplicated on ValidatorsByConsAddr
validator1, _ := k.Keeper.ValidatorByConsAddr(ctx, newConsAddr)
if validator1 != nil {
return nil, types.ErrConsensusPubKeyAlreadyUsedForValidator
}
valAddr, err := k.validatorAddressCodec.StringToBytes(msg.ValidatorAddress)
if err != nil {
return nil, err
}
validator2, err := k.Keeper.GetValidator(ctx, valAddr)
if err != nil {
return nil, types.ErrNoValidatorFound
}
if status := validator2.GetStatus(); status != types.Bonded {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "validator status is not bonded, got %s", status.String())
}
// Check if the validator is exceeding parameter MaxConsPubKeyRotations within the
// unbonding period by iterating ConsPubKeyRotationHistory.
err = k.exceedsMaxRotations(ctx, valAddr)
if err != nil {
return nil, err
}
// Check if the signing account has enough balance to pay KeyRotationFee
// KeyRotationFees are sent to the community fund.
params, err := k.Params.Get(ctx)
if err != nil {
return nil, err
}
err = k.Keeper.bankKeeper.SendCoinsFromAccountToModule(ctx, sdk.AccAddress(valAddr), types.DistributionModuleName, sdk.NewCoins(params.KeyRotationFee))
if err != nil {
return nil, err
}
// Add ConsPubKeyRotationHistory for tracking rotation
err = k.setConsPubKeyRotationHistory(
ctx,
valAddr,
validator2.ConsensusPubkey,
msg.NewPubkey,
params.KeyRotationFee,
)
if err != nil {
return nil, err
}
return res, nil
}