diff --git a/CHANGELOG.md b/CHANGELOG.md index 94efc4d653d1..11184090ae53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* [\#9884](https://github.com/cosmos/cosmos-sdk/pull/9884) Provide a new gRPC query handler, `/cosmos/params/v1beta1/subspaces`, that allows the ability to query for all registered subspaces and their respective keys. * [\#9860](https://github.com/cosmos/cosmos-sdk/pull/9860) Emit transaction fee in ante handler fee decorator. The event type is `tx` and the attribute is `fee`. * [\#9776](https://github.com/cosmos/cosmos-sdk/pull/9776) Add flag `staking-bond-denom` to specify the staking bond denomination value when initializing a new chain. * [\#9533](https://github.com/cosmos/cosmos-sdk/pull/9533) Added a new gRPC method, `DenomOwners`, in `x/bank` to query for all account holders of a specific denomination. diff --git a/docs/core/proto-docs.md b/docs/core/proto-docs.md index 6b68c21ae232..b9d5372e35ab 100644 --- a/docs/core/proto-docs.md +++ b/docs/core/proto-docs.md @@ -483,6 +483,9 @@ - [cosmos/params/v1beta1/query.proto](#cosmos/params/v1beta1/query.proto) - [QueryParamsRequest](#cosmos.params.v1beta1.QueryParamsRequest) - [QueryParamsResponse](#cosmos.params.v1beta1.QueryParamsResponse) + - [QuerySubspacesRequest](#cosmos.params.v1beta1.QuerySubspacesRequest) + - [QuerySubspacesResponse](#cosmos.params.v1beta1.QuerySubspacesResponse) + - [Subspace](#cosmos.params.v1beta1.Subspace) - [Query](#cosmos.params.v1beta1.Query) @@ -966,7 +969,7 @@ Query defines the gRPC querier service. | `Accounts` | [QueryAccountsRequest](#cosmos.auth.v1beta1.QueryAccountsRequest) | [QueryAccountsResponse](#cosmos.auth.v1beta1.QueryAccountsResponse) | Accounts returns all the existing accounts | GET|/cosmos/auth/v1beta1/accounts| | `Account` | [QueryAccountRequest](#cosmos.auth.v1beta1.QueryAccountRequest) | [QueryAccountResponse](#cosmos.auth.v1beta1.QueryAccountResponse) | Account returns account details based on address. | GET|/cosmos/auth/v1beta1/accounts/{address}| | `Params` | [QueryParamsRequest](#cosmos.auth.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#cosmos.auth.v1beta1.QueryParamsResponse) | Params queries all parameters. | GET|/cosmos/auth/v1beta1/params| -| `ModuleAccounts` | [QueryModuleAccountsRequest](#cosmos.auth.v1beta1.QueryModuleAccountsRequest) | [QueryModuleAccountsResponse](#cosmos.auth.v1beta1.QueryModuleAccountsResponse) | ModuleAccounts returns all the existing Module Accounts. | GET|/cosmos/auth/v1beta1/module_accounts| +| `ModuleAccounts` | [QueryModuleAccountsRequest](#cosmos.auth.v1beta1.QueryModuleAccountsRequest) | [QueryModuleAccountsResponse](#cosmos.auth.v1beta1.QueryModuleAccountsResponse) | ModuleAccounts returns all the existing module accounts. | GET|/cosmos/auth/v1beta1/module_accounts| @@ -6957,6 +6960,50 @@ QueryParamsResponse is response type for the Query/Params RPC method. + + + +### QuerySubspacesRequest +QuerySubspacesRequest defines a request type for querying for all registered +subspaces and all keys for a subspace. + + + + + + + + +### QuerySubspacesResponse +QuerySubspacesResponse defines the response types for querying for all +registered subspaces and all keys for a subspace. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `subspaces` | [Subspace](#cosmos.params.v1beta1.Subspace) | repeated | | + + + + + + + + +### Subspace +Subspace defines a parameter subspace name and all the keys that exist for +the subspace. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| `subspace` | [string](#string) | | | +| `keys` | [string](#string) | repeated | | + + + + + @@ -6972,6 +7019,7 @@ Query defines the gRPC querier service. | Method Name | Request Type | Response Type | Description | HTTP Verb | Endpoint | | ----------- | ------------ | ------------- | ------------| ------- | -------- | | `Params` | [QueryParamsRequest](#cosmos.params.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#cosmos.params.v1beta1.QueryParamsResponse) | Params queries a specific parameter of a module, given its subspace and key. | GET|/cosmos/params/v1beta1/params| +| `Subspaces` | [QuerySubspacesRequest](#cosmos.params.v1beta1.QuerySubspacesRequest) | [QuerySubspacesResponse](#cosmos.params.v1beta1.QuerySubspacesResponse) | Subspaces queries for all registered subspaces and all keys for a subspace. | GET|/cosmos/params/v1beta1/subspaces| diff --git a/proto/cosmos/params/v1beta1/query.proto b/proto/cosmos/params/v1beta1/query.proto index 1078e02ae3e6..3b1c9a760092 100644 --- a/proto/cosmos/params/v1beta1/query.proto +++ b/proto/cosmos/params/v1beta1/query.proto @@ -14,6 +14,11 @@ service Query { rpc Params(QueryParamsRequest) returns (QueryParamsResponse) { option (google.api.http).get = "/cosmos/params/v1beta1/params"; } + + // Subspaces queries for all registered subspaces and all keys for a subspace. + rpc Subspaces(QuerySubspacesRequest) returns (QuerySubspacesResponse) { + option (google.api.http).get = "/cosmos/params/v1beta1/subspaces"; + } } // QueryParamsRequest is request type for the Query/Params RPC method. @@ -30,3 +35,20 @@ message QueryParamsResponse { // param defines the queried parameter. ParamChange param = 1 [(gogoproto.nullable) = false]; } + +// QuerySubspacesRequest defines a request type for querying for all registered +// subspaces and all keys for a subspace. +message QuerySubspacesRequest {} + +// QuerySubspacesResponse defines the response types for querying for all +// registered subspaces and all keys for a subspace. +message QuerySubspacesResponse { + repeated Subspace subspaces = 1; +} + +// Subspace defines a parameter subspace name and all the keys that exist for +// the subspace. +message Subspace { + string subspace = 1; + repeated string keys = 2; +} diff --git a/x/auth/types/query.pb.go b/x/auth/types/query.pb.go index 61c7041a6a9d..c3712a26cf79 100644 --- a/x/auth/types/query.pb.go +++ b/x/auth/types/query.pb.go @@ -456,7 +456,7 @@ type QueryClient interface { Account(ctx context.Context, in *QueryAccountRequest, opts ...grpc.CallOption) (*QueryAccountResponse, error) // Params queries all parameters. Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) - // ModuleAccounts returns all the existing Module Accounts. + // ModuleAccounts returns all the existing module accounts. ModuleAccounts(ctx context.Context, in *QueryModuleAccountsRequest, opts ...grpc.CallOption) (*QueryModuleAccountsResponse, error) } @@ -512,7 +512,7 @@ type QueryServer interface { Account(context.Context, *QueryAccountRequest) (*QueryAccountResponse, error) // Params queries all parameters. Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) - // ModuleAccounts returns all the existing Module Accounts. + // ModuleAccounts returns all the existing module accounts. ModuleAccounts(context.Context, *QueryModuleAccountsRequest) (*QueryModuleAccountsResponse, error) } diff --git a/x/group/types.pb.go b/x/group/types.pb.go index 56fbe2286f4f..c0e5cf2d5e75 100644 --- a/x/group/types.pb.go +++ b/x/group/types.pb.go @@ -567,9 +567,9 @@ type Proposal struct { Result Proposal_Result `protobuf:"varint,9,opt,name=result,proto3,enum=cosmos.group.v1beta1.Proposal_Result" json:"result,omitempty"` // vote_state contains the sums of all weighted votes for this proposal. VoteState Tally `protobuf:"bytes,10,opt,name=vote_state,json=voteState,proto3" json:"vote_state"` - // timeout is the timestamp of the block where the proposal execution times out. Header times of the votes and execution messages - // must be before this end time to be included in the election. After the timeout timestamp the proposal can not be - // executed anymore and should be considered pending delete. + // timeout is the timestamp of the block where the proposal execution times out. Header times of the votes and + // execution messages must be before this end time to be included in the election. After the timeout timestamp the + // proposal can not be executed anymore and should be considered pending delete. Timeout time.Time `protobuf:"bytes,11,opt,name=timeout,proto3,stdtime" json:"timeout"` // executor_result is the final result based on the votes and election rule. Initial value is NotRun. ExecutorResult Proposal_ExecutorResult `protobuf:"varint,12,opt,name=executor_result,json=executorResult,proto3,enum=cosmos.group.v1beta1.Proposal_ExecutorResult" json:"executor_result,omitempty"` diff --git a/x/params/keeper/grpc_query.go b/x/params/keeper/grpc_query.go index 2cfa1c8042d7..d918dc002a38 100644 --- a/x/params/keeper/grpc_query.go +++ b/x/params/keeper/grpc_query.go @@ -34,3 +34,36 @@ func (k Keeper) Params(c context.Context, req *proposal.QueryParamsRequest) (*pr return &proposal.QueryParamsResponse{Param: param}, nil } + +// Subspaces implements the gRPC query handler for fetching all registered +// subspaces and all the keys for each subspace. +func (k Keeper) Subspaces( + goCtx context.Context, + req *proposal.QuerySubspacesRequest, +) (*proposal.QuerySubspacesResponse, error) { + + if req == nil { + return nil, status.Errorf(codes.InvalidArgument, "empty request") + } + + spaces := k.GetSubspaces() + resp := &proposal.QuerySubspacesResponse{ + Subspaces: make([]*proposal.Subspace, len(spaces)), + } + + ctx := sdk.UnwrapSDKContext(goCtx) + for i, ss := range spaces { + var keys []string + ss.IterateKeys(ctx, func(key []byte) bool { + keys = append(keys, string(key)) + return false + }) + + resp.Subspaces[i] = &proposal.Subspace{ + Subspace: ss.Name(), + Keys: keys, + } + } + + return resp, nil +} diff --git a/x/params/keeper/grpc_query_test.go b/x/params/keeper/grpc_query_test.go index 19794beb0808..f6985fe7e6dd 100644 --- a/x/params/keeper/grpc_query_test.go +++ b/x/params/keeper/grpc_query_test.go @@ -84,3 +84,24 @@ func (suite *KeeperTestSuite) TestGRPCQueryParams() { }) } } + +func (suite *KeeperTestSuite) TestGRPCQuerySubspaces() { + ctx := sdk.WrapSDKContext(suite.ctx) + + // NOTE: Each subspace will not have any keys that we can check against + // because InitGenesis has not been called during app construction. + resp, err := suite.queryClient.Subspaces(ctx, &proposal.QuerySubspacesRequest{}) + suite.Require().NoError(err) + suite.Require().NotNil(resp) + + spaces := make([]string, len(resp.Subspaces)) + i := 0 + for _, ss := range resp.Subspaces { + spaces[i] = ss.Subspace + i++ + } + + // require the response contains a few subspaces we know exist + suite.Require().Contains(spaces, "bank") + suite.Require().Contains(spaces, "staking") +} diff --git a/x/params/keeper/keeper.go b/x/params/keeper/keeper.go index 388d99c51c99..8a0e708aeb3d 100644 --- a/x/params/keeper/keeper.go +++ b/x/params/keeper/keeper.go @@ -59,3 +59,15 @@ func (k Keeper) GetSubspace(s string) (types.Subspace, bool) { } return *space, ok } + +// GetSubspaces returns all the registered subspaces. +func (k Keeper) GetSubspaces() []types.Subspace { + spaces := make([]types.Subspace, len(k.spaces)) + i := 0 + for _, ss := range k.spaces { + spaces[i] = *ss + i++ + } + + return spaces +} diff --git a/x/params/keeper/keeper_test.go b/x/params/keeper/keeper_test.go index 44c8223f2c25..795a9aac6ffc 100644 --- a/x/params/keeper/keeper_test.go +++ b/x/params/keeper/keeper_test.go @@ -148,6 +148,29 @@ func indirect(ptr interface{}) interface{} { return reflect.ValueOf(ptr).Elem().Interface() } +func TestGetSubspaces(t *testing.T) { + _, _, _, _, keeper := testComponents() + + table := types.NewKeyTable( + types.NewParamSetPair([]byte("string"), "", validateNoOp), + types.NewParamSetPair([]byte("bool"), false, validateNoOp), + ) + + _ = keeper.Subspace("key1").WithKeyTable(table) + _ = keeper.Subspace("key2").WithKeyTable(table) + + spaces := keeper.GetSubspaces() + require.Len(t, spaces, 2) + + var names []string + for _, ss := range spaces { + names = append(names, ss.Name()) + } + + require.Contains(t, names, "key1") + require.Contains(t, names, "key2") +} + func TestSubspace(t *testing.T) { cdc, ctx, key, _, keeper := testComponents() diff --git a/x/params/types/proposal/query.pb.go b/x/params/types/proposal/query.pb.go index e0c770d70e24..229f4f8e9bb0 100644 --- a/x/params/types/proposal/query.pb.go +++ b/x/params/types/proposal/query.pb.go @@ -130,36 +130,182 @@ func (m *QueryParamsResponse) GetParam() ParamChange { return ParamChange{} } +// QuerySubspacesRequest defines a request type for querying for all registered +// subspaces and all keys for a subspace. +type QuerySubspacesRequest struct { +} + +func (m *QuerySubspacesRequest) Reset() { *m = QuerySubspacesRequest{} } +func (m *QuerySubspacesRequest) String() string { return proto.CompactTextString(m) } +func (*QuerySubspacesRequest) ProtoMessage() {} +func (*QuerySubspacesRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_2b32979c1792ccc4, []int{2} +} +func (m *QuerySubspacesRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySubspacesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySubspacesRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QuerySubspacesRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySubspacesRequest.Merge(m, src) +} +func (m *QuerySubspacesRequest) XXX_Size() int { + return m.Size() +} +func (m *QuerySubspacesRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySubspacesRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySubspacesRequest proto.InternalMessageInfo + +// QuerySubspacesResponse defines the response types for querying for all +// registered subspaces and all keys for a subspace. +type QuerySubspacesResponse struct { + Subspaces []*Subspace `protobuf:"bytes,1,rep,name=subspaces,proto3" json:"subspaces,omitempty"` +} + +func (m *QuerySubspacesResponse) Reset() { *m = QuerySubspacesResponse{} } +func (m *QuerySubspacesResponse) String() string { return proto.CompactTextString(m) } +func (*QuerySubspacesResponse) ProtoMessage() {} +func (*QuerySubspacesResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_2b32979c1792ccc4, []int{3} +} +func (m *QuerySubspacesResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QuerySubspacesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QuerySubspacesResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QuerySubspacesResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QuerySubspacesResponse.Merge(m, src) +} +func (m *QuerySubspacesResponse) XXX_Size() int { + return m.Size() +} +func (m *QuerySubspacesResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QuerySubspacesResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QuerySubspacesResponse proto.InternalMessageInfo + +func (m *QuerySubspacesResponse) GetSubspaces() []*Subspace { + if m != nil { + return m.Subspaces + } + return nil +} + +// Subspace defines a parameter subspace name and all the keys that exist for +// the subspace. +type Subspace struct { + Subspace string `protobuf:"bytes,1,opt,name=subspace,proto3" json:"subspace,omitempty"` + Keys []string `protobuf:"bytes,2,rep,name=keys,proto3" json:"keys,omitempty"` +} + +func (m *Subspace) Reset() { *m = Subspace{} } +func (m *Subspace) String() string { return proto.CompactTextString(m) } +func (*Subspace) ProtoMessage() {} +func (*Subspace) Descriptor() ([]byte, []int) { + return fileDescriptor_2b32979c1792ccc4, []int{4} +} +func (m *Subspace) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Subspace) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Subspace.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *Subspace) XXX_Merge(src proto.Message) { + xxx_messageInfo_Subspace.Merge(m, src) +} +func (m *Subspace) XXX_Size() int { + return m.Size() +} +func (m *Subspace) XXX_DiscardUnknown() { + xxx_messageInfo_Subspace.DiscardUnknown(m) +} + +var xxx_messageInfo_Subspace proto.InternalMessageInfo + +func (m *Subspace) GetSubspace() string { + if m != nil { + return m.Subspace + } + return "" +} + +func (m *Subspace) GetKeys() []string { + if m != nil { + return m.Keys + } + return nil +} + func init() { proto.RegisterType((*QueryParamsRequest)(nil), "cosmos.params.v1beta1.QueryParamsRequest") proto.RegisterType((*QueryParamsResponse)(nil), "cosmos.params.v1beta1.QueryParamsResponse") + proto.RegisterType((*QuerySubspacesRequest)(nil), "cosmos.params.v1beta1.QuerySubspacesRequest") + proto.RegisterType((*QuerySubspacesResponse)(nil), "cosmos.params.v1beta1.QuerySubspacesResponse") + proto.RegisterType((*Subspace)(nil), "cosmos.params.v1beta1.Subspace") } func init() { proto.RegisterFile("cosmos/params/v1beta1/query.proto", fileDescriptor_2b32979c1792ccc4) } var fileDescriptor_2b32979c1792ccc4 = []byte{ - // 321 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x91, 0x31, 0x4b, 0x3b, 0x31, - 0x14, 0xc0, 0x2f, 0xfd, 0xff, 0x5b, 0x34, 0x2e, 0x12, 0x15, 0xca, 0xa1, 0x57, 0x3d, 0x10, 0x54, - 0x30, 0xa1, 0xd5, 0xd9, 0xa1, 0xee, 0xa2, 0x05, 0x17, 0xb7, 0x5c, 0x0d, 0x69, 0x69, 0x7b, 0x2f, - 0xbd, 0x97, 0x13, 0xbb, 0x3a, 0x38, 0x17, 0xfc, 0x52, 0x1d, 0x0b, 0x2e, 0x4e, 0x22, 0xad, 0x1f, - 0x44, 0x9a, 0xb4, 0x82, 0x58, 0xc5, 0x29, 0x2f, 0x2f, 0xbf, 0xf7, 0x7b, 0x79, 0x09, 0xdd, 0x6b, - 0x02, 0xf6, 0x00, 0x85, 0x91, 0x99, 0xec, 0xa1, 0xb8, 0xab, 0x26, 0xca, 0xca, 0xaa, 0xe8, 0xe7, - 0x2a, 0x1b, 0x70, 0x93, 0x81, 0x05, 0xb6, 0xe5, 0x11, 0xee, 0x11, 0x3e, 0x47, 0xc2, 0x4d, 0x0d, - 0x1a, 0x1c, 0x21, 0x66, 0x91, 0x87, 0xc3, 0x6d, 0x0d, 0xa0, 0xbb, 0x4a, 0x48, 0xd3, 0x16, 0x32, - 0x4d, 0xc1, 0x4a, 0xdb, 0x86, 0x14, 0xe7, 0xa7, 0xf1, 0xf2, 0x6e, 0x73, 0xb3, 0x63, 0xe2, 0x3a, - 0x65, 0x57, 0xb3, 0xee, 0x97, 0x2e, 0xd9, 0x50, 0xfd, 0x5c, 0xa1, 0x65, 0x21, 0x5d, 0xc1, 0x3c, - 0x41, 0x23, 0x9b, 0xaa, 0x4c, 0x76, 0xc9, 0xc1, 0x6a, 0xe3, 0x73, 0xcf, 0xd6, 0xe9, 0xbf, 0x8e, - 0x1a, 0x94, 0x0b, 0x2e, 0x3d, 0x0b, 0xe3, 0x6b, 0xba, 0xf1, 0xc5, 0x81, 0x06, 0x52, 0x54, 0xec, - 0x8c, 0x16, 0x5d, 0x2b, 0x67, 0x58, 0xab, 0xc5, 0x7c, 0xe9, 0x64, 0xdc, 0x55, 0x9d, 0xb7, 0x64, - 0xaa, 0x55, 0xfd, 0xff, 0xe8, 0xb5, 0x12, 0x34, 0x7c, 0x59, 0x6d, 0x48, 0x68, 0xd1, 0x79, 0xd9, - 0x23, 0xa1, 0x25, 0x2f, 0x67, 0x87, 0x3f, 0x58, 0xbe, 0x0f, 0x11, 0x1e, 0xfd, 0x05, 0xf5, 0x77, - 0x8d, 0xf7, 0x1f, 0x9e, 0xdf, 0x9f, 0x0a, 0x15, 0xb6, 0x23, 0x7e, 0x7b, 0xb3, 0xfa, 0xc5, 0x68, - 0x12, 0x91, 0xf1, 0x24, 0x22, 0x6f, 0x93, 0x88, 0x0c, 0xa7, 0x51, 0x30, 0x9e, 0x46, 0xc1, 0xcb, - 0x34, 0x0a, 0x6e, 0x4e, 0x75, 0xdb, 0xb6, 0xf2, 0x84, 0x37, 0xa1, 0xb7, 0x50, 0xf8, 0xe5, 0x18, - 0x6f, 0x3b, 0xe2, 0x7e, 0xe1, 0xb3, 0x03, 0xa3, 0x50, 0x98, 0x0c, 0x0c, 0xa0, 0xec, 0x26, 0x25, - 0xf7, 0x09, 0x27, 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xaa, 0xd5, 0x67, 0xc7, 0x18, 0x02, 0x00, - 0x00, + // 415 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x4d, 0x8b, 0xd3, 0x40, + 0x18, 0xce, 0xa4, 0x1f, 0x34, 0xd3, 0x8b, 0x8c, 0x56, 0x43, 0xd0, 0x34, 0x0e, 0x08, 0x51, 0x6c, + 0x86, 0x56, 0x4f, 0x82, 0x1e, 0xea, 0x5d, 0x34, 0x22, 0x82, 0xb7, 0x49, 0x1d, 0xd2, 0xd2, 0x36, + 0x33, 0xcd, 0x24, 0x62, 0xae, 0x1e, 0x3c, 0x2f, 0xbb, 0xbf, 0x61, 0xff, 0x4b, 0x8f, 0x85, 0xbd, + 0xec, 0x69, 0x59, 0xda, 0xfd, 0x21, 0x4b, 0x27, 0x49, 0x97, 0xed, 0xb6, 0xa5, 0xa7, 0xbc, 0x79, + 0xe7, 0xf9, 0x9a, 0x27, 0x81, 0x2f, 0x07, 0x5c, 0x4e, 0xb9, 0x24, 0x82, 0xc6, 0x74, 0x2a, 0xc9, + 0x9f, 0x6e, 0xc0, 0x12, 0xda, 0x25, 0xb3, 0x94, 0xc5, 0x99, 0x27, 0x62, 0x9e, 0x70, 0xd4, 0xca, + 0x21, 0x5e, 0x0e, 0xf1, 0x0a, 0x88, 0xf5, 0x24, 0xe4, 0x21, 0x57, 0x08, 0xb2, 0x9e, 0x72, 0xb0, + 0xf5, 0x3c, 0xe4, 0x3c, 0x9c, 0x30, 0x42, 0xc5, 0x88, 0xd0, 0x28, 0xe2, 0x09, 0x4d, 0x46, 0x3c, + 0x92, 0xc5, 0x29, 0xde, 0xed, 0x56, 0x28, 0x2b, 0x0c, 0xee, 0x43, 0xf4, 0x6d, 0xed, 0xfe, 0x55, + 0x2d, 0x7d, 0x36, 0x4b, 0x99, 0x4c, 0x90, 0x05, 0x1b, 0x32, 0x0d, 0xa4, 0xa0, 0x03, 0x66, 0x02, + 0x07, 0xb8, 0x86, 0xbf, 0x79, 0x47, 0x8f, 0x60, 0x65, 0xcc, 0x32, 0x53, 0x57, 0xeb, 0xf5, 0x88, + 0x7f, 0xc0, 0xc7, 0xf7, 0x34, 0xa4, 0xe0, 0x91, 0x64, 0xe8, 0x13, 0xac, 0x29, 0x2b, 0xa5, 0xd0, + 0xec, 0x61, 0x6f, 0xe7, 0xcd, 0x3c, 0xc5, 0xfa, 0x3c, 0xa4, 0x51, 0xc8, 0xfa, 0xd5, 0xf9, 0x55, + 0x5b, 0xf3, 0x73, 0x1a, 0x7e, 0x06, 0x5b, 0x4a, 0xf6, 0x7b, 0xe1, 0x5c, 0xa6, 0xc3, 0x3f, 0xe1, + 0xd3, 0xed, 0x83, 0xc2, 0xf2, 0x23, 0x34, 0xca, 0x9c, 0xd2, 0x04, 0x4e, 0xc5, 0x6d, 0xf6, 0xda, + 0x7b, 0x6c, 0x4b, 0xb2, 0x7f, 0xc7, 0xc0, 0x1f, 0x60, 0xa3, 0x5c, 0x1f, 0xac, 0x00, 0xc1, 0xea, + 0x98, 0x65, 0xd2, 0xd4, 0x9d, 0x8a, 0x6b, 0xf8, 0x6a, 0xee, 0x9d, 0xeb, 0xb0, 0xa6, 0x52, 0xa1, + 0xff, 0x00, 0xd6, 0xf3, 0x2a, 0xd0, 0xeb, 0x3d, 0xe6, 0x0f, 0x2b, 0xb7, 0xde, 0x1c, 0x03, 0xcd, + 0xaf, 0x89, 0x5f, 0xfd, 0xbb, 0xb8, 0x39, 0xd3, 0xdb, 0xe8, 0x05, 0x39, 0xf4, 0x85, 0xd1, 0x29, + 0x80, 0xc6, 0xa6, 0x23, 0xf4, 0xf6, 0x90, 0xc1, 0x76, 0xc7, 0x56, 0xe7, 0x48, 0x74, 0x91, 0xc8, + 0x55, 0x89, 0x30, 0x72, 0xf6, 0x24, 0xda, 0x74, 0xdc, 0xff, 0x32, 0x5f, 0xda, 0x60, 0xb1, 0xb4, + 0xc1, 0xf5, 0xd2, 0x06, 0x27, 0x2b, 0x5b, 0x5b, 0xac, 0x6c, 0xed, 0x72, 0x65, 0x6b, 0xbf, 0xde, + 0x87, 0xa3, 0x64, 0x98, 0x06, 0xde, 0x80, 0x4f, 0x4b, 0x95, 0xfc, 0xd1, 0x91, 0xbf, 0xc7, 0xe4, + 0x6f, 0x29, 0x99, 0x64, 0x82, 0x49, 0x22, 0x62, 0x2e, 0xb8, 0xa4, 0x93, 0xa0, 0xae, 0xfe, 0xe3, + 0x77, 0xb7, 0x01, 0x00, 0x00, 0xff, 0xff, 0x69, 0xa9, 0xbc, 0x11, 0x5b, 0x03, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -177,6 +323,8 @@ type QueryClient interface { // Params queries a specific parameter of a module, given its subspace and // key. Params(ctx context.Context, in *QueryParamsRequest, opts ...grpc.CallOption) (*QueryParamsResponse, error) + // Subspaces queries for all registered subspaces and all keys for a subspace. + Subspaces(ctx context.Context, in *QuerySubspacesRequest, opts ...grpc.CallOption) (*QuerySubspacesResponse, error) } type queryClient struct { @@ -196,11 +344,22 @@ func (c *queryClient) Params(ctx context.Context, in *QueryParamsRequest, opts . return out, nil } +func (c *queryClient) Subspaces(ctx context.Context, in *QuerySubspacesRequest, opts ...grpc.CallOption) (*QuerySubspacesResponse, error) { + out := new(QuerySubspacesResponse) + err := c.cc.Invoke(ctx, "/cosmos.params.v1beta1.Query/Subspaces", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // Params queries a specific parameter of a module, given its subspace and // key. Params(context.Context, *QueryParamsRequest) (*QueryParamsResponse, error) + // Subspaces queries for all registered subspaces and all keys for a subspace. + Subspaces(context.Context, *QuerySubspacesRequest) (*QuerySubspacesResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -210,6 +369,9 @@ type UnimplementedQueryServer struct { func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsRequest) (*QueryParamsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Params not implemented") } +func (*UnimplementedQueryServer) Subspaces(ctx context.Context, req *QuerySubspacesRequest) (*QuerySubspacesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method Subspaces not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -233,6 +395,24 @@ func _Query_Params_Handler(srv interface{}, ctx context.Context, dec func(interf return interceptor(ctx, in, info, handler) } +func _Query_Subspaces_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QuerySubspacesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).Subspaces(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cosmos.params.v1beta1.Query/Subspaces", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).Subspaces(ctx, req.(*QuerySubspacesRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "cosmos.params.v1beta1.Query", HandlerType: (*QueryServer)(nil), @@ -241,6 +421,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "Params", Handler: _Query_Params_Handler, }, + { + MethodName: "Subspaces", + Handler: _Query_Subspaces_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "cosmos/params/v1beta1/query.proto", @@ -316,6 +500,105 @@ func (m *QueryParamsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QuerySubspacesRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QuerySubspacesRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySubspacesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QuerySubspacesResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QuerySubspacesResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QuerySubspacesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Subspaces) > 0 { + for iNdEx := len(m.Subspaces) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Subspaces[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + +func (m *Subspace) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *Subspace) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Subspace) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Keys) > 0 { + for iNdEx := len(m.Keys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Keys[iNdEx]) + copy(dAtA[i:], m.Keys[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Keys[iNdEx]))) + i-- + dAtA[i] = 0x12 + } + } + if len(m.Subspace) > 0 { + i -= len(m.Subspace) + copy(dAtA[i:], m.Subspace) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Subspace))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -355,6 +638,49 @@ func (m *QueryParamsResponse) Size() (n int) { return n } +func (m *QuerySubspacesRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QuerySubspacesResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Subspaces) > 0 { + for _, e := range m.Subspaces { + l = e.Size() + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + +func (m *Subspace) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Subspace) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + if len(m.Keys) > 0 { + for _, s := range m.Keys { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } + return n +} + func sovQuery(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -558,6 +884,254 @@ func (m *QueryParamsResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *QuerySubspacesRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QuerySubspacesRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySubspacesRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QuerySubspacesResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QuerySubspacesResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QuerySubspacesResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Subspaces", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Subspaces = append(m.Subspaces, &Subspace{}) + if err := m.Subspaces[len(m.Subspaces)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *Subspace) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Subspace: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Subspace: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Subspace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Subspace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Keys", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Keys = append(m.Keys, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/params/types/proposal/query.pb.gw.go b/x/params/types/proposal/query.pb.gw.go index f5b9f9d5b686..dcb9c9443c0c 100644 --- a/x/params/types/proposal/query.pb.gw.go +++ b/x/params/types/proposal/query.pb.gw.go @@ -67,6 +67,24 @@ func local_request_Query_Params_0(ctx context.Context, marshaler runtime.Marshal } +func request_Query_Subspaces_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySubspacesRequest + var metadata runtime.ServerMetadata + + msg, err := client.Subspaces(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_Subspaces_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QuerySubspacesRequest + var metadata runtime.ServerMetadata + + msg, err := server.Subspaces(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -93,6 +111,26 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_Subspaces_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_Subspaces_0(rctx, inboundMarshaler, server, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Subspaces_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -154,13 +192,37 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_Subspaces_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_Subspaces_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_Subspaces_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } var ( pattern_Query_Params_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 1}, []string{"cosmos", "params", "v1beta1"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_Subspaces_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"cosmos", "params", "v1beta1", "subspaces"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( forward_Query_Params_0 = runtime.ForwardResponseMessage + + forward_Query_Subspaces_0 = runtime.ForwardResponseMessage ) diff --git a/x/params/types/subspace.go b/x/params/types/subspace.go index 42afe6cc9b21..541277dcf612 100644 --- a/x/params/types/subspace.go +++ b/x/params/types/subspace.go @@ -127,6 +127,22 @@ func (s Subspace) GetIfExists(ctx sdk.Context, key []byte, ptr interface{}) { } } +// IterateKeys iterates over all the keys in the subspace and executes the +// provided callback. If the callback returns true for a given key, iteration +// will halt. +func (s Subspace) IterateKeys(ctx sdk.Context, cb func(key []byte) bool) { + store := s.kvStore(ctx) + + iter := sdk.KVStorePrefixIterator(store, nil) + defer iter.Close() + + for ; iter.Valid(); iter.Next() { + if cb(iter.Key()) { + break + } + } +} + // GetRaw queries for the raw values bytes for a parameter by key. func (s Subspace) GetRaw(ctx sdk.Context, key []byte) []byte { store := s.kvStore(ctx) diff --git a/x/params/types/subspace_test.go b/x/params/types/subspace_test.go index 664c70df1801..d09e9c26b532 100644 --- a/x/params/types/subspace_test.go +++ b/x/params/types/subspace_test.go @@ -1,6 +1,7 @@ package types_test import ( + "bytes" "fmt" "testing" "time" @@ -92,6 +93,41 @@ func (suite *SubspaceTestSuite) TestGetRaw() { }) } +func (suite *SubspaceTestSuite) TestIterateKeys() { + suite.Require().NotPanics(func() { + suite.ss.Set(suite.ctx, keyUnbondingTime, time.Second) + }) + suite.Require().NotPanics(func() { + suite.ss.Set(suite.ctx, keyMaxValidators, uint16(50)) + }) + suite.Require().NotPanics(func() { + suite.ss.Set(suite.ctx, keyBondDenom, "stake") + }) + + var keys [][]byte + suite.ss.IterateKeys(suite.ctx, func(key []byte) bool { + keys = append(keys, key) + return false + }) + suite.Require().Len(keys, 3) + suite.Require().Contains(keys, keyUnbondingTime) + suite.Require().Contains(keys, keyMaxValidators) + suite.Require().Contains(keys, keyBondDenom) + + var keys2 [][]byte + suite.ss.IterateKeys(suite.ctx, func(key []byte) bool { + if bytes.Equal(key, keyUnbondingTime) { + return true + } + + keys2 = append(keys2, key) + return false + }) + suite.Require().Len(keys2, 2) + suite.Require().Contains(keys2, keyMaxValidators) + suite.Require().Contains(keys2, keyBondDenom) +} + func (suite *SubspaceTestSuite) TestHas() { t := time.Hour * 48