Skip to content

Commit

Permalink
refactor(staking): check for nil ptrs after GetCachedValue() (#21300)
Browse files Browse the repository at this point in the history
  • Loading branch information
raynaudoe authored Sep 4, 2024
1 parent d56bbb8 commit 502661b
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 40 deletions.
16 changes: 12 additions & 4 deletions x/staking/keeper/cons_pubkey.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,22 @@ func (k Keeper) updateToNewPubkey(ctx context.Context, val types.Validator, oldP
return err
}

oldPk, ok := oldPubKey.GetCachedValue().(cryptotypes.PubKey)
oldPkCached := oldPubKey.GetCachedValue()
if oldPkCached == nil {
return errorsmod.Wrap(sdkerrors.ErrInvalidType, "OldPubKey cached value is nil")
}
oldPk, ok := oldPkCached.(cryptotypes.PubKey)
if !ok {
return errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", oldPk)
return errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", oldPkCached)
}

newPk, ok := newPubKey.GetCachedValue().(cryptotypes.PubKey)
newPkCached := newPubKey.GetCachedValue()
if newPkCached == nil {
return errorsmod.Wrap(sdkerrors.ErrInvalidType, "NewPubKey cached value is nil")
}
newPk, ok := newPkCached.(cryptotypes.PubKey)
if !ok {
return errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", newPk)
return errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", newPkCached)
}

// sets a map: oldConsKey -> newConsKey
Expand Down
9 changes: 8 additions & 1 deletion x/staking/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import (
"google.golang.org/grpc/status"

"cosmossdk.io/collections"
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/store/prefix"
storetypes "cosmossdk.io/store/types"
"cosmossdk.io/x/staking/types"

cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/runtime"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/query"
)

Expand Down Expand Up @@ -63,7 +65,12 @@ func (k Querier) Validators(ctx context.Context, req *types.QueryValidatorsReque
vals.Validators = append(vals.Validators, *val)
valInfo := types.ValidatorInfo{}

cpk, ok := val.ConsensusPubkey.GetCachedValue().(cryptotypes.PubKey)
cv := val.ConsensusPubkey.GetCachedValue()
if cv == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidType, "public key cached value is nil")
}

cpk, ok := cv.(cryptotypes.PubKey)
if ok {
consAddr, err := k.consensusAddressCodec.BytesToString(cpk.Address())
if err == nil {
Expand Down
78 changes: 47 additions & 31 deletions x/staking/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ func NewMsgServerImpl(keeper *Keeper) types.MsgServer {

var _ types.MsgServer = msgServer{}

// CreateValidator defines a method for creating a new validator
// CreateValidator defines a method for creating a new validator.
// The validator's params should not be nil for this function to execute successfully.
func (k msgServer) CreateValidator(ctx context.Context, msg *types.MsgCreateValidator) (*types.MsgCreateValidatorResponse, error) {
valAddr, err := k.validatorAddressCodec.StringToBytes(msg.ValidatorAddress)
if err != nil {
Expand All @@ -64,9 +65,14 @@ func (k msgServer) CreateValidator(ctx context.Context, msg *types.MsgCreateVali
return nil, types.ErrValidatorOwnerExists
}

pk, ok := msg.Pubkey.GetCachedValue().(cryptotypes.PubKey)
cv := msg.Pubkey.GetCachedValue()
if cv == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidType, "Pubkey cached value is nil")
}

pk, ok := cv.(cryptotypes.PubKey)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", msg.Pubkey.GetCachedValue())
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", cv)
}

resp, err := k.QueryRouterService.Invoke(ctx, &consensusv1.QueryParamsRequest{})
Expand All @@ -78,21 +84,12 @@ func (k msgServer) CreateValidator(ctx context.Context, msg *types.MsgCreateVali
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unexpected response type: %T", resp)
}

if res.Params.Validator != nil {
pkType := pk.Type()
if !slices.Contains(res.Params.Validator.PubKeyTypes, pkType) {
return nil, errorsmod.Wrapf(
types.ErrValidatorPubKeyTypeNotSupported,
"got: %s, expected: %s", pk.Type(), res.Params.Validator.PubKeyTypes,
)
}
if res.Params.Validator == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "validator params are not set")
}

if pkType == sdk.PubKeyEd25519Type && len(pk.Bytes()) != ed25519.PubKeySize {
return nil, errorsmod.Wrapf(
types.ErrConsensusPubKeyLenInvalid,
"got: %d, expected: %d", len(pk.Bytes()), ed25519.PubKeySize,
)
}
if err = validatePubKey(pk, res.Params.Validator.PubKeyTypes); err != nil {
return nil, err
}

err = k.checkConsKeyAlreadyUsed(ctx, pk)
Expand Down Expand Up @@ -649,8 +646,15 @@ func (k msgServer) UpdateParams(ctx context.Context, msg *types.MsgUpdateParams)
return &types.MsgUpdateParamsResponse{}, nil
}

