Skip to content

Commit

Permalink
feat(cli): add module-account cli cmd and grpc get api (#13612)
Browse files Browse the repository at this point in the history
(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
  • Loading branch information
gsk967 authored and mergify[bot] committed Oct 22, 2022
1 parent 7f88c60 commit 96ea326
Show file tree
Hide file tree
Showing 10 changed files with 11,498 additions and 160 deletions.
148 changes: 148 additions & 0 deletions CHANGELOG.md

Large diffs are not rendered by default.

9,847 changes: 9,847 additions & 0 deletions api/cosmos/auth/v1beta1/query.pulsar.go

Large diffs are not rendered by default.

483 changes: 483 additions & 0 deletions api/cosmos/auth/v1beta1/query_grpc.pb.go

Large diffs are not rendered by default.

38 changes: 27 additions & 11 deletions proto/cosmos/auth/v1beta1/query.proto
Expand Up @@ -43,6 +43,12 @@ service Query {
option (google.api.http).get = "/cosmos/auth/v1beta1/module_accounts";
}

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

// Bech32Prefix queries bech32Prefix
//
// Since: cosmos-sdk 0.46
Expand Down Expand Up @@ -93,17 +99,6 @@ message QueryAccountRequest {
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

// QueryModuleAccountsRequest is the request type for the Query/ModuleAccounts RPC method.
//
// Since: cosmos-sdk 0.46
message QueryModuleAccountsRequest {}

// QueryParamsResponse is the response type for the Query/Params RPC method.
message QueryParamsResponse {
// params defines the parameters of the module.
Params params = 1 [(gogoproto.nullable) = false];
}

// QueryAccountResponse is the response type for the Query/Account RPC method.
message QueryAccountResponse {
// account defines the account of the corresponding address.
Expand All @@ -113,13 +108,34 @@ message QueryAccountResponse {
// QueryParamsRequest is the request type for the Query/Params RPC method.
message QueryParamsRequest {}

// QueryParamsResponse is the response type for the Query/Params RPC method.
message QueryParamsResponse {
// params defines the parameters of the module.
Params params = 1 [(gogoproto.nullable) = false];
}

// QueryModuleAccountsRequest is the request type for the Query/ModuleAccounts RPC method.
//
// Since: cosmos-sdk 0.46
message QueryModuleAccountsRequest {}

// QueryModuleAccountsResponse is the response type for the Query/ModuleAccounts RPC method.
//
// Since: cosmos-sdk 0.46
message QueryModuleAccountsResponse {
repeated google.protobuf.Any accounts = 1 [(cosmos_proto.accepts_interface) = "ModuleAccountI"];
}

// 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"];
}

// Bech32PrefixRequest is the request type for Bech32Prefix rpc method.
//
// Since: cosmos-sdk 0.46
Expand Down
35 changes: 35 additions & 0 deletions x/auth/client/cli/query.go
Expand Up @@ -46,6 +46,7 @@ func GetQueryCmd() *cobra.Command {
GetAccountsCmd(),
QueryParamsCmd(),
QueryModuleAccountsCmd(),
QueryModuleAccountByNameCmd(),
)

return cmd
Expand Down Expand Up @@ -219,6 +220,40 @@ func QueryModuleAccountsCmd() *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
71 changes: 71 additions & 0 deletions x/auth/client/testutil/suite.go
Expand Up @@ -15,6 +15,15 @@ import (
"github.com/stretchr/testify/suite"
tmcli "github.com/tendermint/tendermint/libs/cli"

<<<<<<< HEAD:x/auth/client/testutil/suite.go
=======
"cosmossdk.io/depinject"
"cosmossdk.io/math"

authtestutil "github.com/cosmos/cosmos-sdk/x/auth/testutil"
"github.com/cosmos/cosmos-sdk/x/auth/types"

>>>>>>> ddf5cf0d8 (feat(cli): add module-account cli cmd and grpc get api (#13612)):tests/e2e/auth/suite.go
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/crypto/hd"
Expand Down Expand Up @@ -1391,6 +1400,68 @@ 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 types.AccountI
err := val.ClientCtx.InterfaceRegistry.UnpackAny(res.Account, &account)
s.Require().NoError(err)

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

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

out, err := clitestutil.ExecTestCLICmd(clientCtx, authcli.QueryModuleAccountsCmd(), []string{
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
})
s.Require().NoError(err)

var res authtypes.QueryModuleAccountsResponse
s.Require().NoError(val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
s.Require().NotEmpty(res.Accounts)
}

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
Expand Up @@ -135,6 +135,31 @@ func (ak AccountKeeper) ModuleAccounts(c context.Context, req *types.QueryModule
return &types.QueryModuleAccountsResponse{Accounts: modAccounts}, 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
}

// Bech32Prefix returns the keeper internally stored bech32 prefix.
func (ak AccountKeeper) Bech32Prefix(ctx context.Context, req *types.Bech32PrefixRequest) (*types.Bech32PrefixResponse, error) {
bech32Prefix, err := ak.getBech32Prefix()
Expand Down
55 changes: 55 additions & 0 deletions x/auth/keeper/grpc_query_test.go
Expand Up @@ -348,6 +348,61 @@ func (suite *KeeperTestSuite) TestGRPCQueryModuleAccounts() {
}
}

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.encCfg.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)
})
}
}

func (suite *KeeperTestSuite) TestBech32Prefix() {
suite.SetupTest() // reset
req := &types.Bech32PrefixRequest{}
Expand Down

0 comments on commit 96ea326

Please sign in to comment.