Skip to content

Commit 393b1b7

Browse files
mergify[bot]gsk967julienrbrt
authored andcommitted
feat(cli): add module-account cli cmd and grpc get api (backport cosmos#13612) (cosmos#13617)
* feat(cli): add module-account cli cmd and grpc get api (cosmos#13612) (cherry picked from commit ddf5cf0) # Conflicts: # CHANGELOG.md # api/cosmos/auth/v1beta1/query.pulsar.go # api/cosmos/auth/v1beta1/query_grpc.pb.go # proto/cosmos/auth/v1beta1/query.proto # tests/e2e/auth/suite.go # x/auth/client/cli/query.go # x/auth/keeper/grpc_query.go # x/auth/keeper/grpc_query_test.go # x/auth/types/query.pb.go # x/auth/types/query.pb.gw.go * update changelog * fix conflicts Co-authored-by: Sai Kumar <17549398+gsk967@users.noreply.github.com> Co-authored-by: Julien Robert <julien@rbrt.fr>
1 parent d6abbdb commit 393b1b7

File tree

9 files changed

+741
-35
lines changed

9 files changed

+741
-35
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
4141

4242
* (grpc) [#13485](https://github.com/cosmos/cosmos-sdk/pull/13485) Implement a new gRPC query, `/cosmos/base/node/v1beta1/config`, which provides operator configuration. Applications that wish to expose operator minimum gas prices via gRPC should have their application implement the `ApplicationQueryService` interface (see `SimApp#RegisterNodeService` as an example).
4343
* [#13557](https://github.com/cosmos/cosmos-sdk/pull/#13557) - Add `GenSignedMockTx`. This can be used as workaround for #12437 revertion. `v0.46+` contains as well a `GenSignedMockTx` that behaves the same way.
44+
* (x/auth) [#13612](https://github.com/cosmos/cosmos-sdk/pull/13612) Add `Query/ModuleAccountByName` endpoint for accessing the module account info by module name.
4445

4546
### Improvements
4647

docs/core/proto-docs.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
- [QueryAccountResponse](#cosmos.auth.v1beta1.QueryAccountResponse)
2222
- [QueryAccountsRequest](#cosmos.auth.v1beta1.QueryAccountsRequest)
2323
- [QueryAccountsResponse](#cosmos.auth.v1beta1.QueryAccountsResponse)
24+
- [QueryModuleAccountByNameRequest](#cosmos.auth.v1beta1.QueryModuleAccountByNameRequest)
25+
- [QueryModuleAccountByNameResponse](#cosmos.auth.v1beta1.QueryModuleAccountByNameResponse)
2426
- [QueryParamsRequest](#cosmos.auth.v1beta1.QueryParamsRequest)
2527
- [QueryParamsResponse](#cosmos.auth.v1beta1.QueryParamsResponse)
2628

@@ -846,6 +848,36 @@ Since: cosmos-sdk 0.43
846848

847849

848850

851+
<a name="cosmos.auth.v1beta1.QueryModuleAccountByNameRequest"></a>
852+
853+
### QueryModuleAccountByNameRequest
854+
QueryModuleAccountByNameRequest is the request type for the Query/ModuleAccountByName RPC method.
855+
856+
857+
| Field | Type | Label | Description |
858+
| ----- | ---- | ----- | ----------- |
859+
| `name` | [string](#string) | | |
860+
861+
862+
863+
864+
865+
866+
<a name="cosmos.auth.v1beta1.QueryModuleAccountByNameResponse"></a>
867+
868+
### QueryModuleAccountByNameResponse
869+
QueryModuleAccountByNameResponse is the response type for the Query/ModuleAccountByName RPC method.
870+
871+
872+
| Field | Type | Label | Description |
873+
| ----- | ---- | ----- | ----------- |
874+
| `account` | [google.protobuf.Any](#google.protobuf.Any) | | |
875+
876+
877+
878+
879+
880+
849881
<a name="cosmos.auth.v1beta1.QueryParamsRequest"></a>
850882

851883
### QueryParamsRequest
@@ -889,6 +921,7 @@ Query defines the gRPC querier service.
889921
Since: cosmos-sdk 0.43 | GET|/cosmos/auth/v1beta1/accounts|
890922
| `Account` | [QueryAccountRequest](#cosmos.auth.v1beta1.QueryAccountRequest) | [QueryAccountResponse](#cosmos.auth.v1beta1.QueryAccountResponse) | Account returns account details based on address. | GET|/cosmos/auth/v1beta1/accounts/{address}|
891923
| `Params` | [QueryParamsRequest](#cosmos.auth.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#cosmos.auth.v1beta1.QueryParamsResponse) | Params queries all parameters. | GET|/cosmos/auth/v1beta1/params|
924+
| `ModuleAccountByName` | [QueryModuleAccountByNameRequest](#cosmos.auth.v1beta1.QueryModuleAccountByNameRequest) | [QueryModuleAccountByNameResponse](#cosmos.auth.v1beta1.QueryModuleAccountByNameResponse) | ModuleAccountByName returns the module account info by module name | GET|/cosmos/auth/v1beta1/module_accounts/{name}|
892925

893926
<!-- end services -->
894927

proto/cosmos/auth/v1beta1/query.proto

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ service Query {
2828
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
2929
option (google.api.http).get = "/cosmos/auth/v1beta1/params";
3030
}
31+
32+
// ModuleAccountByName returns the module account info by module name
33+
rpc ModuleAccountByName(QueryModuleAccountByNameRequest) returns (QueryModuleAccountByNameResponse) {
34+
option (google.api.http).get = "/cosmos/auth/v1beta1/module_accounts/{name}";
35+
}
3136
}
3237

3338
// QueryAccountsRequest is the request type for the Query/Accounts RPC method.
@@ -72,3 +77,13 @@ message QueryParamsResponse {
7277
// params defines the parameters of the module.
7378
Params params = 1 [(gogoproto.nullable) = false];
7479
}
80+
81+
// QueryModuleAccountByNameRequest is the request type for the Query/ModuleAccountByName RPC method.
82+
message QueryModuleAccountByNameRequest {
83+
string name = 1;
84+
}
85+
86+
// QueryModuleAccountByNameResponse is the response type for the Query/ModuleAccountByName RPC method.
87+
message QueryModuleAccountByNameResponse {
88+
google.protobuf.Any account = 1 [(cosmos_proto.accepts_interface) = "ModuleAccountI"];
89+
}

x/auth/client/cli/query.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cli
22

33
import (
4+
"context"
45
"fmt"
56
"strings"
67

@@ -43,6 +44,7 @@ func GetQueryCmd() *cobra.Command {
4344
GetAccountCmd(),
4445
GetAccountsCmd(),
4546
QueryParamsCmd(),
47+
QueryModuleAccountByNameCmd(),
4648
)
4749

4850
return cmd
@@ -143,6 +145,40 @@ func GetAccountsCmd() *cobra.Command {
143145
return cmd
144146
}
145147

148+
// QueryModuleAccountByNameCmd returns a command to
149+
func QueryModuleAccountByNameCmd() *cobra.Command {
150+
cmd := &cobra.Command{
151+
Use: "module-account [module-name]",
152+
Short: "Query module account info by module name",
153+
Args: cobra.ExactArgs(1),
154+
Example: fmt.Sprintf("%s q auth module-account auth", version.AppName),
155+
RunE: func(cmd *cobra.Command, args []string) error {
156+
clientCtx, err := client.GetClientQueryContext(cmd)
157+
if err != nil {
158+
return err
159+
}
160+
161+
moduleName := args[0]
162+
if len(moduleName) == 0 {
163+
return fmt.Errorf("module name should not be empty")
164+
}
165+
166+
queryClient := types.NewQueryClient(clientCtx)
167+
168+
res, err := queryClient.ModuleAccountByName(context.Background(), &types.QueryModuleAccountByNameRequest{Name: moduleName})
169+
if err != nil {
170+
return err
171+
}
172+
173+
return clientCtx.PrintProto(res)
174+
},
175+
}
176+
177+
flags.AddQueryFlagsToCmd(cmd)
178+
179+
return cmd
180+
}
181+
146182
// QueryTxsByEventsCmd returns a command to search through transactions by events.
147183
func QueryTxsByEventsCmd() *cobra.Command {
148184
cmd := &cobra.Command{

x/auth/client/testutil/suite.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,54 @@ func (s *IntegrationTestSuite) TestGetAccountsCmd() {
11311131
s.Require().NotEmpty(res.Accounts)
11321132
}
11331133

1134+
func (s *IntegrationTestSuite) TestQueryModuleAccountByNameCmd() {
1135+
val := s.network.Validators[0]
1136+
1137+
testCases := []struct {
1138+
name string
1139+
moduleName string
1140+
expectErr bool
1141+
}{
1142+
{
1143+
"invalid module name",
1144+
"gover",
1145+
true,
1146+
},
1147+
{
1148+
"valid module name",
1149+
"mint",
1150+
false,
1151+
},
1152+
}
1153+
1154+
for _, tc := range testCases {
1155+
tc := tc
1156+
s.Run(tc.name, func() {
1157+
clientCtx := val.ClientCtx
1158+
1159+
out, err := clitestutil.ExecTestCLICmd(clientCtx, authcli.QueryModuleAccountByNameCmd(), []string{
1160+
tc.moduleName,
1161+
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
1162+
})
1163+
if tc.expectErr {
1164+
s.Require().Error(err)
1165+
s.Require().NotEqual("internal", err.Error())
1166+
} else {
1167+
var res authtypes.QueryModuleAccountByNameResponse
1168+
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
1169+
1170+
var account authtypes.AccountI
1171+
err := val.ClientCtx.InterfaceRegistry.UnpackAny(res.Account, &account)
1172+
s.Require().NoError(err)
1173+
1174+
moduleAccount, ok := account.(authtypes.ModuleAccountI)
1175+
s.Require().True(ok)
1176+
s.Require().Equal(tc.moduleName, moduleAccount.GetName())
1177+
}
1178+
})
1179+
}
1180+
}
1181+
11341182
func TestGetBroadcastCommandOfflineFlag(t *testing.T) {
11351183
clientCtx := client.Context{}.WithOffline(true)
11361184
clientCtx = clientCtx.WithTxConfig(simapp.MakeTestEncodingConfig().TxConfig) //nolint:staticcheck

x/auth/keeper/grpc_query.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,28 @@ func (ak AccountKeeper) Params(c context.Context, req *types.QueryParamsRequest)
8181

8282
return &types.QueryParamsResponse{Params: params}, nil
8383
}
84+
85+
// ModuleAccountByName returns module account by module name
86+
func (ak AccountKeeper) ModuleAccountByName(c context.Context, req *types.QueryModuleAccountByNameRequest) (*types.QueryModuleAccountByNameResponse, error) {
87+
if req == nil {
88+
return nil, status.Errorf(codes.InvalidArgument, "empty request")
89+
}
90+
91+
if len(req.Name) == 0 {
92+
return nil, status.Error(codes.InvalidArgument, "module name is empty")
93+
}
94+
95+
ctx := sdk.UnwrapSDKContext(c)
96+
moduleName := req.Name
97+
98+
account := ak.GetModuleAccount(ctx, moduleName)
99+
if account == nil {
100+
return nil, status.Errorf(codes.NotFound, "account %s not found", moduleName)
101+
}
102+
any, err := codectypes.NewAnyWithValue(account)
103+
if err != nil {
104+
return nil, status.Errorf(codes.Internal, err.Error())
105+
}
106+
107+
return &types.QueryModuleAccountByNameResponse{Account: any}, nil
108+
}

x/auth/keeper/grpc_query_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,58 @@ func (suite *KeeperTestSuite) TestGRPCQueryParameters() {
187187
})
188188
}
189189
}
190+
191+
func (suite *KeeperTestSuite) TestGRPCQueryModuleAccountByName() {
192+
var req *types.QueryModuleAccountByNameRequest
193+
194+
testCases := []struct {
195+
msg string
196+
malleate func()
197+
expPass bool
198+
posttests func(res *types.QueryModuleAccountByNameResponse)
199+
}{
200+
{
201+
"success",
202+
func() {
203+
req = &types.QueryModuleAccountByNameRequest{Name: "mint"}
204+
},
205+
true,
206+
func(res *types.QueryModuleAccountByNameResponse) {
207+
var account types.AccountI
208+
err := suite.app.InterfaceRegistry().UnpackAny(res.Account, &account)
209+
suite.Require().NoError(err)
210+
211+
moduleAccount, ok := account.(types.ModuleAccountI)
212+
suite.Require().True(ok)
213+
suite.Require().Equal(moduleAccount.GetName(), "mint")
214+
},
215+
},
216+
{
217+
"invalid module name",
218+
func() {
219+
req = &types.QueryModuleAccountByNameRequest{Name: "gover"}
220+
},
221+
false,
222+
func(res *types.QueryModuleAccountByNameResponse) {
223+
},
224+
},
225+
}
226+
227+
for _, tc := range testCases {
228+
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
229+
suite.SetupTest() // reset
230+
tc.malleate()
231+
ctx := sdk.WrapSDKContext(suite.ctx)
232+
res, err := suite.queryClient.ModuleAccountByName(ctx, req)
233+
if tc.expPass {
234+
suite.Require().NoError(err)
235+
suite.Require().NotNil(res)
236+
} else {
237+
suite.Require().Error(err)
238+
suite.Require().Nil(res)
239+
}
240+
241+
tc.posttests(res)
242+
})
243+
}
244+
}

0 commit comments

Comments
 (0)