Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

auth: query all accounts stored via gRPC #8522

Merged
merged 18 commits into from
Feb 22, 2021
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Improvements

* (x/auth) [\#8522](https://github.com/cosmos/cosmos-sdk/pull/8522) Allow to query all stored accounts

### Bug Fixes

* (x/evidence) [#8461](https://github.com/cosmos/cosmos-sdk/pull/8461) Fix bech32 prefix in evidence validator address conversion
Expand Down
9,474 changes: 4,754 additions & 4,720 deletions docs/core/proto-docs.md

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions proto/cosmos/auth/v1beta1/query.proto
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
syntax = "proto3";
package cosmos.auth.v1beta1;

import "cosmos/base/query/v1beta1/pagination.proto";
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "google/api/annotations.proto";
Expand All @@ -11,6 +12,11 @@ option go_package = "github.com/cosmos/cosmos-sdk/x/auth/types";

// Query defines the gRPC querier service.
service Query {
// Accounts returns all the existing accounts
rpc Accounts(QueryAccountsRequest) returns (QueryAccountsResponse) {
option (google.api.http).get = "/cosmos/auth/v1beta1/accounts";
}

// Account returns account details based on address.
rpc Account(QueryAccountRequest) returns (QueryAccountResponse) {
option (google.api.http).get = "/cosmos/auth/v1beta1/accounts/{address}";
Expand All @@ -22,6 +28,21 @@ service Query {
}
}

// QueryAccountsRequest is the request type for the Query/Accounts RPC method.
message QueryAccountsRequest {
// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}

// QueryAccountsResponse is the response type for the Query/Accounts RPC method.
message QueryAccountsResponse {
// accounts are the existing accounts
repeated google.protobuf.Any accounts = 1 [(cosmos_proto.accepts_interface) = "AccountI"];

// pagination defines the pagination in the response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryAccountRequest is the request type for the Query/Account RPC method.
message QueryAccountRequest {
option (gogoproto.equal) = false;
Expand Down
50 changes: 25 additions & 25 deletions proto/cosmos/staking/v1beta1/staking.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ message CommissionRates {
option (gogoproto.goproto_stringer) = false;

// rate is the commission rate charged to delegators, as a fraction.
string rate = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
string rate = 1 [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false];
// max_rate defines the maximum commission rate which validator can ever charge, as a fraction.
string max_rate = 2 [
(gogoproto.moretags) = "yaml:\"max_rate\"",
Expand All @@ -49,9 +49,9 @@ message Commission {
option (gogoproto.goproto_stringer) = false;

// commission_rates defines the initial commission rates to be used for creating a validator.
CommissionRates commission_rates = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
CommissionRates commission_rates = 1 [(gogoproto.embed) = true, (gogoproto.nullable) = false];
// update_time is the last time the commission rate was changed.
google.protobuf.Timestamp update_time = 2
google.protobuf.Timestamp update_time = 2
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"update_time\""];
}

Expand All @@ -61,15 +61,15 @@ message Description {
option (gogoproto.goproto_stringer) = false;

// moniker defines a human-readable name for the validator.
string moniker = 1;
string moniker = 1;
// identity defines an optional identity signature (ex. UPort or Keybase).
string identity = 2;
string identity = 2;
// website defines an optional website link.
string website = 3;
string website = 3;
// security_contact defines an optional email for security contact.
string security_contact = 4 [(gogoproto.moretags) = "yaml:\"security_contact\""];
// details define other optional details.
string details = 5;
string details = 5;
}

// Validator defines a validator, together with the total amount of the
Expand All @@ -86,12 +86,12 @@ message Validator {
option (gogoproto.goproto_getters) = false;

// operator_address defines the address of the validator's operator; bech encoded in JSON.
string operator_address = 1 [(gogoproto.moretags) = "yaml:\"operator_address\""];
string operator_address = 1 [(gogoproto.moretags) = "yaml:\"operator_address\""];
// consensus_pubkey is the consensus public key of the validator, as a Protobuf Any.
google.protobuf.Any consensus_pubkey = 2
[(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey", (gogoproto.moretags) = "yaml:\"consensus_pubkey\""];
// jailed defined whether the validator has been jailed from bonded status or not.
bool jailed = 3;
bool jailed = 3;
// status is the validator status (bonded/unbonding/unbonded).
BondStatus status = 4;
// tokens define the delegated tokens (incl. self-delegation).
Expand All @@ -103,16 +103,16 @@ message Validator {
(gogoproto.nullable) = false
];
// description defines the description terms for the validator.
Description description = 7 [(gogoproto.nullable) = false];
Description description = 7 [(gogoproto.nullable) = false];
// unbonding_height defines, if unbonding, the height at which this validator has begun unbonding.
int64 unbonding_height = 8 [(gogoproto.moretags) = "yaml:\"unbonding_height\""];
int64 unbonding_height = 8 [(gogoproto.moretags) = "yaml:\"unbonding_height\""];
// unbonding_time defines, if unbonding, the min time for the validator to complete unbonding.
google.protobuf.Timestamp unbonding_time = 9
google.protobuf.Timestamp unbonding_time = 9
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"unbonding_time\""];
// commission defines the commission parameters.
Commission commission = 10 [(gogoproto.nullable) = false];
Commission commission = 10 [(gogoproto.nullable) = false];
// min_self_delegation is the validator's self declared minimum self delegation.
string min_self_delegation = 11 [
string min_self_delegation = 11 [
(gogoproto.moretags) = "yaml:\"min_self_delegation\"",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
Expand Down Expand Up @@ -201,9 +201,9 @@ message UnbondingDelegation {
option (gogoproto.goproto_stringer) = false;

// delegator_address is the bech32-encoded address of the delegator.
string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""];
string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""];
// validator_address is the bech32-encoded address of the validator.
string validator_address = 2 [(gogoproto.moretags) = "yaml:\"validator_address\""];
string validator_address = 2 [(gogoproto.moretags) = "yaml:\"validator_address\""];
// entries are the unbonding delegation entries.
repeated UnbondingDelegationEntry entries = 3 [(gogoproto.nullable) = false]; // unbonding delegation entries
}
Expand All @@ -214,7 +214,7 @@ message UnbondingDelegationEntry {
option (gogoproto.goproto_stringer) = false;

// creation_height is the height which the unbonding took place.
int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""];
int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""];
// completion_time is the unix time for unbonding completion.
google.protobuf.Timestamp completion_time = 2
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"completion_time\""];
Expand All @@ -234,7 +234,7 @@ message RedelegationEntry {
option (gogoproto.goproto_stringer) = false;

// creation_height defines the height which the redelegation took place.
int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""];
int64 creation_height = 1 [(gogoproto.moretags) = "yaml:\"creation_height\""];
// completion_time defines the unix time for redelegation completion.
google.protobuf.Timestamp completion_time = 2
[(gogoproto.nullable) = false, (gogoproto.stdtime) = true, (gogoproto.moretags) = "yaml:\"completion_time\""];
Expand All @@ -257,13 +257,13 @@ message Redelegation {
option (gogoproto.goproto_stringer) = false;

// delegator_address is the bech32-encoded address of the delegator.
string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""];
string delegator_address = 1 [(gogoproto.moretags) = "yaml:\"delegator_address\""];
// validator_src_address is the validator redelegation source operator address.
string validator_src_address = 2 [(gogoproto.moretags) = "yaml:\"validator_src_address\""];
string validator_src_address = 2 [(gogoproto.moretags) = "yaml:\"validator_src_address\""];
// validator_dst_address is the validator redelegation destination operator address.
string validator_dst_address = 3 [(gogoproto.moretags) = "yaml:\"validator_dst_address\""];
string validator_dst_address = 3 [(gogoproto.moretags) = "yaml:\"validator_dst_address\""];
// entries are the redelegation entries.
repeated RedelegationEntry entries = 4 [(gogoproto.nullable) = false]; // redelegation entries
repeated RedelegationEntry entries = 4 [(gogoproto.nullable) = false]; // redelegation entries
}

// Params defines the parameters for the staking module.
Expand All @@ -275,13 +275,13 @@ message Params {
google.protobuf.Duration unbonding_time = 1
[(gogoproto.nullable) = false, (gogoproto.stdduration) = true, (gogoproto.moretags) = "yaml:\"unbonding_time\""];
// max_validators is the maximum number of validators.
uint32 max_validators = 2 [(gogoproto.moretags) = "yaml:\"max_validators\""];
uint32 max_validators = 2 [(gogoproto.moretags) = "yaml:\"max_validators\""];
// max_entries is the max entries for either unbonding delegation or redelegation (per pair/trio).
uint32 max_entries = 3 [(gogoproto.moretags) = "yaml:\"max_entries\""];
uint32 max_entries = 3 [(gogoproto.moretags) = "yaml:\"max_entries\""];
// historical_entries is the number of historical entries to persist.
uint32 historical_entries = 4 [(gogoproto.moretags) = "yaml:\"historical_entries\""];
// bond_denom defines the bondable coin denomination.
string bond_denom = 5 [(gogoproto.moretags) = "yaml:\"bond_denom\""];
string bond_denom = 5 [(gogoproto.moretags) = "yaml:\"bond_denom\""];
}

// DelegationResponse is equivalent to Delegation except that it contains a
Expand Down
14 changes: 14 additions & 0 deletions x/auth/client/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -851,6 +851,20 @@ func (s *IntegrationTestSuite) TestGetAccountCmd() {
}
}

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

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

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

func TestGetBroadcastCommand_OfflineFlag(t *testing.T) {
clientCtx := client.Context{}.WithOffline(true)
clientCtx = clientCtx.WithTxConfig(simapp.MakeTestEncodingConfig().TxConfig)
Expand Down
33 changes: 33 additions & 0 deletions x/auth/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func GetQueryCmd() *cobra.Command {

cmd.AddCommand(
GetAccountCmd(),
GetAccountsCmd(),
QueryParamsCmd(),
)

Expand Down Expand Up @@ -103,6 +104,38 @@ func GetAccountCmd() *cobra.Command {
return cmd
}

// GetAccountsCmd returns a query command that will display a list of accounts
func GetAccountsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "accounts",
Short: "Query all the accounts",
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}

queryClient := types.NewQueryClient(clientCtx)
res, err := queryClient.Accounts(cmd.Context(), &types.QueryAccountsRequest{Pagination: pageReq})
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "all-accounts")

return cmd
}

// QueryTxsByEventsCmd returns a command to search through transactions by events.
func QueryTxsByEventsCmd() *cobra.Command {
cmd := &cobra.Command{
Expand Down
31 changes: 31 additions & 0 deletions x/auth/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package keeper
import (
"context"

"github.com/cosmos/cosmos-sdk/store/prefix"
"github.com/cosmos/cosmos-sdk/types/query"
amaury1093 marked this conversation as resolved.
Show resolved Hide resolved

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

Expand All @@ -13,6 +16,34 @@ import (

var _ types.QueryServer = AccountKeeper{}

func (ak AccountKeeper) Accounts(c context.Context, req *types.QueryAccountsRequest) (*types.QueryAccountsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}

ctx := sdk.UnwrapSDKContext(c)
store := ctx.KVStore(ak.key)
accountsStore := prefix.NewStore(store, types.AddressStoreKeyPrefix)

var accounts []*codectypes.Any
pageRes, err := query.Paginate(accountsStore, req.Pagination, func(key, value []byte) error {
account := ak.decodeAccount(value)
any, err := codectypes.NewAnyWithValue(account)
if err != nil {
return err
}

accounts = append(accounts, any)
return nil
})

if err != nil {
return nil, status.Errorf(codes.Internal, "paginate: %v", err)
}

return &types.QueryAccountsResponse{Accounts: accounts, Pagination: pageRes}, err
}

// Account returns account details based on address
func (ak AccountKeeper) Account(c context.Context, req *types.QueryAccountRequest) (*types.QueryAccountResponse, error) {
if req == nil {
Expand Down
58 changes: 58 additions & 0 deletions x/auth/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,64 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth/types"
)

func (suite *KeeperTestSuite) TestGRPCQueryAccounts() {
var (
req *types.QueryAccountsRequest
)
_, _, first := testdata.KeyTestPubAddr()
_, _, second := testdata.KeyTestPubAddr()

testCases := []struct {
msg string
malleate func()
expPass bool
posttests func(res *types.QueryAccountsResponse)
}{
{
"success",
func() {
suite.app.AccountKeeper.SetAccount(suite.ctx,
suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, first))
suite.app.AccountKeeper.SetAccount(suite.ctx,
suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, second))
req = &types.QueryAccountsRequest{}
},
true,
func(res *types.QueryAccountsResponse) {
for _, acc := range res.Accounts {
var account types.AccountI
err := suite.app.InterfaceRegistry().UnpackAny(acc, &account)
suite.Require().NoError(err)

suite.Require().True(
first.Equals(account.GetAddress()) || second.Equals(account.GetAddress()))
}
},
},
}

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.Accounts(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) TestGRPCQueryAccount() {
var (
req *types.QueryAccountRequest
Expand Down
Loading