// RotateConsPubKey handles the rotation of a validator's consensus public key.
// It validates the new key, checks for conflicts, and updates the necessary state.
// The function requires that the validator params are not nil for successful execution.
func (k msgServer) RotateConsPubKey(ctx context.Context, msg *types.MsgRotateConsPubKey) (res *types.MsgRotateConsPubKeyResponse, err error) {
cv := msg.NewPubkey.GetCachedValue()
if cv == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidType, "new public key is nil")
}

pk, ok := cv.(cryptotypes.PubKey)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "expecting cryptotypes.PubKey, got %T", cv)
Expand All @@ -666,21 +670,12 @@ func (k msgServer) RotateConsPubKey(ctx context.Context, msg *types.MsgRotateCon
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidRequest, "unexpected response type: %T", resp)
}

if paramsRes.Params.Validator != nil {
pkType := pk.Type()
if !slices.Contains(paramsRes.Params.Validator.PubKeyTypes, pkType) {
return nil, errorsmod.Wrapf(
types.ErrValidatorPubKeyTypeNotSupported,
"got: %s, expected: %s", pk.Type(), paramsRes.Params.Validator.PubKeyTypes,
)
}
if paramsRes.Params.Validator == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidRequest, "validator params are not set")
}

if pkType == sdk.PubKeyEd25519Type && len(pk.Bytes()) != ed25519.PubKeySize {
return nil, errorsmod.Wrapf(
types.ErrConsensusPubKeyLenInvalid,
"got: %d, expected: %d", len(pk.Bytes()), ed25519.PubKeySize,
)
}
if err = validatePubKey(pk, paramsRes.Params.Validator.PubKeyTypes); err != nil {
return nil, err
}

err = k.checkConsKeyAlreadyUsed(ctx, pk)
Expand Down Expand Up @@ -778,3 +773,24 @@ func (k msgServer) checkConsKeyAlreadyUsed(ctx context.Context, newConsPubKey cr

return nil
}

func validatePubKey(pk cryptotypes.PubKey, knownPubKeyTypes []string) error {
pkType := pk.Type()
if !slices.Contains(knownPubKeyTypes, pkType) {
return errorsmod.Wrapf(
types.ErrValidatorPubKeyTypeNotSupported,
"got: %s, expected: %s", pk.Type(), knownPubKeyTypes,
)
}

if pkType == sdk.PubKeyEd25519Type {
if len(pk.Bytes()) != ed25519.PubKeySize {
return errorsmod.Wrapf(
types.ErrConsensusPubKeyLenInvalid,
"invalid Ed25519 pubkey size: got %d, expected %d", len(pk.Bytes()), ed25519.PubKeySize,
)
}
}

return nil
}
16 changes: 12 additions & 4 deletions x/staking/keeper/val_state_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,22 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx context.Context) ([]appmod
return nil, err
}

oldPk, ok := history.OldConsPubkey.GetCachedValue().(cryptotypes.PubKey)
oldPkCached := history.OldConsPubkey.GetCachedValue()
if oldPkCached == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidType, "OldConsPubkey cached value is nil")
}
oldPk, ok := oldPkCached.(cryptotypes.PubKey)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", oldPk)
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", oldPkCached)
}

newPk, ok := history.NewConsPubkey.GetCachedValue().(cryptotypes.PubKey)
newPkCached := history.NewConsPubkey.GetCachedValue()
if newPkCached == nil {
return nil, errorsmod.Wrap(sdkerrors.ErrInvalidType, "NewConsPubkey cached value is nil")
}
newPk, ok := newPkCached.(cryptotypes.PubKey)
if !ok {
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", newPk)
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", newPkCached)
}

// a validator cannot rotate keys if it's not bonded or if it's jailed
Expand Down

0 comments on commit 502661b

Please sign in to comment.