diff --git a/x/interchainqueries/types/errors.go b/x/interchainqueries/types/errors.go index e1a47ef7d..6260cfe92 100644 --- a/x/interchainqueries/types/errors.go +++ b/x/interchainqueries/types/errors.go @@ -23,4 +23,8 @@ var ( ErrInvalidHeight = sdkerrors.Register(ModuleName, 1114, "height is invalid") ErrNoQueryResult = sdkerrors.Register(ModuleName, 1115, "no query result") ErrNotContract = sdkerrors.Register(ModuleName, 1116, "not a contract") + ErrEmptyKeys = sdkerrors.Register(ModuleName, 1117, "keys are empty") + ErrEmptyKeyPath = sdkerrors.Register(ModuleName, 1118, "key path is empty") + ErrEmptyKeyID = sdkerrors.Register(ModuleName, 1119, "key id is empty") + ErrTooManyKVQueryKeys = sdkerrors.Register(ModuleName, 1120, "too many keys") ) diff --git a/x/interchainqueries/types/tx.go b/x/interchainqueries/types/tx.go index ace97c6c4..bbce9c72a 100644 --- a/x/interchainqueries/types/tx.go +++ b/x/interchainqueries/types/tx.go @@ -9,6 +9,10 @@ import ( "github.com/cosmos/ibc-go/v3/modules/core/exported" ) +const ( + MaxKVQueryKeysCount = 32 +) + var _ codectypes.UnpackInterfacesMessage = MsgSubmitQueryResult{} func (msg MsgSubmitQueryResult) Route() string { @@ -88,6 +92,15 @@ func (msg MsgRegisterInterchainQuery) ValidateBasic() error { return sdkerrors.Wrap(ErrInvalidQueryType, "invalid query type") } + if InterchainQueryType(msg.QueryType).IsKV() { + if len(msg.Keys) == 0 { + return sdkerrors.Wrap(ErrEmptyKeys, "keys cannot be empty") + } + if err := validateKeys(msg.GetKeys()); err != nil { + return err + } + } + if InterchainQueryType(msg.QueryType).IsTX() { if err := ValidateTransactionsFilter(msg.TransactionsFilter); err != nil { return sdkerrors.Wrap(ErrInvalidTransactionsFilter, err.Error()) @@ -159,6 +172,10 @@ func (msg MsgUpdateInterchainQueryRequest) ValidateBasic() error { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "one of new_keys or new_update_period should be set") } + if err := validateKeys(msg.GetNewKeys()); err != nil { + return err + } + if strings.TrimSpace(msg.Sender) == "" { return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "missing sender address") } @@ -180,3 +197,18 @@ func (msg MsgUpdateInterchainQueryRequest) GetSigners() []sdk.AccAddress { } return []sdk.AccAddress{senderAddr} } + +func validateKeys(keys []*KVKey) error { + if uint64(len(keys)) > MaxKVQueryKeysCount { + return sdkerrors.Wrapf(ErrTooManyKVQueryKeys, "keys count cannot be more than %d", MaxKVQueryKeysCount) + } + for _, key := range keys { + if len(key.Path) == 0 { + return sdkerrors.Wrap(ErrEmptyKeyPath, "keys path cannot be empty") + } + if len(key.Key) == 0 { + return sdkerrors.Wrap(ErrEmptyKeyID, "keys id cannot be empty") + } + } + return nil +} diff --git a/x/interchainqueries/types/tx_test.go b/x/interchainqueries/types/tx_test.go index 1e81c8b53..41da46d14 100644 --- a/x/interchainqueries/types/tx_test.go +++ b/x/interchainqueries/types/tx_test.go @@ -1,6 +1,8 @@ package types_test import ( + "fmt" + "strconv" "testing" sdktypes "github.com/cosmos/cosmos-sdk/types" @@ -48,6 +50,20 @@ func TestMsgRegisterInterchainQueryValidate(t *testing.T) { }, iqtypes.ErrInvalidTransactionsFilter, }, + { + "too many keys", + func() sdktypes.Msg { + return &iqtypes.MsgRegisterInterchainQuery{ + ConnectionId: "connection-0", + TransactionsFilter: "[]", + Keys: craftKVKeys(200), + QueryType: string(iqtypes.InterchainQueryTypeKV), + UpdatePeriod: 1, + Sender: TestAddress, + } + }, + iqtypes.ErrTooManyKVQueryKeys, + }, { "invalid update period", func() sdktypes.Msg { @@ -105,7 +121,7 @@ func TestMsgRegisterInterchainQueryValidate(t *testing.T) { iqtypes.ErrInvalidConnectionID, }, { - "valid", + "empty keys", func() sdktypes.Msg { return &iqtypes.MsgRegisterInterchainQuery{ ConnectionId: "connection-0", @@ -116,6 +132,48 @@ func TestMsgRegisterInterchainQueryValidate(t *testing.T) { Sender: TestAddress, } }, + iqtypes.ErrEmptyKeys, + }, + { + "empty key path", + func() sdktypes.Msg { + return &iqtypes.MsgRegisterInterchainQuery{ + ConnectionId: "connection-0", + TransactionsFilter: "{}", + Keys: []*iqtypes.KVKey{{Key: []byte("key1"), Path: ""}}, + QueryType: string(iqtypes.InterchainQueryTypeKV), + UpdatePeriod: 1, + Sender: TestAddress, + } + }, + iqtypes.ErrEmptyKeyPath, + }, + { + "empty key id", + func() sdktypes.Msg { + return &iqtypes.MsgRegisterInterchainQuery{ + ConnectionId: "connection-0", + TransactionsFilter: "{}", + Keys: []*iqtypes.KVKey{{Key: []byte(""), Path: "path"}}, + QueryType: string(iqtypes.InterchainQueryTypeKV), + UpdatePeriod: 1, + Sender: TestAddress, + } + }, + iqtypes.ErrEmptyKeyID, + }, + { + "valid", + func() sdktypes.Msg { + return &iqtypes.MsgRegisterInterchainQuery{ + ConnectionId: "connection-0", + TransactionsFilter: "{}", + Keys: []*iqtypes.KVKey{{Key: []byte("key1"), Path: "path1"}}, + QueryType: string(iqtypes.InterchainQueryTypeKV), + UpdatePeriod: 1, + Sender: TestAddress, + } + }, nil, }, } @@ -345,6 +403,42 @@ func TestMsgUpdateQueryRequestValidate(t *testing.T) { }, sdkerrors.ErrInvalidRequest, }, + { + "empty key path", + func() sdktypes.Msg { + return &iqtypes.MsgUpdateInterchainQueryRequest{ + QueryId: 1, + NewKeys: []*iqtypes.KVKey{{Key: []byte("key1"), Path: ""}}, + NewUpdatePeriod: 0, + Sender: TestAddress, + } + }, + iqtypes.ErrEmptyKeyPath, + }, + { + "empty key id", + func() sdktypes.Msg { + return &iqtypes.MsgUpdateInterchainQueryRequest{ + QueryId: 1, + NewKeys: []*iqtypes.KVKey{{Key: []byte(""), Path: "path"}}, + NewUpdatePeriod: 0, + Sender: TestAddress, + } + }, + iqtypes.ErrEmptyKeyID, + }, + { + "too many keys", + func() sdktypes.Msg { + return &iqtypes.MsgUpdateInterchainQueryRequest{ + QueryId: 1, + NewKeys: craftKVKeys(200), + NewUpdatePeriod: 0, + Sender: TestAddress, + } + }, + iqtypes.ErrTooManyKVQueryKeys, + }, { "invalid query id", func() sdktypes.Msg { @@ -573,3 +667,15 @@ func TestMsgRemoveQueryGetSigners(t *testing.T) { require.Equal(t, msg.GetSigners(), []sdktypes.AccAddress{addr}) } } + +func craftKVKeys(n uint64) []*iqtypes.KVKey { + keys := make([]*iqtypes.KVKey, n) + for i := uint64(0); i < n; i++ { + keys[i] = &iqtypes.KVKey{ + Path: "path-" + strconv.FormatUint(i, 10), + Key: []byte(fmt.Sprintf("key-%d", i)), + } + } + + return keys +}