diff --git a/CHANGELOG.md b/CHANGELOG.md index 06833ef15560..5944aeff845b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (server) [#16827](https://github.com/cosmos/cosmos-sdk/pull/16827) Properly use `--trace` flag (before it was setting the trace level instead of displaying the stacktraces). * (x/bank) [#16841](https://github.com/cosmos/cosmos-sdk/pull/16841) correctly process legacy `DenomAddressIndex` values. +* (types/query) [#16905](https://github.com/cosmos/cosmos-sdk/pull/16905) – Collections Pagination now applies proper count when filtering results. ### API Breaking Changes diff --git a/types/query/collections_pagination.go b/types/query/collections_pagination.go index 4ef389038dc6..47ca6d5fbb74 100644 --- a/types/query/collections_pagination.go +++ b/types/query/collections_pagination.go @@ -35,24 +35,40 @@ type Collection[K, V any] interface { KeyCodec() collcodec.KeyCodec[K] } -// CollectionPaginate follows the same behavior as Paginate but works on a Collection. -func CollectionPaginate[K, V any, C Collection[K, V]]( +// CollectionPaginate follows the same logic as Paginate but for collection types. +// transformFunc is used to transform the result to a different type. +func CollectionPaginate[K, V any, C Collection[K, V], T any]( ctx context.Context, coll C, pageReq *PageRequest, -) ([]collections.KeyValue[K, V], *PageResponse, error) { - return CollectionFilteredPaginate[K, V](ctx, coll, pageReq, nil) + transformFunc func(key K, value V) (T, error), + opts ...func(opt *CollectionsPaginateOptions[K]), +) ([]T, *PageResponse, error) { + return CollectionFilteredPaginate( + ctx, + coll, + pageReq, + nil, + transformFunc, + opts..., + ) } -// CollectionFilteredPaginate works in the same way as FilteredPaginate but for collection types. +// CollectionFilteredPaginate works in the same way as CollectionPaginate but allows to filter +// results using a predicateFunc. // A nil predicateFunc means no filtering is applied and results are collected as is. -func CollectionFilteredPaginate[K, V any, C Collection[K, V]]( +// TransformFunc is applied only to results which are in range of the pagination and allow +// to convert the result to a different type. +// NOTE: do not collect results using the values/keys passed to predicateFunc as they are not +// guaranteed to be in the pagination range requested. +func CollectionFilteredPaginate[K, V any, C Collection[K, V], T any]( ctx context.Context, coll C, pageReq *PageRequest, predicateFunc func(key K, value V) (include bool, err error), + transformFunc func(key K, value V) (T, error), opts ...func(opt *CollectionsPaginateOptions[K]), -) ([]collections.KeyValue[K, V], *PageResponse, error) { +) (results []T, pageRes *PageResponse, err error) { pageReq = initPageRequestDefaults(pageReq) offset := pageReq.Offset @@ -65,12 +81,6 @@ func CollectionFilteredPaginate[K, V any, C Collection[K, V]]( return nil, nil, fmt.Errorf("invalid request, either offset or key is expected, got both") } - var ( - results []collections.KeyValue[K, V] - pageRes *PageResponse - err error - ) - opt := new(CollectionsPaginateOptions[K]) for _, o := range opts { o(opt) @@ -85,9 +95,9 @@ func CollectionFilteredPaginate[K, V any, C Collection[K, V]]( } if len(key) != 0 { - results, pageRes, err = collFilteredPaginateByKey(ctx, coll, prefix, key, reverse, limit, predicateFunc) + results, pageRes, err = collFilteredPaginateByKey(ctx, coll, prefix, key, reverse, limit, predicateFunc, transformFunc) } else { - results, pageRes, err = collFilteredPaginateNoKey(ctx, coll, prefix, reverse, offset, limit, countTotal, predicateFunc) + results, pageRes, err = collFilteredPaginateNoKey(ctx, coll, prefix, reverse, offset, limit, countTotal, predicateFunc, transformFunc) } // invalid iter error is ignored to retain Paginate behavior if errors.Is(err, collections.ErrInvalidIterator) { @@ -102,7 +112,7 @@ func CollectionFilteredPaginate[K, V any, C Collection[K, V]]( // collFilteredPaginateNoKey applies the provided pagination on the collection when the starting key is not set. // If predicateFunc is nil no filtering is applied. -func collFilteredPaginateNoKey[K, V any, C Collection[K, V]]( +func collFilteredPaginateNoKey[K, V any, C Collection[K, V], T any]( ctx context.Context, coll C, prefix []byte, @@ -111,7 +121,8 @@ func collFilteredPaginateNoKey[K, V any, C Collection[K, V]]( limit uint64, countTotal bool, predicateFunc func(K, V) (bool, error), -) ([]collections.KeyValue[K, V], *PageResponse, error) { + transformFunc func(K, V) (T, error), +) ([]T, *PageResponse, error) { iterator, err := getCollIter[K, V](ctx, coll, prefix, nil, reverse) if err != nil { return nil, nil, err @@ -125,7 +136,7 @@ func collFilteredPaginateNoKey[K, V any, C Collection[K, V]]( var ( count uint64 nextKey []byte - results []collections.KeyValue[K, V] + results []T ) for ; iterator.Valid(); iterator.Next() { @@ -138,7 +149,13 @@ func collFilteredPaginateNoKey[K, V any, C Collection[K, V]]( } // if no predicate function is specified then we just include the result if predicateFunc == nil { - results = append(results, kv) + transformed, err := transformFunc(kv.Key, kv.Value) + if err != nil { + return nil, nil, err + } + results = append(results, transformed) + count++ + // if predicate function is defined we check if the result matches the filtering criteria } else { include, err := predicateFunc(kv.Key, kv.Value) @@ -146,10 +163,14 @@ func collFilteredPaginateNoKey[K, V any, C Collection[K, V]]( return nil, nil, err } if include { - results = append(results, kv) + transformed, err := transformFunc(kv.Key, kv.Value) + if err != nil { + return nil, nil, err + } + results = append(results, transformed) + count++ } } - count++ // second case, we found all the objects specified within the limit case count == limit: key, err := iterator.Key() @@ -172,12 +193,31 @@ func collFilteredPaginateNoKey[K, V any, C Collection[K, V]]( // but we need to count how many possible results exist in total. // so we keep increasing the count until the iterator is fully consumed. case count > limit: - count++ + if predicateFunc == nil { + count++ + + // if predicate function is defined we check if the result matches the filtering criteria + } else { + kv, err := iterator.KeyValue() + if err != nil { + return nil, nil, err + } + + include, err := predicateFunc(kv.Key, kv.Value) + if err != nil { + return nil, nil, err + } + if include { + count++ + } + } } } + resp := &PageResponse{ NextKey: nextKey, } + if countTotal { resp.Total = count + offset } @@ -200,15 +240,16 @@ func advanceIter[I interface { // collFilteredPaginateByKey paginates a collection when a starting key // is provided in the PageRequest. Predicate is applied only if not nil. -func collFilteredPaginateByKey[K, V any, C Collection[K, V]]( +func collFilteredPaginateByKey[K, V any, C Collection[K, V], T any]( ctx context.Context, coll C, prefix []byte, key []byte, reverse bool, limit uint64, - predicateFunc func(K, V) (bool, error), -) ([]collections.KeyValue[K, V], *PageResponse, error) { + predicateFunc func(key K, value V) (bool, error), + transformFunc func(key K, value V) (transformed T, err error), +) (results []T, pageRes *PageResponse, err error) { iterator, err := getCollIter[K, V](ctx, coll, prefix, key, reverse) if err != nil { return nil, nil, err @@ -218,7 +259,6 @@ func collFilteredPaginateByKey[K, V any, C Collection[K, V]]( var ( count uint64 nextKey []byte - results []collections.KeyValue[K, V] ) for ; iterator.Valid(); iterator.Next() { @@ -243,7 +283,11 @@ func collFilteredPaginateByKey[K, V any, C Collection[K, V]]( } // if no predicate is specified then we just append the result if predicateFunc == nil { - results = append(results, kv) + transformed, err := transformFunc(kv.Key, kv.Value) + if err != nil { + return nil, nil, err + } + results = append(results, transformed) // if predicate is applied we execute the predicate function // and append only if predicateFunc yields true. } else { @@ -252,7 +296,11 @@ func collFilteredPaginateByKey[K, V any, C Collection[K, V]]( return nil, nil, err } if include { - results = append(results, kv) + transformed, err := transformFunc(kv.Key, kv.Value) + if err != nil { + return nil, nil, err + } + results = append(results, transformed) } } count++ diff --git a/types/query/collections_pagination_test.go b/types/query/collections_pagination_test.go index cbd3cd0b736e..874722d4de40 100644 --- a/types/query/collections_pagination_test.go +++ b/types/query/collections_pagination_test.go @@ -100,7 +100,7 @@ func TestCollectionPagination(t *testing.T) { Limit: 3, }, expResp: &PageResponse{ - NextKey: encodeKey(3), + NextKey: encodeKey(5), }, filter: func(key, value uint64) (bool, error) { return key%2 == 0, nil @@ -108,6 +108,7 @@ func TestCollectionPagination(t *testing.T) { expResults: []collections.KeyValue[uint64, uint64]{ {Key: 0, Value: 0}, {Key: 2, Value: 2}, + {Key: 4, Value: 4}, }, }, "filtered with key": { @@ -131,7 +132,15 @@ func TestCollectionPagination(t *testing.T) { for name, tc := range tcs { tc := tc t.Run(name, func(t *testing.T) { - gotResults, gotResponse, err := CollectionFilteredPaginate(ctx, m, tc.req, tc.filter) + gotResults, gotResponse, err := CollectionFilteredPaginate( + ctx, + m, + tc.req, + tc.filter, + func(key, value uint64) (collections.KeyValue[uint64, uint64], error) { + return collections.KeyValue[uint64, uint64]{Key: key, Value: value}, nil + }, + ) if tc.wantErr != nil { require.ErrorIs(t, err, tc.wantErr) return diff --git a/x/auth/keeper/grpc_query.go b/x/auth/keeper/grpc_query.go index f348131ca3ad..1b40d3c3b38c 100644 --- a/x/auth/keeper/grpc_query.go +++ b/x/auth/keeper/grpc_query.go @@ -47,15 +47,14 @@ func (s queryServer) Accounts(ctx context.Context, req *types.QueryAccountsReque return nil, status.Error(codes.InvalidArgument, "empty request") } - var accounts []*codectypes.Any - _, pageRes, err := query.CollectionFilteredPaginate(ctx, s.k.Accounts, req.Pagination, func(_ sdk.AccAddress, value sdk.AccountI) (include bool, err error) { - accountAny, err := codectypes.NewAnyWithValue(value) - if err != nil { - return false, err - } - accounts = append(accounts, accountAny) - return false, nil // we don't include it since we're already appending the account - }) + accounts, pageRes, err := query.CollectionPaginate( + ctx, + s.k.Accounts, + req.Pagination, + func(_ sdk.AccAddress, value sdk.AccountI) (*codectypes.Any, error) { + return codectypes.NewAnyWithValue(value) + }, + ) return &types.QueryAccountsResponse{Accounts: accounts, Pagination: pageRes}, err } diff --git a/x/bank/keeper/grpc_query.go b/x/bank/keeper/grpc_query.go index 086f105664e1..010525e5d415 100644 --- a/x/bank/keeper/grpc_query.go +++ b/x/bank/keeper/grpc_query.go @@ -60,19 +60,20 @@ func (k BaseKeeper) AllBalances(ctx context.Context, req *types.QueryAllBalances } sdkCtx := sdk.UnwrapSDKContext(ctx) - - balances := sdk.NewCoins() - - _, pageRes, err := query.CollectionFilteredPaginate(ctx, k.Balances, req.Pagination, func(key collections.Pair[sdk.AccAddress, string], value math.Int) (include bool, err error) { - denom := key.K2() - if req.ResolveDenom { - if metadata, ok := k.GetDenomMetaData(sdkCtx, denom); ok { - denom = metadata.Display + balances, pageRes, err := query.CollectionPaginate( + ctx, + k.Balances, + req.Pagination, + func(key collections.Pair[sdk.AccAddress, string], value math.Int) (sdk.Coin, error) { + if req.ResolveDenom { + if metadata, ok := k.GetDenomMetaData(sdkCtx, key.K2()); ok { + return sdk.NewCoin(metadata.Display, value), nil + } } - } - balances = append(balances, sdk.NewCoin(denom, value)) - return false, nil // we don't include results because we're appending them here. - }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, string](addr)) + return sdk.NewCoin(key.K2(), value), nil + }, + query.WithCollectionPaginationPairPrefix[sdk.AccAddress, string](addr), + ) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "paginate: %v", err) } @@ -94,12 +95,10 @@ func (k BaseKeeper) SpendableBalances(ctx context.Context, req *types.QuerySpend sdkCtx := sdk.UnwrapSDKContext(ctx) - balances := sdk.NewCoins() zeroAmt := math.ZeroInt() - _, pageRes, err := query.CollectionFilteredPaginate(ctx, k.Balances, req.Pagination, func(key collections.Pair[sdk.AccAddress, string], _ math.Int) (include bool, err error) { - balances = append(balances, sdk.NewCoin(key.K2(), zeroAmt)) - return false, nil // not including results as they're appended here + balances, pageRes, err := query.CollectionPaginate(ctx, k.Balances, req.Pagination, func(key collections.Pair[sdk.AccAddress, string], _ math.Int) (coin sdk.Coin, err error) { + return sdk.NewCoin(key.K2(), zeroAmt), nil }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, string](addr)) if err != nil { return nil, status.Errorf(codes.InvalidArgument, "paginate: %v", err) @@ -280,19 +279,16 @@ func (k BaseKeeper) DenomOwners( return nil, status.Error(codes.InvalidArgument, err.Error()) } - var denomOwners []*types.DenomOwner - - _, pageRes, err := query.CollectionFilteredPaginate(goCtx, k.Balances.Indexes.Denom, req.Pagination, - func(key collections.Pair[string, sdk.AccAddress], value collections.NoValue) (include bool, err error) { + denomOwners, pageRes, err := query.CollectionPaginate( + goCtx, + k.Balances.Indexes.Denom, + req.Pagination, + func(key collections.Pair[string, sdk.AccAddress], value collections.NoValue) (*types.DenomOwner, error) { amt, err := k.Balances.Get(goCtx, collections.Join(key.K2(), req.Denom)) if err != nil { - return false, err + return nil, err } - denomOwners = append(denomOwners, &types.DenomOwner{ - Address: key.K2().String(), - Balance: sdk.NewCoin(req.Denom, amt), - }) - return false, nil + return &types.DenomOwner{Address: key.K2().String(), Balance: sdk.NewCoin(req.Denom, amt)}, nil }, query.WithCollectionPaginationPairPrefix[string, sdk.AccAddress](req.Denom), ) @@ -316,16 +312,17 @@ func (k BaseKeeper) SendEnabled(goCtx context.Context, req *types.QuerySendEnabl } } } else { - results, pageResp, err := query.CollectionPaginate[string, bool](ctx, k.BaseViewKeeper.SendEnabled, req.Pagination) + results, pageResp, err := query.CollectionPaginate( + ctx, + k.BaseViewKeeper.SendEnabled, + req.Pagination, func(key string, value bool) (*types.SendEnabled, error) { + return types.NewSendEnabled(key, value), nil + }, + ) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } - for _, r := range results { - resp.SendEnabled = append(resp.SendEnabled, &types.SendEnabled{ - Denom: r.Key, - Enabled: r.Value, - }) - } + resp.SendEnabled = results resp.Pagination = pageResp } diff --git a/x/bank/keeper/keeper.go b/x/bank/keeper/keeper.go index 4c9b63e07c25..cb0787a5addc 100644 --- a/x/bank/keeper/keeper.go +++ b/x/bank/keeper/keeper.go @@ -69,14 +69,12 @@ type MintingRestrictionFn func(ctx context.Context, coins sdk.Coins) error // GetPaginatedTotalSupply queries for the supply, ignoring 0 coins, with a given pagination func (k BaseKeeper) GetPaginatedTotalSupply(ctx context.Context, pagination *query.PageRequest) (sdk.Coins, *query.PageResponse, error) { - results, pageResp, err := query.CollectionPaginate[string, math.Int](ctx, k.Supply, pagination) + coins, pageResp, err := query.CollectionPaginate(ctx, k.Supply, pagination, func(key string, value math.Int) (sdk.Coin, error) { + return sdk.NewCoin(key, value), nil + }) if err != nil { return nil, nil, err } - coins := sdk.NewCoins() - for _, res := range results { - coins = coins.Add(sdk.NewCoin(res.Key, res.Value)) - } return coins, pageResp, nil } diff --git a/x/circuit/go.mod b/x/circuit/go.mod index a422e971689b..60af1396608a 100644 --- a/x/circuit/go.mod +++ b/x/circuit/go.mod @@ -12,7 +12,7 @@ require ( cosmossdk.io/store v1.0.0-alpha.1 github.com/cockroachdb/errors v1.10.0 github.com/cometbft/cometbft v0.38.0-rc2 - github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713093628-90d9a75d4125 + github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713152238-de8d95cc44b5 github.com/cosmos/gogoproto v1.4.10 github.com/golang/protobuf v1.5.3 github.com/grpc-ecosystem/grpc-gateway v1.16.0 diff --git a/x/circuit/go.sum b/x/circuit/go.sum index a0d8d2092b7b..c5a37a5e1391 100644 --- a/x/circuit/go.sum +++ b/x/circuit/go.sum @@ -168,8 +168,8 @@ github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0 github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U= github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o= github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I= -github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713093628-90d9a75d4125 h1:2aGCqfxWf2AAvLOUHaRiByle6n0FPRdeOF/62JTldh0= -github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713093628-90d9a75d4125/go.mod h1:LME6v5XztqVK7/1uTQj/G6ZJdosJEz24rKaPYk+WbqI= +github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713152238-de8d95cc44b5 h1:6s31oUkdv9/uEuCIQ/eUXxOOhfJ6gAHbX/9C2mollhY= +github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713152238-de8d95cc44b5/go.mod h1:LME6v5XztqVK7/1uTQj/G6ZJdosJEz24rKaPYk+WbqI= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/circuit/keeper/query.go b/x/circuit/keeper/query.go index 681a04c210ae..931fe828d230 100644 --- a/x/circuit/keeper/query.go +++ b/x/circuit/keeper/query.go @@ -42,26 +42,26 @@ func (qs QueryServer) Account(c context.Context, req *types.QueryAccountRequest) // Account returns account permissions. func (qs QueryServer) Accounts(ctx context.Context, req *types.QueryAccountsRequest) (*types.AccountsResponse, error) { - var accounts []*types.GenesisAccountPermissions - results, pageRes, err := query.CollectionPaginate[[]byte, types.Permissions](ctx, qs.keeper.Permissions, req.Pagination) + results, pageRes, err := query.CollectionPaginate( + ctx, + qs.keeper.Permissions, + req.Pagination, + func(key []byte, value types.Permissions) (*types.GenesisAccountPermissions, error) { + addrStr, err := qs.keeper.addressCodec.BytesToString(key) + if err != nil { + return nil, err + } + return &types.GenesisAccountPermissions{ + Address: addrStr, + Permissions: &value, + }, nil + }, + ) if err != nil { return nil, err } - for _, result := range results { - result := result - address, err := qs.keeper.addressCodec.BytesToString(result.Key) - if err != nil { - return nil, err - } - - accounts = append(accounts, &types.GenesisAccountPermissions{ - Address: address, - Permissions: &result.Value, - }) - } - - return &types.AccountsResponse{Accounts: accounts, Pagination: pageRes}, nil + return &types.AccountsResponse{Accounts: results, Pagination: pageRes}, nil } // DisabledList returns a list of disabled message urls diff --git a/x/evidence/go.mod b/x/evidence/go.mod index 35f2515a49dc..b7d34fd8863d 100644 --- a/x/evidence/go.mod +++ b/x/evidence/go.mod @@ -13,7 +13,7 @@ require ( cosmossdk.io/store v1.0.0-alpha.1 github.com/cometbft/cometbft v0.38.0-rc2 github.com/cosmos/cosmos-proto v1.0.0-beta.3 - github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713093628-90d9a75d4125 + github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713152238-de8d95cc44b5 github.com/cosmos/gogoproto v1.4.10 github.com/golang/mock v1.6.0 github.com/golang/protobuf v1.5.3 diff --git a/x/evidence/go.sum b/x/evidence/go.sum index 1d9eab9748af..80d8dd39b249 100644 --- a/x/evidence/go.sum +++ b/x/evidence/go.sum @@ -175,8 +175,8 @@ github.com/cosmos/cosmos-db v1.0.0 h1:EVcQZ+qYag7W6uorBKFPvX6gRjw6Uq2hIh4hCWjuQ0 github.com/cosmos/cosmos-db v1.0.0/go.mod h1:iBvi1TtqaedwLdcrZVYRSSCb6eSy61NLj4UNmdIgs0U= github.com/cosmos/cosmos-proto v1.0.0-beta.3 h1:VitvZ1lPORTVxkmF2fAp3IiA61xVwArQYKXTdEcpW6o= github.com/cosmos/cosmos-proto v1.0.0-beta.3/go.mod h1:t8IASdLaAq+bbHbjq4p960BvcTqtwuAxid3b/2rOD6I= -github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713093628-90d9a75d4125 h1:2aGCqfxWf2AAvLOUHaRiByle6n0FPRdeOF/62JTldh0= -github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713093628-90d9a75d4125/go.mod h1:LME6v5XztqVK7/1uTQj/G6ZJdosJEz24rKaPYk+WbqI= +github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713152238-de8d95cc44b5 h1:6s31oUkdv9/uEuCIQ/eUXxOOhfJ6gAHbX/9C2mollhY= +github.com/cosmos/cosmos-sdk v0.46.0-beta2.0.20230713152238-de8d95cc44b5/go.mod h1:LME6v5XztqVK7/1uTQj/G6ZJdosJEz24rKaPYk+WbqI= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= github.com/cosmos/gogogateway v1.2.0 h1:Ae/OivNhp8DqBi/sh2A8a1D0y638GpL3tkmLQAiKxTE= diff --git a/x/evidence/keeper/grpc_query.go b/x/evidence/keeper/grpc_query.go index 38ee61c00bd1..22d2be5c2458 100644 --- a/x/evidence/keeper/grpc_query.go +++ b/x/evidence/keeper/grpc_query.go @@ -68,18 +68,12 @@ func (k Querier) AllEvidence(ctx context.Context, req *types.QueryAllEvidenceReq return nil, status.Errorf(codes.InvalidArgument, "empty request") } - var evidence []*codectypes.Any - _, pageRes, err := query.CollectionFilteredPaginate(ctx, k.k.Evidences, req.Pagination, func(_ []byte, value exported.Evidence) (include bool, err error) { - evidenceAny, err := codectypes.NewAnyWithValue(value) - if err != nil { - return false, err - } - evidence = append(evidence, evidenceAny) - return false, nil // we don't include results because we're appending them + evidences, pageRes, err := query.CollectionPaginate(ctx, k.k.Evidences, req.Pagination, func(_ []byte, value exported.Evidence) (*codectypes.Any, error) { + return codectypes.NewAnyWithValue(value) }) if err != nil { return nil, err } - return &types.QueryAllEvidenceResponse{Evidence: evidence, Pagination: pageRes}, nil + return &types.QueryAllEvidenceResponse{Evidence: evidences, Pagination: pageRes}, nil } diff --git a/x/gov/keeper/grpc_query.go b/x/gov/keeper/grpc_query.go index a4b4a035140a..070be73711cb 100644 --- a/x/gov/keeper/grpc_query.go +++ b/x/gov/keeper/grpc_query.go @@ -56,8 +56,7 @@ func (q queryServer) Proposal(ctx context.Context, req *v1.QueryProposalRequest) // Proposals implements the Query/Proposals gRPC method func (q queryServer) Proposals(ctx context.Context, req *v1.QueryProposalsRequest) (*v1.QueryProposalsResponse, error) { - var filteredProposals []*v1.Proposal - _, pageRes, err := query.CollectionFilteredPaginate(ctx, q.k.Proposals, req.Pagination, func(key uint64, p v1.Proposal) (bool, error) { + filteredProposals, pageRes, err := query.CollectionFilteredPaginate(ctx, q.k.Proposals, req.Pagination, func(key uint64, p v1.Proposal) (include bool, err error) { matchVoter, matchDepositor, matchStatus := true, true, true // match status (if supplied/valid) @@ -90,11 +89,14 @@ func (q queryServer) Proposals(ctx context.Context, req *v1.QueryProposalsReques // if all match, append to results if matchVoter && matchDepositor && matchStatus { - filteredProposals = append(filteredProposals, &p) + return true, nil } // continue to next item, do not include because we're appending results above. return false, nil + }, func(_ uint64, value v1.Proposal) (*v1.Proposal, error) { + return &value, nil }) + if err != nil && !errors.IsOf(err, collections.ErrInvalidIterator) { return nil, status.Error(codes.Internal, err.Error()) } @@ -142,10 +144,8 @@ func (q queryServer) Votes(ctx context.Context, req *v1.QueryVotesRequest) (*v1. return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0") } - var votes v1.Votes - _, pageRes, err := query.CollectionFilteredPaginate(ctx, q.k.Votes, req.Pagination, func(_ collections.Pair[uint64, sdk.AccAddress], value v1.Vote) (include bool, err error) { - votes = append(votes, &value) - return false, nil // not including results because they're being appended. + votes, pageRes, err := query.CollectionPaginate(ctx, q.k.Votes, req.Pagination, func(_ collections.Pair[uint64, sdk.AccAddress], value v1.Vote) (vote *v1.Vote, err error) { + return &value, nil }, query.WithCollectionPaginationPairPrefix[uint64, sdk.AccAddress](req.ProposalId)) if err != nil { return nil, status.Error(codes.Internal, err.Error()) @@ -227,9 +227,8 @@ func (q queryServer) Deposits(ctx context.Context, req *v1.QueryDepositsRequest) } var deposits []*v1.Deposit - _, pageRes, err := query.CollectionFilteredPaginate(ctx, q.k.Deposits, req.Pagination, func(_ collections.Pair[uint64, sdk.AccAddress], deposit v1.Deposit) (bool, error) { - deposits = append(deposits, &deposit) - return false, nil // we don't include results as they're being appended to the slice above. + deposits, pageRes, err := query.CollectionPaginate(ctx, q.k.Deposits, req.Pagination, func(_ collections.Pair[uint64, sdk.AccAddress], deposit v1.Deposit) (*v1.Deposit, error) { + return &deposit, nil }, query.WithCollectionPaginationPairPrefix[uint64, sdk.AccAddress](req.ProposalId)) if err != nil { return nil, status.Error(codes.Internal, err.Error()) diff --git a/x/gov/keeper/grpc_query_test.go b/x/gov/keeper/grpc_query_test.go index 4ed4d5e8cccc..4edfd04651f9 100644 --- a/x/gov/keeper/grpc_query_test.go +++ b/x/gov/keeper/grpc_query_test.go @@ -233,7 +233,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryProposals() { true, }, { - "request 2nd page with limit 4", + "request 2nd page with limit 3", func() { req = &v1.QueryProposalsRequest{ Pagination: &query.PageRequest{Offset: 3, Limit: 3}, @@ -307,6 +307,70 @@ func (suite *KeeperTestSuite) TestGRPCQueryProposals() { }, true, }, + { + "request with filter of status voting period", + func() { + req = &v1.QueryProposalsRequest{ + ProposalStatus: v1.StatusVotingPeriod, + } + + var proposals []*v1.Proposal + for i := 0; i < len(testProposals); i++ { + if testProposals[i].GetStatus() == v1.StatusVotingPeriod { + proposals = append(proposals, testProposals[i]) + } + } + + expRes = &v1.QueryProposalsResponse{ + Proposals: proposals, + } + }, + true, + }, + { + "request with filter of status deposit period", + func() { + req = &v1.QueryProposalsRequest{ + ProposalStatus: v1.StatusDepositPeriod, + } + + var proposals []*v1.Proposal + for i := 0; i < len(testProposals); i++ { + if testProposals[i].GetStatus() == v1.StatusDepositPeriod { + proposals = append(proposals, testProposals[i]) + } + } + + expRes = &v1.QueryProposalsResponse{ + Proposals: proposals, + } + }, + true, + }, + { + "request with filter of status deposit period with limit 2", + func() { + req = &v1.QueryProposalsRequest{ + ProposalStatus: v1.StatusDepositPeriod, + Pagination: &query.PageRequest{ + Limit: 2, + CountTotal: true, + }, + } + + var proposals []*v1.Proposal + for i := 0; i < len(testProposals) && len(proposals) < 2; i++ { + if testProposals[i].GetStatus() == v1.StatusDepositPeriod { + proposals = append(proposals, testProposals[i]) + } + } + + expRes = &v1.QueryProposalsResponse{ + Proposals: proposals, + } + }, + true, + }, } for _, testCase := range testCases {