Skip to content

Commit

Permalink
feat: mapped account query (#443)
Browse files Browse the repository at this point in the history
* add mapped account query

* format

* rebase

* return map instead of struct

* Update x/interchainstaking/client/cli/query.go

Co-authored-by: Alex Johnson <[email protected]>

* Update x/interchainstaking/keeper/grpc_query.go

* Update x/interchainstaking/keeper/grpc_query_test.go

* fix lint

* use sdkConfig

---------

Co-authored-by: Alex Johnson <[email protected]>
  • Loading branch information
ajansari95 and Alex Johnson authored Jun 2, 2023
1 parent 0cf0ecc commit 84f6d97
Show file tree
Hide file tree
Showing 9 changed files with 1,189 additions and 86 deletions.
130 changes: 130 additions & 0 deletions docs/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2379,6 +2379,136 @@ paths:
type: string
tags:
- Msg
/quicksilver/interchainstaking/v1/mapped_addresses/{address}:
get:
summary: >-
MappedAccounts provides data on the mapped accounts for a given user
over different host chains.
operationId: MappedAccounts
responses:
'200':
description: A successful response.
schema:
type: object
properties:
RemoteAddressMap:
type: object
additionalProperties:
type: string
format: byte
pagination:
type: object
properties:
next_key:
type: string
format: byte
description: |-
next_key is the key to be passed to PageRequest.key to
query the next page most efficiently. It will be empty if
there are no more results.
total:
type: string
format: uint64
title: >-
total is total number of results available if
PageRequest.count_total
was set, its value is undefined otherwise
description: >-
PageResponse is to be embedded in gRPC response messages where
the
corresponding request message has used PageRequest.
message SomeResponse {
repeated Bar results = 1;
PageResponse page = 2;
}
default:
description: An unexpected error response.
schema:
type: object
properties:
error:
type: string
code:
type: integer
format: int32
message:
type: string
details:
type: array
items:
type: object
properties:
type_url:
type: string
value:
type: string
format: byte
parameters:
- name: address
in: path
required: true
type: string
- name: pagination.key
description: |-
key is a value returned in PageResponse.next_key to begin
querying the next page most efficiently. Only one of offset or key
should be set.
in: query
required: false
type: string
format: byte
- name: pagination.offset
description: >-
offset is a numeric offset that can be used when key is unavailable.
It is less efficient than using key. Only one of offset or key
should
be set.
in: query
required: false
type: string
format: uint64
- name: pagination.limit
description: >-
limit is the total number of results to be returned in the result
page.
If left empty it will default to a value to be set by each app.
in: query
required: false
type: string
format: uint64
- name: pagination.count_total
description: >-
count_total is set to true to indicate that the result set should
include
a count of the total number of items available for pagination in
UIs.
count_total is only respected when offset is used. It is ignored
when key
is set.
in: query
required: false
type: boolean
- name: pagination.reverse
description: >-
reverse is set to true if results are to be returned in the
descending order.
Since: cosmos-sdk 0.43
in: query
required: false
type: boolean
tags:
- QueryInterchainStaking
/quicksilver/interchainstaking/v1/zone/{chain_id}:
get:
summary: Zone provides meta data on a specific zone.
Expand Down
15 changes: 15 additions & 0 deletions proto/quicksilver/interchainstaking/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ service Query {
"/quicksilver/interchainstaking/v1/zones/"
"{chain_id}/redelegation_records";
}

// MappedAccounts provides data on the mapped accounts for a given user over different host chains.
rpc MappedAccounts(QueryMappedAccountsRequest) returns (QueryMappedAccountsResponse) {
option (google.api.http).get = "/quicksilver/interchainstaking/v1/mapped_addresses/{address}";
}
}

message Statistics {
Expand Down Expand Up @@ -184,3 +189,13 @@ message QueryRedelegationRecordsResponse {
repeated RedelegationRecord redelegations = 1 [(gogoproto.nullable) = false];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

message QueryMappedAccountsRequest {
string address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}

message QueryMappedAccountsResponse {
map<string, bytes> RemoteAddressMap= 1 [(gogoproto.nullable) = false];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}
35 changes: 35 additions & 0 deletions x/interchainstaking/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func GetQueryCmd() *cobra.Command {
GetCmdZones(),
GetDelegatorIntentCmd(),
GetDepositAccountCmd(),
GetMappedAccountsCmd(),
)

return cmd
Expand Down Expand Up @@ -144,3 +145,37 @@ func GetDepositAccountCmd() *cobra.Command {

return cmd
}

// GetMappedAccountsCmd returns the mapped account for the given address.
func GetMappedAccountsCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "mapped-accounts [address]",
Short: "Query mapped accounts for a given address.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}

// args
address := args[0]

queryClient := types.NewQueryClient(clientCtx)
req := &types.QueryMappedAccountsRequest{
Address: address,
}

res, err := queryClient.MappedAccounts(cmd.Context(), req)
if err != nil {
return err
}

return clientCtx.PrintProto(res)
},
}

flags.AddQueryFlagsToCmd(cmd)

return cmd
}
24 changes: 24 additions & 0 deletions x/interchainstaking/keeper/address_map.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,30 @@ func (k *Keeper) GetRemoteAddressMap(ctx sdk.Context, localAddress []byte, chain
return value, value != nil
}

// IterateUserMappedAccounts iterates over all the user mapped accounts.
func (k Keeper) IterateUserMappedAccounts(ctx sdk.Context, localAddress []byte, fn func(index int64, chainID string, remoteAddressBytes []byte) (stop bool)) {
// noop
if fn == nil {
return
}

store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, types.GetRemoteAddressPrefix(localAddress))
defer iterator.Close()

i := int64(0)
for ; iterator.Valid(); iterator.Next() {
value := iterator.Value()
key := iterator.Key()
chainIDBytes := key[len(types.GetRemoteAddressPrefix(localAddress)):]
stop := fn(i, string(chainIDBytes), value)
if stop {
break
}
i++
}
}

// SetRemoteAddressMap sets a remote address using a local address as a map.
func (k *Keeper) SetRemoteAddressMap(ctx sdk.Context, localAddress, remoteAddress []byte, chainID string) {
store := ctx.KVStore(k.storeKey)
Expand Down
22 changes: 22 additions & 0 deletions x/interchainstaking/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

"github.com/ingenuity-build/quicksilver/utils"
"github.com/ingenuity-build/quicksilver/x/interchainstaking/types"
)

Expand Down Expand Up @@ -254,3 +255,24 @@ func (k *Keeper) RedelegationRecords(c context.Context, req *types.QueryRedelega

return &types.QueryRedelegationRecordsResponse{Redelegations: redelegations}, nil
}

func (k *Keeper) MappedAccounts(c context.Context, req *types.QueryMappedAccountsRequest) (*types.QueryMappedAccountsResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}

ctx := sdk.UnwrapSDKContext(c)

remoteAddressMap := make(map[string][]byte)
addrBytes, err := utils.AccAddressFromBech32(req.Address, sdk.GetConfig().GetBech32AccountAddrPrefix())
if err != nil {
return nil, status.Error(codes.InvalidArgument, "Invalid Address")
}

k.IterateUserMappedAccounts(ctx, addrBytes, func(index int64, chainID string, remoteAddressBytes []byte) (stop bool) {
remoteAddressMap[chainID] = remoteAddressBytes
return false
})

return &types.QueryMappedAccountsResponse{RemoteAddressMap: remoteAddressMap}, nil
}
Loading

0 comments on commit 84f6d97

Please sign in to comment.