Skip to content

Commit

Permalink
feat(cli): add module-account cli cmd and grpc get api (backport #13612
Browse files Browse the repository at this point in the history
…) (#13617)

* 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
#	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>
  • Loading branch information
3 people authored Oct 24, 2022
1 parent 3f29739 commit e972b64
Show file tree
Hide file tree
Showing 9 changed files with 741 additions and 35 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

* (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).
* [#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.
* (x/auth) [#13612](https://github.com/cosmos/cosmos-sdk/pull/13612) Add `Query/ModuleAccountByName` endpoint for accessing the module account info by module name.

### Improvements

Expand Down
33 changes: 33 additions & 0 deletions docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
- [QueryAccountResponse](#cosmos.auth.v1beta1.QueryAccountResponse)
- [QueryAccountsRequest](#cosmos.auth.v1beta1.QueryAccountsRequest)
- [QueryAccountsResponse](#cosmos.auth.v1beta1.QueryAccountsResponse)
- [QueryModuleAccountByNameRequest](#cosmos.auth.v1beta1.QueryModuleAccountByNameRequest)
- [QueryModuleAccountByNameResponse](#cosmos.auth.v1beta1.QueryModuleAccountByNameResponse)
- [QueryParamsRequest](#cosmos.auth.v1beta1.QueryParamsRequest)
- [QueryParamsResponse](#cosmos.auth.v1beta1.QueryParamsResponse)

Expand Down Expand Up @@ -846,6 +848,36 @@ Since: cosmos-sdk 0.43



<a name="cosmos.auth.v1beta1.QueryModuleAccountByNameRequest"></a>

### QueryModuleAccountByNameRequest
QueryModuleAccountByNameRequest is the request type for the Query/ModuleAccountByName RPC method.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `name` | [string](#string) | | |






<a name="cosmos.auth.v1beta1.QueryModuleAccountByNameResponse"></a>

### QueryModuleAccountByNameResponse
QueryModuleAccountByNameResponse is the response type for the Query/ModuleAccountByName RPC method.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `account` | [google.protobuf.Any](#google.protobuf.Any) | | |






<a name="cosmos.auth.v1beta1.QueryParamsRequest"></a>

### QueryParamsRequest
Expand Down Expand Up @@ -889,6 +921,7 @@ Query defines the gRPC querier service.
Since: cosmos-sdk 0.43 | 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|
| `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}|

<!-- end services -->

Expand Down
15 changes: 15 additions & 0 deletions proto/cosmos/auth/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ service Query {
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/cosmos/auth/v1beta1/params";
}

// ModuleAccountByName returns the module account info by module name
rpc ModuleAccountByName(QueryModuleAccountByNameRequest) returns (QueryModuleAccountByNameResponse) {
option (google.api.http).get = "/cosmos/auth/v1beta1/module_accounts/{name}";
}
}

// QueryAccountsRequest is the request type for the Query/Accounts RPC method.
Expand Down Expand Up @@ -72,3 +77,13 @@ message QueryParamsResponse {
// params defines the parameters of the module.
Params params = 1 [(gogoproto.nullable) = false];
}

// QueryModuleAccountByNameRequest is the request type for the Query/ModuleAccountByName RPC method.
message QueryModuleAccountByNameRequest {
string name = 1;
}

// QueryModuleAccountByNameResponse is the response type for the Query/ModuleAccountByName RPC method.
message QueryModuleAccountByNameResponse {
google.protobuf.Any account = 1 [(cosmos_proto.accepts_interface) = "ModuleAccountI"];
}
36 changes: 36 additions & 0 deletions x/auth/client/cli/query.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"context"
"fmt"
"strings"

Expand Down Expand Up @@ -43,6 +44,7 @@ func GetQueryCmd() *cobra.Command {
GetAccountCmd(),
GetAccountsCmd(),
QueryParamsCmd(),
QueryModuleAccountByNameCmd(),
)

return cmd
Expand Down Expand Up @@ -143,6 +145,40 @@ func GetAccountsCmd() *cobra.Command {
return cmd
}

// QueryModuleAccountByNameCmd returns a command to
func QueryModuleAccountByNameCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "module-account [module-name]",
Short: "Query module account info by module name",
Args: cobra.ExactArgs(1),
Example: fmt.Sprintf("%s q auth module-account auth", version.AppName),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

moduleName := args[0]
if len(moduleName) == 0 {
return fmt.Errorf("module name should not be empty")
}

queryClient := types.NewQueryClient(clientCtx)

res, err := queryClient.ModuleAccountByName(context.Background(), &types.QueryModuleAccountByNameRequest{Name: moduleName})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// QueryTxsByEventsCmd returns a command to search through transactions by events.
func QueryTxsByEventsCmd() *cobra.Command {
cmd := &cobra.Command{
Expand Down
48 changes: 48 additions & 0 deletions x/auth/client/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -1131,6 +1131,54 @@ func (s *IntegrationTestSuite) TestGetAccountsCmd() {
s.Require().NotEmpty(res.Accounts)
}

func (s *IntegrationTestSuite) TestQueryModuleAccountByNameCmd() {
val := s.network.Validators[0]

testCases := []struct {
name string
moduleName string
expectErr bool
}{
{
"invalid module name",
"gover",
true,
},
{
"valid module name",
"mint",
false,
},
}

for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
clientCtx := val.ClientCtx

out, err := clitestutil.ExecTestCLICmd(clientCtx, authcli.QueryModuleAccountByNameCmd(), []string{
tc.moduleName,
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
})
if tc.expectErr {
s.Require().Error(err)
s.Require().NotEqual("internal", err.Error())
} else {
var res authtypes.QueryModuleAccountByNameResponse
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))

var account authtypes.AccountI
err := val.ClientCtx.InterfaceRegistry.UnpackAny(res.Account, &account)
s.Require().NoError(err)

moduleAccount, ok := account.(authtypes.ModuleAccountI)
s.Require().True(ok)
s.Require().Equal(tc.moduleName, moduleAccount.GetName())
}
})
}
}

func TestGetBroadcastCommandOfflineFlag(t *testing.T) {
clientCtx := client.Context{}.WithOffline(true)
clientCtx = clientCtx.WithTxConfig(simapp.MakeTestEncodingConfig().TxConfig) //nolint:staticcheck
Expand Down
25 changes: 25 additions & 0 deletions x/auth/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,28 @@ func (ak AccountKeeper) Params(c context.Context, req *types.QueryParamsRequest)

return &types.QueryParamsResponse{Params: params}, nil
}

// ModuleAccountByName returns module account by module name
func (ak AccountKeeper) ModuleAccountByName(c context.Context, req *types.QueryModuleAccountByNameRequest) (*types.QueryModuleAccountByNameResponse, error) {
if req == nil {
return nil, status.Errorf(codes.InvalidArgument, "empty request")
}

if len(req.Name) == 0 {
return nil, status.Error(codes.InvalidArgument, "module name is empty")
}

ctx := sdk.UnwrapSDKContext(c)
moduleName := req.Name

account := ak.GetModuleAccount(ctx, moduleName)
if account == nil {
return nil, status.Errorf(codes.NotFound, "account %s not found", moduleName)
}
any, err := codectypes.NewAnyWithValue(account)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}

return &types.QueryModuleAccountByNameResponse{Account: any}, nil
}
55 changes: 55 additions & 0 deletions x/auth/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,3 +187,58 @@ func (suite *KeeperTestSuite) TestGRPCQueryParameters() {
})
}
}

func (suite *KeeperTestSuite) TestGRPCQueryModuleAccountByName() {
var req *types.QueryModuleAccountByNameRequest

testCases := []struct {
msg string
malleate func()
expPass bool
posttests func(res *types.QueryModuleAccountByNameResponse)
}{
{
"success",
func() {
req = &types.QueryModuleAccountByNameRequest{Name: "mint"}
},
true,
func(res *types.QueryModuleAccountByNameResponse) {
var account types.AccountI
err := suite.app.InterfaceRegistry().UnpackAny(res.Account, &account)
suite.Require().NoError(err)

moduleAccount, ok := account.(types.ModuleAccountI)
suite.Require().True(ok)
suite.Require().Equal(moduleAccount.GetName(), "mint")
},
},
{
"invalid module name",
func() {
req = &types.QueryModuleAccountByNameRequest{Name: "gover"}
},
false,
func(res *types.QueryModuleAccountByNameResponse) {
},
},
}

for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.ctx)
res, err := suite.queryClient.ModuleAccountByName(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
} else {
suite.Require().Error(err)
suite.Require().Nil(res)
}

tc.posttests(res)
})
}
}
Loading

0 comments on commit e972b64

Please sign in to comment.