Skip to content

Commit f538e09

Browse files
mergify[bot]gsk967julienrbrt
authored
feat(cli): add module-account cli cmd and grpc get api (backport #13612) (#13616)
* feat(cli): add module-account cli cmd and grpc get api (#13612) (cherry picked from commit ddf5cf0) # Conflicts: # CHANGELOG.md # api/cosmos/auth/v1beta1/query.pulsar.go # api/cosmos/auth/v1beta1/query_grpc.pb.go # x/auth/client/testutil/suite.go # x/auth/types/query.pb.go * fix conflicts * updates * updates Co-authored-by: Sai Kumar <17549398+gsk967@users.noreply.github.com> Co-authored-by: Julien Robert <julien@rbrt.fr>
1 parent 7f88c60 commit f538e09

File tree

8 files changed

+907
-217
lines changed

8 files changed

+907
-217
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
3737

3838
## [Unreleased]
3939

40+
### Features
41+
42+
* (x/auth) [#13612](https://github.com/cosmos/cosmos-sdk/pull/13612) Add `Query/ModuleAccountByName` endpoint for accessing the module account info by module name.
43+
4044
## [v0.46.3](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.46.3) - 2022-10-20
4145

4246
ATTENTION:

proto/cosmos/auth/v1beta1/query.proto

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ service Query {
4343
option (google.api.http).get = "/cosmos/auth/v1beta1/module_accounts";
4444
}
4545

46+
// ModuleAccountByName returns the module account info by module name
47+
rpc ModuleAccountByName(QueryModuleAccountByNameRequest) returns (QueryModuleAccountByNameResponse) {
48+
option (google.api.http).get = "/cosmos/auth/v1beta1/module_accounts/{name}";
49+
}
50+
4651
// Bech32Prefix queries bech32Prefix
4752
//
4853
// Since: cosmos-sdk 0.46
@@ -93,17 +98,6 @@ message QueryAccountRequest {
9398
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
9499
}
95100

96-
// QueryModuleAccountsRequest is the request type for the Query/ModuleAccounts RPC method.
97-
//
98-
// Since: cosmos-sdk 0.46
99-
message QueryModuleAccountsRequest {}
100-
101-
// QueryParamsResponse is the response type for the Query/Params RPC method.
102-
message QueryParamsResponse {
103-
// params defines the parameters of the module.
104-
Params params = 1 [(gogoproto.nullable) = false];
105-
}
106-
107101
// QueryAccountResponse is the response type for the Query/Account RPC method.
108102
message QueryAccountResponse {
109103
// account defines the account of the corresponding address.
@@ -113,13 +107,34 @@ message QueryAccountResponse {
113107
// QueryParamsRequest is the request type for the Query/Params RPC method.
114108
message QueryParamsRequest {}
115109

110+
// QueryParamsResponse is the response type for the Query/Params RPC method.
111+
message QueryParamsResponse {
112+
// params defines the parameters of the module.
113+
Params params = 1 [(gogoproto.nullable) = false];
114+
}
115+
116+
// QueryModuleAccountsRequest is the request type for the Query/ModuleAccounts RPC method.
117+
//
118+
// Since: cosmos-sdk 0.46
119+
message QueryModuleAccountsRequest {}
120+
116121
// QueryModuleAccountsResponse is the response type for the Query/ModuleAccounts RPC method.
117122
//
118123
// Since: cosmos-sdk 0.46
119124
message QueryModuleAccountsResponse {
120125
repeated google.protobuf.Any accounts = 1 [(cosmos_proto.accepts_interface) = "ModuleAccountI"];
121126
}
122127

128+
// QueryModuleAccountByNameRequest is the request type for the Query/ModuleAccountByName RPC method.
129+
message QueryModuleAccountByNameRequest {
130+
string name = 1;
131+
}
132+
133+
// QueryModuleAccountByNameResponse is the response type for the Query/ModuleAccountByName RPC method.
134+
message QueryModuleAccountByNameResponse {
135+
google.protobuf.Any account = 1 [(cosmos_proto.accepts_interface) = "ModuleAccountI"];
136+
}
137+
123138
// Bech32PrefixRequest is the request type for Bech32Prefix rpc method.
124139
//
125140
// Since: cosmos-sdk 0.46

x/auth/client/cli/query.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func GetQueryCmd() *cobra.Command {
4646
GetAccountsCmd(),
4747
QueryParamsCmd(),
4848
QueryModuleAccountsCmd(),
49+
QueryModuleAccountByNameCmd(),
4950
)
5051

5152
return cmd
@@ -219,6 +220,40 @@ func QueryModuleAccountsCmd() *cobra.Command {
219220
return cmd
220221
}
221222

223+
// QueryModuleAccountByNameCmd returns a command to
224+
func QueryModuleAccountByNameCmd() *cobra.Command {
225+
cmd := &cobra.Command{
226+
Use: "module-account [module-name]",
227+
Short: "Query module account info by module name",
228+
Args: cobra.ExactArgs(1),
229+
Example: fmt.Sprintf("%s q auth module-account auth", version.AppName),
230+
RunE: func(cmd *cobra.Command, args []string) error {
231+
clientCtx, err := client.GetClientQueryContext(cmd)
232+
if err != nil {
233+
return err
234+
}
235+
236+
moduleName := args[0]
237+
if len(moduleName) == 0 {
238+
return fmt.Errorf("module name should not be empty")
239+
}
240+
241+
queryClient := types.NewQueryClient(clientCtx)
242+
243+
res, err := queryClient.ModuleAccountByName(context.Background(), &types.QueryModuleAccountByNameRequest{Name: moduleName})
244+
if err != nil {
245+
return err
246+
}
247+
248+
return clientCtx.PrintProto(res)
249+
},
250+
}
251+
252+
flags.AddQueryFlagsToCmd(cmd)
253+
254+
return cmd
255+
}
256+
222257
// QueryTxsByEventsCmd returns a command to search through transactions by events.
223258
func QueryTxsByEventsCmd() *cobra.Command {
224259
cmd := &cobra.Command{

x/auth/client/testutil/suite.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1391,6 +1391,68 @@ func (s *IntegrationTestSuite) TestGetAccountsCmd() {
13911391
s.Require().NotEmpty(res.Accounts)
13921392
}
13931393

1394+
func (s *IntegrationTestSuite) TestQueryModuleAccountByNameCmd() {
1395+
val := s.network.Validators[0]
1396+
1397+
testCases := []struct {
1398+
name string
1399+
moduleName string
1400+
expectErr bool
1401+
}{
1402+
{
1403+
"invalid module name",
1404+
"gover",
1405+
true,
1406+
},
1407+
{
1408+
"valid module name",
1409+
"mint",
1410+
false,
1411+
},
1412+
}
1413+
1414+
for _, tc := range testCases {
1415+
tc := tc
1416+
s.Run(tc.name, func() {
1417+
clientCtx := val.ClientCtx
1418+
1419+
out, err := clitestutil.ExecTestCLICmd(clientCtx, authcli.QueryModuleAccountByNameCmd(), []string{
1420+
tc.moduleName,
1421+
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
1422+
})
1423+
if tc.expectErr {
1424+
s.Require().Error(err)
1425+
s.Require().NotEqual("internal", err.Error())
1426+
} else {
1427+
var res authtypes.QueryModuleAccountByNameResponse
1428+
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
1429+
1430+
var account authtypes.AccountI
1431+
err := val.ClientCtx.InterfaceRegistry.UnpackAny(res.Account, &account)
1432+
s.Require().NoError(err)
1433+
1434+
moduleAccount, ok := account.(authtypes.ModuleAccountI)
1435+
s.Require().True(ok)
1436+
s.Require().Equal(tc.moduleName, moduleAccount.GetName())
1437+
}
1438+
})
1439+
}
1440+
}
1441+
1442+
func (s *IntegrationTestSuite) TestQueryModuleAccountsCmd() {
1443+
val := s.network.Validators[0]
1444+
clientCtx := val.ClientCtx
1445+
1446+
out, err := clitestutil.ExecTestCLICmd(clientCtx, authcli.QueryModuleAccountsCmd(), []string{
1447+
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
1448+
})
1449+
s.Require().NoError(err)
1450+
1451+
var res authtypes.QueryModuleAccountsResponse
1452+
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
1453+
s.Require().NotEmpty(res.Accounts)
1454+
}
1455+
13941456
func TestGetBroadcastCommandOfflineFlag(t *testing.T) {
13951457
clientCtx := client.Context{}.WithOffline(true)
13961458
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
@@ -135,6 +135,31 @@ func (ak AccountKeeper) ModuleAccounts(c context.Context, req *types.QueryModule
135135
return &types.QueryModuleAccountsResponse{Accounts: modAccounts}, nil
136136
}
137137

138+
// ModuleAccountByName returns module account by module name
139+
func (ak AccountKeeper) ModuleAccountByName(c context.Context, req *types.QueryModuleAccountByNameRequest) (*types.QueryModuleAccountByNameResponse, error) {
140+
if req == nil {
141+
return nil, status.Errorf(codes.InvalidArgument, "empty request")
142+
}
143+
144+
if len(req.Name) == 0 {
145+
return nil, status.Error(codes.InvalidArgument, "module name is empty")
146+
}
147+
148+
ctx := sdk.UnwrapSDKContext(c)
149+
moduleName := req.Name
150+
151+
account := ak.GetModuleAccount(ctx, moduleName)
152+
if account == nil {
153+
return nil, status.Errorf(codes.NotFound, "account %s not found", moduleName)
154+
}
155+
any, err := codectypes.NewAnyWithValue(account)
156+
if err != nil {
157+
return nil, status.Errorf(codes.Internal, err.Error())
158+
}
159+
160+
return &types.QueryModuleAccountByNameResponse{Account: any}, nil
161+
}
162+
138163
// Bech32Prefix returns the keeper internally stored bech32 prefix.
139164
func (ak AccountKeeper) Bech32Prefix(ctx context.Context, req *types.Bech32PrefixRequest) (*types.Bech32PrefixResponse, error) {
140165
bech32Prefix, err := ak.getBech32Prefix()

x/auth/keeper/grpc_query_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,61 @@ func (suite *KeeperTestSuite) TestGRPCQueryModuleAccounts() {
348348
}
349349
}
350350

351+
func (suite *KeeperTestSuite) TestGRPCQueryModuleAccountByName() {
352+
var req *types.QueryModuleAccountByNameRequest
353+
354+
testCases := []struct {
355+
msg string
356+
malleate func()
357+
expPass bool
358+
posttests func(res *types.QueryModuleAccountByNameResponse)
359+
}{
360+
{
361+
"success",
362+
func() {
363+
req = &types.QueryModuleAccountByNameRequest{Name: "mint"}
364+
},
365+
true,
366+
func(res *types.QueryModuleAccountByNameResponse) {
367+
var account types.AccountI
368+
err := suite.app.InterfaceRegistry().UnpackAny(res.Account, &account)
369+
suite.Require().NoError(err)
370+
371+
moduleAccount, ok := account.(types.ModuleAccountI)
372+
suite.Require().True(ok)
373+
suite.Require().Equal(moduleAccount.GetName(), "mint")
374+
},
375+
},
376+
{
377+
"invalid module name",
378+
func() {
379+
req = &types.QueryModuleAccountByNameRequest{Name: "gover"}
380+
},
381+
false,
382+
func(res *types.QueryModuleAccountByNameResponse) {
383+
},
384+
},
385+
}
386+
387+
for _, tc := range testCases {
388+
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
389+
suite.SetupTest() // reset
390+
tc.malleate()
391+
ctx := sdk.WrapSDKContext(suite.ctx)
392+
res, err := suite.queryClient.ModuleAccountByName(ctx, req)
393+
if tc.expPass {
394+
suite.Require().NoError(err)
395+
suite.Require().NotNil(res)
396+
} else {
397+
suite.Require().Error(err)
398+
suite.Require().Nil(res)
399+
}
400+
401+
tc.posttests(res)
402+
})
403+
}
404+
}
405+
351406
func (suite *KeeperTestSuite) TestBech32Prefix() {
352407
suite.SetupTest() // reset
353408
req := &types.Bech32PrefixRequest{}

0 commit comments

Comments
 (0)