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

feat: resolve IBC hash to human readable denom #14894

Merged
merged 16 commits into from
Feb 6, 2023
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (client) [#14509](https://github.com/cosmos/cosmos-sdk/pull/#14509) Added `AddKeyringFlags` function.
* (x/gov,cli) [#14718](https://github.com/cosmos/cosmos-sdk/pull/14718) Added `AddGovPropFlagsToCmd` and `ReadGovPropFlags` functions.
* (store) [#14189](https://github.com/cosmos/cosmos-sdk/pull/14189) Add config `iavl-lazy-loading` to enable lazy loading of iavl store, to improve start up time of archive nodes, add method `SetLazyLoading` to `CommitMultiStore` interface.
* (x/bank) [#14894](https://github.com/cosmos/cosmos-sdk/pull/14894) Return a human readable denomination for IBC vouchers when querying bank balances. Added a `ResolveDenom` parameter to `types.QueryAllBalancesRequest` and `--resolve-denom` flag to `GetBalancesCmd()`.
* (x/groups) [#14879](https://github.com/cosmos/cosmos-sdk/pull/14879) Add `Query/Groups` query to get all the groups.

### Improvements
Expand Down Expand Up @@ -247,6 +248,7 @@ extension interfaces. `module.Manager.Modules` is now of type `map[string]interf
* (store/streaming)[#14603](https://github.com/cosmos/cosmos-sdk/pull/14603) `StoreDecoderRegistry` moved from store to `types/simulations` this breaks the `AppModuleSimulation` interface.
* (x/staking) [#14590](https://github.com/cosmos/cosmos-sdk/pull/14590) `MsgUndelegateResponse` now includes undelegated amount. `x/staking` module's `keeper.Undelegate` now returns 3 values (completionTime,undelegateAmount,error) instead of 2.
* (x/feegrant) [14649](https://github.com/cosmos/cosmos-sdk/pull/14649) Extract Feegrant in its own go.mod and rename the package to `cosmossdk.io/x/feegrant`.
* (x/bank) [#14894](https://github.com/cosmos/cosmos-sdk/pull/14894) Return a human readable denomination for IBC vouchers when querying bank balances. Added a `ResolveDenom` parameter to `types.QueryAllBalancesRequest`.

### Client Breaking Changes

Expand Down
617 changes: 342 additions & 275 deletions api/cosmos/bank/v1beta1/query.pulsar.go

Large diffs are not rendered by default.

820 changes: 820 additions & 0 deletions go.sum

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions proto/cosmos/bank/v1beta1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ message QueryAllBalancesRequest {

// pagination defines an optional pagination for the request.
cosmos.base.query.v1beta1.PageRequest pagination = 2;

// resolve_denom is the flag to resolve the denom into a human-readable form from the metadata.
//
// Since: cosmos-sdk 0.47
0xmuralik marked this conversation as resolved.
Show resolved Hide resolved
bool resolve_denom = 3;
}

// QueryAllBalancesResponse is the response type for the Query/AllBalances RPC
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/bank/keeper/deterministic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func TestGRPCQueryAllBalances(t *testing.T) {

fundAccount(f, addr, coins...)

req := banktypes.NewQueryAllBalancesRequest(addr, testdata.PaginationGenerator(rt, uint64(numCoins)).Draw(rt, "pagination"))
req := banktypes.NewQueryAllBalancesRequest(addr, testdata.PaginationGenerator(rt, uint64(numCoins)).Draw(rt, "pagination"), false)
testdata.DeterministicIterations(f.ctx, t, req, f.queryClient.AllBalances, 0, true)
})

Expand All @@ -144,7 +144,7 @@ func TestGRPCQueryAllBalances(t *testing.T) {
)

fundAccount(f, addr1, coins...)
req := banktypes.NewQueryAllBalancesRequest(addr1, nil)
req := banktypes.NewQueryAllBalancesRequest(addr1, nil, false)

testdata.DeterministicIterations(f.ctx, t, req, f.queryClient.AllBalances, 357, false)
}
Expand Down
2 changes: 1 addition & 1 deletion types/query/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func FuzzPagination(f *testing.F) {
}

// Now try to paginate it.
req := types.NewQueryAllBalancesRequest(addr1, qr)
req := types.NewQueryAllBalancesRequest(addr1, qr, false)
balResult := sdk.NewCoins()
authStore := suite.ctx.KVStore(suite.app.UnsafeFindStoreKey(types.StoreKey))
balancesStore := prefix.NewStore(authStore, types.BalancesPrefix)
Expand Down
44 changes: 22 additions & 22 deletions types/query/pagination_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ func (s *paginationTestSuite) TestPagination() {

s.T().Log("verify empty page request results a max of defaultLimit records and counts total records")
pageReq := &query.PageRequest{}
request := types.NewQueryAllBalancesRequest(addr1, pageReq)
request := types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err := queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Pagination.Total, uint64(numBalances))
Expand All @@ -129,7 +129,7 @@ func (s *paginationTestSuite) TestPagination() {

s.T().Log("verify page request with limit > defaultLimit, returns less or equal to `limit` records")
pageReq = &query.PageRequest{Limit: overLimit}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Pagination.Total, uint64(0))
Expand All @@ -138,7 +138,7 @@ func (s *paginationTestSuite) TestPagination() {

s.T().Log("verify paginate with custom limit and countTotal true")
pageReq = &query.PageRequest{Limit: underLimit, CountTotal: true}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Balances.Len(), underLimit)
Expand All @@ -147,7 +147,7 @@ func (s *paginationTestSuite) TestPagination() {

s.T().Log("verify paginate with custom limit and countTotal false")
pageReq = &query.PageRequest{Limit: defaultLimit, CountTotal: false}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Balances.Len(), defaultLimit)
Expand All @@ -156,7 +156,7 @@ func (s *paginationTestSuite) TestPagination() {

s.T().Log("verify paginate with custom limit, key and countTotal false")
pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: defaultLimit, CountTotal: false}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Balances.Len(), defaultLimit)
Expand All @@ -165,7 +165,7 @@ func (s *paginationTestSuite) TestPagination() {

s.T().Log("verify paginate for last page, results in records less than max limit")
pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: defaultLimit, CountTotal: false}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().LessOrEqual(res.Balances.Len(), defaultLimit)
Expand All @@ -175,7 +175,7 @@ func (s *paginationTestSuite) TestPagination() {

s.T().Log("verify paginate with offset and limit")
pageReq = &query.PageRequest{Offset: 200, Limit: defaultLimit, CountTotal: false}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().LessOrEqual(res.Balances.Len(), defaultLimit)
Expand All @@ -185,7 +185,7 @@ func (s *paginationTestSuite) TestPagination() {

s.T().Log("verify paginate with offset and limit")
pageReq = &query.PageRequest{Offset: 100, Limit: defaultLimit, CountTotal: false}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().LessOrEqual(res.Balances.Len(), defaultLimit)
Expand All @@ -194,14 +194,14 @@ func (s *paginationTestSuite) TestPagination() {

s.T().Log("verify paginate with offset and key - error")
pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Offset: 100, Limit: defaultLimit, CountTotal: false}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
_, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().Error(err)
s.Require().Equal("rpc error: code = InvalidArgument desc = paginate: invalid request, either offset or key is expected, got both", err.Error())

s.T().Log("verify paginate with offset greater than total results")
pageReq = &query.PageRequest{Offset: 300, Limit: defaultLimit, CountTotal: false}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().LessOrEqual(res.Balances.Len(), 0)
Expand All @@ -228,15 +228,15 @@ func (s *paginationTestSuite) TestReversePagination() {

s.T().Log("verify paginate with custom limit and countTotal, Reverse false")
pageReq := &query.PageRequest{Limit: 2, CountTotal: true, Reverse: true, Key: nil}
request := types.NewQueryAllBalancesRequest(addr1, pageReq)
request := types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res1, err := queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res1.Balances.Len(), 2)
s.Require().NotNil(res1.Pagination.NextKey)

s.T().Log("verify paginate with custom limit and countTotal, Reverse false")
pageReq = &query.PageRequest{Limit: 150}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res1, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res1.Balances.Len(), 150)
Expand All @@ -245,7 +245,7 @@ func (s *paginationTestSuite) TestReversePagination() {

s.T().Log("verify paginate with custom limit, key and Reverse true")
pageReq = &query.PageRequest{Limit: defaultLimit, Reverse: true}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err := queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Balances.Len(), defaultLimit)
Expand All @@ -254,7 +254,7 @@ func (s *paginationTestSuite) TestReversePagination() {

s.T().Log("verify paginate with custom limit, key and Reverse true")
pageReq = &query.PageRequest{Offset: 100, Limit: defaultLimit, Reverse: true}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Balances.Len(), defaultLimit)
Expand All @@ -263,7 +263,7 @@ func (s *paginationTestSuite) TestReversePagination() {

s.T().Log("verify paginate for last page, Reverse true")
pageReq = &query.PageRequest{Offset: 200, Limit: defaultLimit, Reverse: true}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Balances.Len(), lastPageRecords)
Expand All @@ -272,7 +272,7 @@ func (s *paginationTestSuite) TestReversePagination() {

s.T().Log("verify page request with limit > defaultLimit, returns less or equal to `limit` records")
pageReq = &query.PageRequest{Limit: overLimit, Reverse: true}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Pagination.Total, uint64(0))
Expand All @@ -281,7 +281,7 @@ func (s *paginationTestSuite) TestReversePagination() {

s.T().Log("verify paginate with custom limit, key, countTotal false and Reverse true")
pageReq = &query.PageRequest{Key: res1.Pagination.NextKey, Limit: 50, Reverse: true}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Balances.Len(), 50)
Expand All @@ -293,7 +293,7 @@ func (s *paginationTestSuite) TestReversePagination() {

s.T().Log("verify paginate with custom limit, key, countTotal false and Reverse true")
pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: 50, Reverse: true}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Balances.Len(), 50)
Expand All @@ -305,7 +305,7 @@ func (s *paginationTestSuite) TestReversePagination() {

s.T().Log("verify paginate for last page Reverse true")
pageReq = &query.PageRequest{Key: res.Pagination.NextKey, Limit: defaultLimit, Reverse: true}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().Equal(res.Balances.Len(), 51)
Expand All @@ -317,14 +317,14 @@ func (s *paginationTestSuite) TestReversePagination() {

s.T().Log("verify paginate with offset and key - error")
pageReq = &query.PageRequest{Key: res1.Pagination.NextKey, Offset: 100, Limit: defaultLimit, CountTotal: false}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
_, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().Error(err)
s.Require().Equal("rpc error: code = InvalidArgument desc = paginate: invalid request, either offset or key is expected, got both", err.Error())

s.T().Log("verify paginate with offset greater than total results")
pageReq = &query.PageRequest{Offset: 300, Limit: defaultLimit, CountTotal: false, Reverse: true}
request = types.NewQueryAllBalancesRequest(addr1, pageReq)
request = types.NewQueryAllBalancesRequest(addr1, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), request)
s.Require().NoError(err)
s.Require().LessOrEqual(res.Balances.Len(), 0)
Expand All @@ -349,7 +349,7 @@ func (s *paginationTestSuite) TestPaginate() {
}
// Paginate example
pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true}
request := types.NewQueryAllBalancesRequest(addr1, pageReq)
request := types.NewQueryAllBalancesRequest(addr1, pageReq, false)
balResult := sdk.NewCoins()
authStore := s.ctx.KVStore(s.app.UnsafeFindStoreKey(types.StoreKey))
balancesStore := prefix.NewStore(authStore, types.BalancesPrefix)
Expand Down
14 changes: 11 additions & 3 deletions x/bank/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import (
)

const (
FlagDenom = "denom"
FlagDenom = "denom"
FlagResolveDenom = "resolve-denom"
)

// GetQueryCmd returns the parent command for all x/bank CLi query commands. The
Expand Down Expand Up @@ -50,8 +51,9 @@ func GetBalancesCmd() *cobra.Command {
Example:
$ %s query %s balances [address]
$ %s query %s balances [address] --denom=[denom]
$ %s query %s balances [address] --resolve-denom
`,
version.AppName, types.ModuleName, version.AppName, types.ModuleName,
version.AppName, types.ModuleName, version.AppName, types.ModuleName, version.AppName, types.ModuleName,
),
),
Args: cobra.ExactArgs(1),
Expand Down Expand Up @@ -81,7 +83,12 @@ Example:
ctx := cmd.Context()

if denom == "" {
params := types.NewQueryAllBalancesRequest(addr, pageReq)
resolveDenom, err := cmd.Flags().GetBool(FlagResolveDenom)
if err != nil {
return err
}

params := types.NewQueryAllBalancesRequest(addr, pageReq, resolveDenom)

res, err := queryClient.AllBalances(ctx, params)
if err != nil {
Expand All @@ -103,6 +110,7 @@ Example:
}

cmd.Flags().String(FlagDenom, "", "The specific balance denomination to query for")
cmd.Flags().Bool(FlagResolveDenom, false, "Resolve denom to human-readable denom from metadata")
flags.AddQueryFlagsToCmd(cmd)
flags.AddPaginationFlagsToCmd(cmd, "all balances")

Expand Down
9 changes: 9 additions & 0 deletions x/bank/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ func (k BaseKeeper) AllBalances(ctx context.Context, req *types.QueryAllBalances

pageRes, err := query.Paginate(accountStore, req.Pagination, func(key, value []byte) error {
denom := string(key)

// IBC denom metadata will be registered in ibc-go after first mint
//
// Since: ibc-go v7
if req.ResolveDenom {
if metadata, ok := k.GetDenomMetaData(sdkCtx, denom); ok {
denom = metadata.Display
}
}
balance, err := UnmarshalBalanceCompat(k.cdc, value, denom)
if err != nil {
return err
Expand Down
36 changes: 33 additions & 3 deletions x/bank/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,23 @@ func (suite *KeeperTestSuite) TestQueryAllBalances() {
Limit: 1,
CountTotal: false,
}
req := types.NewQueryAllBalancesRequest(addr, pageReq)
req := types.NewQueryAllBalancesRequest(addr, pageReq, false)
res, err := queryClient.AllBalances(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.True(res.Balances.IsZero())

fooCoins := newFooCoin(50)
barCoins := newBarCoin(30)
ibcCoins := newIbcCoin(20)

origCoins := sdk.NewCoins(fooCoins, barCoins)
origCoins := sdk.NewCoins(fooCoins, barCoins, ibcCoins)

suite.mockFundAccount(addr)
suite.Require().NoError(testutil.FundAccount(suite.bankKeeper, ctx, addr, origCoins))

addIBCMetadata(ctx, suite.bankKeeper)

res, err = queryClient.AllBalances(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Require().NotNil(res)
Expand All @@ -83,10 +86,37 @@ func (suite *KeeperTestSuite) TestQueryAllBalances() {
Limit: 1,
CountTotal: true,
}
req = types.NewQueryAllBalancesRequest(addr, pageReq)
req = types.NewQueryAllBalancesRequest(addr, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Equal(res.Balances.Len(), 1)
suite.NotNil(res.Pagination.NextKey)

pageThree := res.Pagination.NextKey

suite.T().Log("query third page with nextkey")
pageReq = &query.PageRequest{
Key: pageThree,
Limit: 1,
CountTotal: true,
}
req = types.NewQueryAllBalancesRequest(addr, pageReq, false)
res, err = queryClient.AllBalances(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Equal(res.Balances.Len(), 1)
suite.Equal(res.Balances[0].Denom, ibcCoins.Denom)

suite.T().Log("query third page with nextkey and resolve ibc denom")
pageReq = &query.PageRequest{
Key: pageThree,
Limit: 1,
CountTotal: true,
}
req = types.NewQueryAllBalancesRequest(addr, pageReq, true)
res, err = queryClient.AllBalances(gocontext.Background(), req)
suite.Require().NoError(err)
suite.Equal(res.Balances.Len(), 1)
suite.Equal(res.Balances[0].Denom, ibcPath+"/"+ibcBaseDenom)
suite.Nil(res.Pagination.NextKey)
}

Expand Down
Loading