Skip to content

Commit 889979c

Browse files
authored
feat: Add cli for listing all module accounts (#242)
cref: cosmos#9812 ## Description This PR adds a CLI for querying all module accounts, `module-accounts`, in the auth module. Using this command would display all the account information, including human readable name of the module, module account address, account number, permissions, etc. This command would be especially useful for developers using cosmos-sdk as there are lots of instances where a developer would have to look into the module account, but only to do so by getting the module account address after getting the module name, hashing it and bech32fying it in the status quo. By using this command, users would be able to get a quick look on the list of all module accounts' information. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [x] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [x] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [x] reviewed tests and test coverage - [x] manually tested (if applicable)
1 parent 9a05fa0 commit 889979c

File tree

7 files changed

+617
-35
lines changed

7 files changed

+617
-35
lines changed

docs/core/proto-docs.md

Lines changed: 28 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+
- [QueryModuleAccountsRequest](#cosmos.auth.v1beta1.QueryModuleAccountsRequest)
25+
- [QueryModuleAccountsResponse](#cosmos.auth.v1beta1.QueryModuleAccountsResponse)
2426
- [QueryParamsRequest](#cosmos.auth.v1beta1.QueryParamsRequest)
2527
- [QueryParamsResponse](#cosmos.auth.v1beta1.QueryParamsResponse)
2628

@@ -840,6 +842,31 @@ Since: cosmos-sdk 0.43
840842

841843

842844

845+
<a name="cosmos.auth.v1beta1.QueryModuleAccountsRequest"></a>
846+
847+
### QueryModuleAccountsRequest
848+
QueryModuleAccountsRequest is the request type for the Query/ModuleAccounts RPC method.
849+
850+
851+
852+
853+
854+
855+
<a name="cosmos.auth.v1beta1.QueryModuleAccountsResponse"></a>
856+
857+
### QueryModuleAccountsResponse
858+
QueryModuleAccountsResponse is the response type for the Query/ModuleAccounts RPC method.
859+
860+
861+
| Field | Type | Label | Description |
862+
| ----- | ---- | ----- | ----------- |
863+
| `accounts` | [google.protobuf.Any](#google.protobuf.Any) | repeated | |
864+
865+
866+
867+
868+
869+
843870
<a name="cosmos.auth.v1beta1.QueryParamsRequest"></a>
844871

845872
### QueryParamsRequest
@@ -883,6 +910,7 @@ Query defines the gRPC querier service.
883910
Since: cosmos-sdk 0.43 | GET|/cosmos/auth/v1beta1/accounts|
884911
| `Account` | [QueryAccountRequest](#cosmos.auth.v1beta1.QueryAccountRequest) | [QueryAccountResponse](#cosmos.auth.v1beta1.QueryAccountResponse) | Account returns account details based on address. | GET|/cosmos/auth/v1beta1/accounts/{address}|
885912
| `Params` | [QueryParamsRequest](#cosmos.auth.v1beta1.QueryParamsRequest) | [QueryParamsResponse](#cosmos.auth.v1beta1.QueryParamsResponse) | Params queries all parameters. | GET|/cosmos/auth/v1beta1/params|
913+
| `ModuleAccounts` | [QueryModuleAccountsRequest](#cosmos.auth.v1beta1.QueryModuleAccountsRequest) | [QueryModuleAccountsResponse](#cosmos.auth.v1beta1.QueryModuleAccountsResponse) | ModuleAccounts returns all the existing Module Accounts. | GET|/cosmos/auth/v1beta1/module_accounts|
886914

887915
<!-- end services -->
888916

proto/cosmos/auth/v1beta1/query.proto

Lines changed: 13 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+
// ModuleAccounts returns all the existing module accounts.
33+
rpc ModuleAccounts(QueryModuleAccountsRequest) returns (QueryModuleAccountsResponse) {
34+
option (google.api.http).get = "/cosmos/auth/v1beta1/module_accounts";
35+
}
3136
}
3237

3338
// QueryAccountsRequest is the request type for the Query/Accounts RPC method.
@@ -72,3 +77,11 @@ message QueryParamsResponse {
7277
// params defines the parameters of the module.
7378
Params params = 1 [(gogoproto.nullable) = false];
7479
}
80+
81+
// QueryModuleAccountsRequest is the request type for the Query/ModuleAccounts RPC method.
82+
message QueryModuleAccountsRequest {}
83+
84+
// QueryModuleAccountsResponse is the response type for the Query/ModuleAccounts RPC method.
85+
message QueryModuleAccountsResponse {
86+
repeated google.protobuf.Any accounts = 1 [(cosmos_proto.accepts_interface) = "ModuleAccountI"];
87+
}

x/auth/client/cli/query.go

Lines changed: 29 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+
QueryModuleAccountsCmd(),
4648
)
4749

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

148+
// QueryAllModuleAccountsCmd returns a list of all the existing module accounts with their account information and permissions
149+
func QueryModuleAccountsCmd() *cobra.Command {
150+
cmd := &cobra.Command{
151+
Use: "module-accounts",
152+
Short: "Query all module accounts",
153+
RunE: func(cmd *cobra.Command, args []string) error {
154+
clientCtx, err := client.GetClientQueryContext(cmd)
155+
if err != nil {
156+
return err
157+
}
158+
159+
queryClient := types.NewQueryClient(clientCtx)
160+
161+
res, err := queryClient.ModuleAccounts(context.Background(), &types.QueryModuleAccountsRequest{})
162+
if err != nil {
163+
return err
164+
}
165+
166+
return clientCtx.PrintProto(res)
167+
},
168+
}
169+
170+
flags.AddQueryFlagsToCmd(cmd)
171+
172+
return cmd
173+
}
174+
146175
// QueryTxsByEventsCmd returns a command to search through transactions by events.
147176
func QueryTxsByEventsCmd() *cobra.Command {
148177
cmd := &cobra.Command{

x/auth/keeper/grpc_query.go

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

8484
return &types.QueryParamsResponse{Params: params}, nil
8585
}
86+
87+
// ModuleAccounts returns all the existing Module Accounts
88+
func (ak AccountKeeper) ModuleAccounts(c context.Context, req *types.QueryModuleAccountsRequest) (*types.QueryModuleAccountsResponse, error) {
89+
if req == nil {
90+
return nil, status.Error(codes.InvalidArgument, "empty request")
91+
}
92+
93+
ctx := sdk.UnwrapSDKContext(c)
94+
95+
modAccounts := make([]*codectypes.Any, 0, len(ak.permAddrs))
96+
97+
for moduleName := range ak.permAddrs {
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+
modAccounts = append(modAccounts, any)
107+
}
108+
109+
return &types.QueryModuleAccountsResponse{Accounts: modAccounts}, nil
110+
}

x/auth/keeper/grpc_query_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,84 @@ func (suite *KeeperTestSuite) TestGRPCQueryParameters() {
191191
})
192192
}
193193
}
194+
195+
func (suite *KeeperTestSuite) TestGRPCQueryModuleAccounts() {
196+
var (
197+
req *types.QueryModuleAccountsRequest
198+
)
199+
200+
testCases := []struct {
201+
msg string
202+
malleate func()
203+
expPass bool
204+
posttests func(res *types.QueryModuleAccountsResponse)
205+
}{
206+
{
207+
"success",
208+
func() {
209+
req = &types.QueryModuleAccountsRequest{}
210+
},
211+
true,
212+
func(res *types.QueryModuleAccountsResponse) {
213+
var mintModuleExists = false
214+
for _, acc := range res.Accounts {
215+
var account types.AccountI
216+
err := suite.app.InterfaceRegistry().UnpackAny(acc, &account)
217+
suite.Require().NoError(err)
218+
219+
moduleAccount, ok := account.(types.ModuleAccountI)
220+
221+
suite.Require().True(ok)
222+
if moduleAccount.GetName() == "mint" {
223+
mintModuleExists = true
224+
}
225+
}
226+
suite.Require().True(mintModuleExists)
227+
},
228+
},
229+
{
230+
"invalid module name",
231+
func() {
232+
req = &types.QueryModuleAccountsRequest{}
233+
},
234+
true,
235+
func(res *types.QueryModuleAccountsResponse) {
236+
var mintModuleExists = false
237+
for _, acc := range res.Accounts {
238+
var account types.AccountI
239+
err := suite.app.InterfaceRegistry().UnpackAny(acc, &account)
240+
suite.Require().NoError(err)
241+
242+
moduleAccount, ok := account.(types.ModuleAccountI)
243+
244+
suite.Require().True(ok)
245+
if moduleAccount.GetName() == "falseCase" {
246+
mintModuleExists = true
247+
}
248+
}
249+
suite.Require().False(mintModuleExists)
250+
},
251+
},
252+
}
253+
254+
for _, tc := range testCases {
255+
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
256+
suite.SetupTest() // reset
257+
258+
tc.malleate()
259+
ctx := sdk.WrapSDKContext(suite.ctx)
260+
261+
res, err := suite.queryClient.ModuleAccounts(ctx, req)
262+
263+
if tc.expPass {
264+
suite.Require().NoError(err)
265+
suite.Require().NotNil(res)
266+
} else {
267+
suite.Require().Error(err)
268+
suite.Require().Nil(res)
269+
}
270+
271+
tc.posttests(res)
272+
})
273+
}
274+
}

0 commit comments

Comments
 (0)