Skip to content

Commit

Permalink
fix: multisig for assigning consumer key, use json (#916)
Browse files Browse the repository at this point in the history
* json for consumer key

* lint fix

* comment

* lint
  • Loading branch information
shaspitz authored May 4, 2023
1 parent 94fc6c5 commit 504811d
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 100 deletions.
7 changes: 4 additions & 3 deletions proto/interchain_security/ccv/provider/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ message MsgAssignConsumerKey {
// The validator address on the provider
string provider_addr = 2
[ (gogoproto.moretags) = "yaml:\"address\"" ];
// The consensus public key to use on the consumer
google.protobuf.Any consumer_key = 3
[ (cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey" ];
// The consensus public key to use on the consumer.
// in json string format corresponding to proto-any, ex:
// `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`
string consumer_key = 3;
}

message MsgAssignConsumerKeyResponse {}
2 changes: 1 addition & 1 deletion x/ccv/consumer/types/consumer.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 1 addition & 6 deletions x/ccv/provider/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/interchain-security/x/ccv/provider/types"
Expand Down Expand Up @@ -44,12 +43,8 @@ func NewAssignConsumerKeyCmd() *cobra.Command {
WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)

providerValAddr := clientCtx.GetFromAddress()
var consumerPubKey cryptotypes.PubKey
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(args[1]), &consumerPubKey); err != nil {
return err
}

msg, err := types.NewMsgAssignConsumerKey(args[0], sdk.ValAddress(providerValAddr), consumerPubKey)
msg, err := types.NewMsgAssignConsumerKey(args[0], sdk.ValAddress(providerValAddr), args[1])
if err != nil {
return err
}
Expand Down
4 changes: 3 additions & 1 deletion x/ccv/provider/handler_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package provider_test

import (
"encoding/base64"
"strings"
"testing"

Expand Down Expand Up @@ -33,7 +34,8 @@ func TestAssignConsensusKeyForConsumerChain(t *testing.T) {

consumerCryptoId := testcrypto.NewCryptoIdentityFromIntSeed(1)
consumerConsAddr := consumerCryptoId.ConsumerConsAddress()
consumerKey := consumerCryptoId.ConsensusSDKPubKey()
consumerKeyBz := base64.StdEncoding.EncodeToString(consumerCryptoId.ConsensusSDKPubKey().Bytes())
consumerKey := `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"` + consumerKeyBz + `"}`

testCases := []struct {
name string
Expand Down
54 changes: 36 additions & 18 deletions x/ccv/provider/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ package keeper

import (
"context"
"encoding/base64"

cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/interchain-security/x/ccv/provider/types"
ccvtypes "github.com/cosmos/interchain-security/x/ccv/types"
tmstrings "github.com/tendermint/tendermint/libs/strings"
tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto"
)

type msgServer struct {
Expand Down Expand Up @@ -46,42 +45,61 @@ func (k msgServer) AssignConsumerKey(goCtx context.Context, msg *types.MsgAssign
return nil, stakingtypes.ErrNoValidatorFound
}

// make sure the consumer key is in the correct format
consumerSDKPublicKey, ok := msg.ConsumerKey.GetCachedValue().(cryptotypes.PubKey)
if !ok {
return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", consumerSDKPublicKey)
// parse consumer key as long as it's in the right format
pkType, keyStr, err := types.ParseConsumerKeyFromJson(msg.ConsumerKey)
if err != nil {
return nil, err
}

// Note: the correct way to decide if a key type is supported is to check the
// consensus params. However this functionality was disabled in https://github.com/cosmos/interchain-security/pull/916
// as a quick way to get ed25519 working, avoiding amino/proto-any marshalling issues.

// make sure the consumer key type is supported
cp := ctx.ConsensusParams()
if cp != nil && cp.Validator != nil {
if !tmstrings.StringInSlice(consumerSDKPublicKey.Type(), cp.Validator.PubKeyTypes) {
return nil, sdkerrors.Wrapf(
stakingtypes.ErrValidatorPubKeyTypeNotSupported,
"got: %s, expected: %s", consumerSDKPublicKey.Type(), cp.Validator.PubKeyTypes,
)
}
// cp := ctx.ConsensusParams()
// if cp != nil && cp.Validator != nil {
// if !tmstrings.StringInSlice(pkType, cp.Validator.PubKeyTypes) {
// return nil, sdkerrors.Wrapf(
// stakingtypes.ErrValidatorPubKeyTypeNotSupported,
// "got: %s, expected one of: %s", pkType, cp.Validator.PubKeyTypes,
// )
// }
// }

// For now, only accept ed25519.
// TODO: decide what types should be supported.
if pkType != "/cosmos.crypto.ed25519.PubKey" {
return nil, sdkerrors.Wrapf(
stakingtypes.ErrValidatorPubKeyTypeNotSupported,
"got: %s, expected: %s", pkType, "/cosmos.crypto.ed25519.PubKey",
)
}

consumerTMPublicKey, err := cryptocodec.ToTmProtoPublicKey(consumerSDKPublicKey)
pubKeyBytes, err := base64.StdEncoding.DecodeString(keyStr)
if err != nil {
return nil, err
}

consumerTMPublicKey := tmprotocrypto.PublicKey{
Sum: &tmprotocrypto.PublicKey_Ed25519{
Ed25519: pubKeyBytes,
},
}

if err := k.Keeper.AssignConsumerKey(ctx, msg.ChainId, validator, consumerTMPublicKey); err != nil {
return nil, err
}
k.Logger(ctx).Info("assigned consumer key",
"consumer chainID", msg.ChainId,
"validator operator addr", msg.ProviderAddr,
"consumer pubkey", consumerSDKPublicKey.String(),
"consumer tm pubkey", consumerTMPublicKey.String(),
)

ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
ccvtypes.EventTypeAssignConsumerKey,
sdk.NewAttribute(ccvtypes.AttributeProviderValidatorAddress, msg.ProviderAddr),
sdk.NewAttribute(ccvtypes.AttributeConsumerConsensusPubKey, consumerSDKPublicKey.String()),
sdk.NewAttribute(ccvtypes.AttributeConsumerConsensusPubKey, consumerTMPublicKey.String()),
),
})

Expand Down
41 changes: 21 additions & 20 deletions x/ccv/provider/types/msg.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package types

import (
"encoding/json"
"strings"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

Expand All @@ -13,27 +12,17 @@ const (
TypeMsgAssignConsumerKey = "assign_consumer_key"
)

var (
_ sdk.Msg = &MsgAssignConsumerKey{}
_ codectypes.UnpackInterfacesMessage = (*MsgAssignConsumerKey)(nil)
)
var _ sdk.Msg = &MsgAssignConsumerKey{}

// NewMsgAssignConsumerKey creates a new MsgAssignConsumerKey instance.
// Delegator address and validator address are the same.
func NewMsgAssignConsumerKey(chainID string, providerValidatorAddress sdk.ValAddress,
consumerConsensusPubKey cryptotypes.PubKey,
consumerConsensusPubKey string,
) (*MsgAssignConsumerKey, error) {
var keyAsAny *codectypes.Any
if consumerConsensusPubKey != nil {
var err error
if keyAsAny, err = codectypes.NewAnyWithValue(consumerConsensusPubKey); err != nil {
return nil, err
}
}
return &MsgAssignConsumerKey{
ChainId: chainID,
ProviderAddr: providerValidatorAddress.String(),
ConsumerKey: keyAsAny,
ConsumerKey: consumerConsensusPubKey,
}, nil
}

Expand Down Expand Up @@ -81,14 +70,26 @@ func (msg MsgAssignConsumerKey) ValidateBasic() error {
if err != nil {
return ErrInvalidProviderAddress
}
if msg.ConsumerKey == nil {
if msg.ConsumerKey == "" {
return ErrInvalidConsumerConsensusPubKey
}
if _, _, err := ParseConsumerKeyFromJson(msg.ConsumerKey); err != nil {
return ErrInvalidConsumerConsensusPubKey
}
return nil
}

// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
func (msg MsgAssignConsumerKey) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
var pubKey cryptotypes.PubKey
return unpacker.UnpackAny(msg.ConsumerKey, &pubKey)
// ParseConsumerKeyFromJson parses the consumer key from a JSON string,
// this replaces deserializing a protobuf any.
func ParseConsumerKeyFromJson(jsonStr string) (pkType, key string, err error) {
type PubKey struct {
Type string `json:"@type"`
Key string `json:"key"`
}
var pubKey PubKey
err = json.Unmarshal([]byte(jsonStr), &pubKey)
if err != nil {
return "", "", err
}
return pubKey.Type, pubKey.Key, nil
}
93 changes: 42 additions & 51 deletions x/ccv/provider/types/tx.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 504811d

Please sign in to comment.