From aad302d6ac99f8da4e5063abdb2c014566fec6f4 Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Tue, 2 May 2023 12:30:31 +0400 Subject: [PATCH 1/7] add basic validation --- x/interchainqueries/types/errors.go | 1 + x/interchainqueries/types/genesis.go | 41 +++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/x/interchainqueries/types/errors.go b/x/interchainqueries/types/errors.go index 6260cfe92..30a5048c1 100644 --- a/x/interchainqueries/types/errors.go +++ b/x/interchainqueries/types/errors.go @@ -27,4 +27,5 @@ var ( 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") + ErrEmptyQueryTypeGenesis = sdkerrors.Register(ModuleName, 1121, "empty query type") ) diff --git a/x/interchainqueries/types/genesis.go b/x/interchainqueries/types/genesis.go index ffd96d1aa..a955f6e5f 100644 --- a/x/interchainqueries/types/genesis.go +++ b/x/interchainqueries/types/genesis.go @@ -1,5 +1,10 @@ package types +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + // DefaultGenesis returns the default Capability genesis state func DefaultGenesis() *GenesisState { return &GenesisState{ @@ -10,5 +15,39 @@ func DefaultGenesis() *GenesisState { // Validate performs basic genesis state validation returning an error upon any // failure. func (gs GenesisState) Validate() error { - return gs.Params.Validate() + err := gs.Params.Validate() + if err != nil { + return err + } + seenIDs := map[uint64]bool{} + + for _, val := range gs.GetRegisteredQueries() { + if seenIDs[val.Id] { + return sdkerrors.Wrapf(ErrInvalidQueryID, "duplicate query id: %d", val.Id) + } + + _, err = sdk.AccAddressFromBech32(val.Owner) + if err != nil { + return sdkerrors.Wrapf(err, "Invalid owner address (%s)", err) + } + + if val.QueryType == "" { + return sdkerrors.Wrapf(ErrEmptyQueryTypeGenesis, "Query type is empty, id: %d", val.Id) + } + + if val.QueryType == "tx" { + if err := ValidateTransactionsFilter(val.TransactionsFilter); err != nil { + return sdkerrors.Wrap(ErrInvalidTransactionsFilter, err.Error()) + } + } + if val.QueryType == "kv" { + if len(val.Keys) == 0 { + return sdkerrors.Wrap(ErrEmptyKeys, "keys cannot be empty") + } + if err := validateKeys(val.GetKeys()); err != nil { + return err + } + } + } + return nil } From a2bdf5c3a001c6ef8e5c5a6b624195f3449be82c Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Tue, 23 May 2023 11:27:35 +0400 Subject: [PATCH 2/7] save keys to map --- x/interchainqueries/types/genesis.go | 1 + 1 file changed, 1 insertion(+) diff --git a/x/interchainqueries/types/genesis.go b/x/interchainqueries/types/genesis.go index a955f6e5f..9ec099a69 100644 --- a/x/interchainqueries/types/genesis.go +++ b/x/interchainqueries/types/genesis.go @@ -25,6 +25,7 @@ func (gs GenesisState) Validate() error { if seenIDs[val.Id] { return sdkerrors.Wrapf(ErrInvalidQueryID, "duplicate query id: %d", val.Id) } + seenIDs[val.Id] = true _, err = sdk.AccAddressFromBech32(val.Owner) if err != nil { From f6ee9f5cd5d3022900ecba58a5b93a3ec2d0f916 Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Fri, 26 May 2023 09:35:28 +0400 Subject: [PATCH 3/7] small ref --- x/interchainqueries/types/errors.go | 44 ++++++++++++++-------------- x/interchainqueries/types/genesis.go | 12 ++++---- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/x/interchainqueries/types/errors.go b/x/interchainqueries/types/errors.go index 30a5048c1..edab0926e 100644 --- a/x/interchainqueries/types/errors.go +++ b/x/interchainqueries/types/errors.go @@ -6,26 +6,26 @@ import ( // x/interchainqueries module sentinel errors var ( - ErrInvalidQueryID = sdkerrors.Register(ModuleName, 1100, "invalid query id") - ErrEmptyResult = sdkerrors.Register(ModuleName, 1101, "empty result") - ErrInvalidClientID = sdkerrors.Register(ModuleName, 1102, "invalid client id") - ErrInvalidUpdatePeriod = sdkerrors.Register(ModuleName, 1103, "invalid update period") - ErrInvalidConnectionID = sdkerrors.Register(ModuleName, 1104, "invalid connection id") - ErrInvalidQueryType = sdkerrors.Register(ModuleName, 1105, "invalid query type") - ErrInvalidTransactionsFilter = sdkerrors.Register(ModuleName, 1106, "invalid transactions filter") - ErrInvalidSubmittedResult = sdkerrors.Register(ModuleName, 1107, "invalid result") - ErrProtoMarshal = sdkerrors.Register(ModuleName, 1108, "failed to marshal protobuf bytes") - ErrProtoUnmarshal = sdkerrors.Register(ModuleName, 1109, "failed to unmarshal protobuf bytes") - ErrInvalidType = sdkerrors.Register(ModuleName, 1110, "invalid type") - ErrInternal = sdkerrors.Register(ModuleName, 1111, "internal error") - ErrInvalidProof = sdkerrors.Register(ModuleName, 1112, "merkle proof is invalid") - ErrInvalidHeader = sdkerrors.Register(ModuleName, 1113, "header is invalid") - 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") - ErrEmptyQueryTypeGenesis = sdkerrors.Register(ModuleName, 1121, "empty query type") + ErrInvalidQueryID = sdkerrors.Register(ModuleName, 1100, "invalid query id") + ErrEmptyResult = sdkerrors.Register(ModuleName, 1101, "empty result") + ErrInvalidClientID = sdkerrors.Register(ModuleName, 1102, "invalid client id") + ErrInvalidUpdatePeriod = sdkerrors.Register(ModuleName, 1103, "invalid update period") + ErrInvalidConnectionID = sdkerrors.Register(ModuleName, 1104, "invalid connection id") + ErrInvalidQueryType = sdkerrors.Register(ModuleName, 1105, "invalid query type") + ErrInvalidTransactionsFilter = sdkerrors.Register(ModuleName, 1106, "invalid transactions filter") + ErrInvalidSubmittedResult = sdkerrors.Register(ModuleName, 1107, "invalid result") + ErrProtoMarshal = sdkerrors.Register(ModuleName, 1108, "failed to marshal protobuf bytes") + ErrProtoUnmarshal = sdkerrors.Register(ModuleName, 1109, "failed to unmarshal protobuf bytes") + ErrInvalidType = sdkerrors.Register(ModuleName, 1110, "invalid type") + ErrInternal = sdkerrors.Register(ModuleName, 1111, "internal error") + ErrInvalidProof = sdkerrors.Register(ModuleName, 1112, "merkle proof is invalid") + ErrInvalidHeader = sdkerrors.Register(ModuleName, 1113, "header is invalid") + 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") + ErrUnexpectedQueryTypeGenesis = sdkerrors.Register(ModuleName, 1121, "empty query type") ) diff --git a/x/interchainqueries/types/genesis.go b/x/interchainqueries/types/genesis.go index 9ec099a69..4769bb957 100644 --- a/x/interchainqueries/types/genesis.go +++ b/x/interchainqueries/types/genesis.go @@ -32,22 +32,20 @@ func (gs GenesisState) Validate() error { return sdkerrors.Wrapf(err, "Invalid owner address (%s)", err) } - if val.QueryType == "" { - return sdkerrors.Wrapf(ErrEmptyQueryTypeGenesis, "Query type is empty, id: %d", val.Id) - } - - if val.QueryType == "tx" { + switch val.QueryType { + case "tx": if err := ValidateTransactionsFilter(val.TransactionsFilter); err != nil { return sdkerrors.Wrap(ErrInvalidTransactionsFilter, err.Error()) } - } - if val.QueryType == "kv" { + case "kv": if len(val.Keys) == 0 { return sdkerrors.Wrap(ErrEmptyKeys, "keys cannot be empty") } if err := validateKeys(val.GetKeys()); err != nil { return err } + default: + return sdkerrors.Wrapf(ErrUnexpectedQueryTypeGenesis, "Unexpected query type: %s", val.QueryType) } } return nil From 8ad657027999c9a5c591285e55181f9736c60862 Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Fri, 26 May 2023 14:23:28 +0400 Subject: [PATCH 4/7] fix err --- x/interchainqueries/types/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/interchainqueries/types/errors.go b/x/interchainqueries/types/errors.go index edab0926e..c35a02d0b 100644 --- a/x/interchainqueries/types/errors.go +++ b/x/interchainqueries/types/errors.go @@ -27,5 +27,5 @@ var ( 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") - ErrUnexpectedQueryTypeGenesis = sdkerrors.Register(ModuleName, 1121, "empty query type") + ErrUnexpectedQueryTypeGenesis = sdkerrors.Register(ModuleName, 1121, "unexpected query type") ) From 3c44e8fdd4e27b9defd922a56e89b1fb31e22603 Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Fri, 26 May 2023 14:31:34 +0400 Subject: [PATCH 5/7] use constants from types --- x/interchainqueries/types/genesis.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/interchainqueries/types/genesis.go b/x/interchainqueries/types/genesis.go index 4769bb957..2a57447c4 100644 --- a/x/interchainqueries/types/genesis.go +++ b/x/interchainqueries/types/genesis.go @@ -33,11 +33,11 @@ func (gs GenesisState) Validate() error { } switch val.QueryType { - case "tx": + case string(InterchainQueryTypeTX): if err := ValidateTransactionsFilter(val.TransactionsFilter); err != nil { return sdkerrors.Wrap(ErrInvalidTransactionsFilter, err.Error()) } - case "kv": + case string(InterchainQueryTypeKV): if len(val.Keys) == 0 { return sdkerrors.Wrap(ErrEmptyKeys, "keys cannot be empty") } From 53862db75c71314a0cca0d2698c7d27c37070ef0 Mon Sep 17 00:00:00 2001 From: quasisamurai Date: Fri, 30 Jun 2023 11:34:19 +0400 Subject: [PATCH 6/7] add unit tests --- x/interchainqueries/genesis_test.go | 238 ++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) diff --git a/x/interchainqueries/genesis_test.go b/x/interchainqueries/genesis_test.go index 594d4a9f0..06a5a9286 100644 --- a/x/interchainqueries/genesis_test.go +++ b/x/interchainqueries/genesis_test.go @@ -59,3 +59,241 @@ func TestGenesisNullQueries(t *testing.T) { require.ElementsMatch(t, genesisState.RegisteredQueries, got.RegisteredQueries) } + +func TestGenesisFilledQueries(t *testing.T) { + genesisState := types.GenesisState{ + Params: types.DefaultParams(), + RegisteredQueries: []*types.RegisteredQuery{ + { + Id: 4, + QueryType: "kv", + Owner: "cosmos18g0avxazu3dkgd5n5ea8h8rtl78de0hytsj9vm", + Keys: []*types.KVKey{ + { + Path: "newpath", + Key: []byte("newdata"), + }, + }, + }, + { + Id: 3, + QueryType: "kv", + Owner: "cosmos18g0avxazu3dkgd5n5ea8h8rtl78de0hytsj9vm", + Keys: []*types.KVKey{ + { + Path: "newpath", + Key: []byte("newdata"), + }, + }, + }, + { + Id: 2, + QueryType: "tx", + Owner: "cosmos18g0avxazu3dkgd5n5ea8h8rtl78de0hytsj9vm", + TransactionsFilter: `[{"field":"tx.height","op":"Eq","value":1000}]`, + }, + { + Id: 1, + QueryType: "tx", + Owner: "cosmos18g0avxazu3dkgd5n5ea8h8rtl78de0hytsj9vm", + TransactionsFilter: `[{"field":"tx.height","op":"Eq","value":1000}]`, + }, + }, + } + + k, ctx := keepertest.InterchainQueriesKeeper(t, nil, nil, nil, nil) + interchainqueries.InitGenesis(ctx, *k, genesisState) + got := interchainqueries.ExportGenesis(ctx, *k) + err := got.Validate() + require.NoError(t, err) + + require.ElementsMatch(t, genesisState.RegisteredQueries, got.RegisteredQueries) +} + +func TestGenesisMalformedQueriesInvalidTxFilter(t *testing.T) { + genesisState := types.GenesisState{ + Params: types.DefaultParams(), + RegisteredQueries: []*types.RegisteredQuery{ + { + Id: 4, + QueryType: "kv", + Owner: "cosmos18g0avxazu3dkgd5n5ea8h8rtl78de0hytsj9vm", + Keys: []*types.KVKey{ + { + Path: "newpath", + Key: []byte("newdata"), + }, + }, + }, + { + Id: 3, + QueryType: "kv", + Owner: "cosmos18g0avxazu3dkgd5n5ea8h8rtl78de0hytsj9vm", + Keys: []*types.KVKey{ + { + Path: "newpath", + Key: []byte("newdata"), + }, + }, + }, + { + Id: 2, + QueryType: "tx", + Owner: "cosmos18g0avxazu3dkgd5n5ea8h8rtl78de0hytsj9vm", + TransactionsFilter: `[{"field":"tx.height","op":"Eq","value":1000}]`, + }, + { + Id: 1, + QueryType: "tx", + Owner: "cosmos18g0avxazu3dkgd5n5ea8h8rtl78de0hytsj9vm", + TransactionsFilter: `[{"fi> Date: Fri, 30 Jun 2023 17:13:09 +0400 Subject: [PATCH 7/7] fix addr --- x/interchainqueries/genesis_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/interchainqueries/genesis_test.go b/x/interchainqueries/genesis_test.go index 06a5a9286..b8f601ddf 100644 --- a/x/interchainqueries/genesis_test.go +++ b/x/interchainqueries/genesis_test.go @@ -167,7 +167,7 @@ func TestGenesisMalformedQueriesNoKvKeys(t *testing.T) { { Id: 4, QueryType: "kv", - Owner: "neutron18g0avxazu3dkgd5n5ea8h8rtl78de0hytsj9vm", + Owner: "cosmos18g0avxazu3dkgd5n5ea8h8rtl78de0hytsj9vm", }, { Id: 3, @@ -199,7 +199,7 @@ func TestGenesisMalformedQueriesNoKvKeys(t *testing.T) { interchainqueries.InitGenesis(ctx, *k, genesisState) got := interchainqueries.ExportGenesis(ctx, *k) err := got.Validate() - require.ErrorContains(t, err, "Invalid owner address") + require.ErrorContains(t, err, "keys are empty") require.ElementsMatch(t, genesisState.RegisteredQueries, got.RegisteredQueries) }