From 4b0c66982a87e824d43873187ae049a9f572ed7a Mon Sep 17 00:00:00 2001 From: SaReN Date: Sun, 21 Jun 2020 05:14:04 +0530 Subject: [PATCH] Add pagination (#6452) * Add pagination types and helper func * Update API * Add pagination to queryBalance * Add QueryBalance to use Paginate * Update GetAllBalances usage * Add tests for QueryAllBalances * Fix bank get balance querier tests * Add pagination test setup * revert simapp changes * Fix pagenation tests * Add more tests for pagination * Add offset nullable * Add more tests * Fix paginate for offset * Add grpc queryconn for query * Fix paginate * Fix maxlimit * Fix queryClient * Fix pagination tests * refacor * Fix grpc tests * Revert * review changes * Fix lint * Update types/query/pagination.go * Fix review suggestions * Remove maxLimit and use defaultLimit * change example paginate as a testable fun * Fix review comments * Merge master * Add bank query.pb.go * Add missing import * Add pageReq to queryBalance * Add example for pagenate * Fix cli tests * Remove example for pagination * Update paginate example Co-authored-by: Aaron Craelius Co-authored-by: Aaron Craelius Co-authored-by: anilCSE Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com> --- proto/cosmos/bank/query.proto | 7 +- proto/cosmos/query/pagination.proto | 49 ++ types/query/pagination.go | 93 ++++ types/query/pagination.pb.go | 675 ++++++++++++++++++++++++++++ types/query/pagination_test.go | 213 +++++++++ x/bank/client/cli/query.go | 6 +- x/bank/client/rest/query.go | 2 +- x/bank/keeper/grpc_query.go | 27 +- x/bank/keeper/grpc_query_test.go | 28 +- x/bank/keeper/keeper_test.go | 1 + x/bank/keeper/querier_test.go | 2 +- x/bank/keeper/view.go | 1 - x/bank/types/querier.go | 5 +- x/bank/types/query.pb.go | 186 ++++++-- x/distribution/genesis.go | 3 +- 15 files changed, 1251 insertions(+), 47 deletions(-) create mode 100644 proto/cosmos/query/pagination.proto create mode 100644 types/query/pagination.go create mode 100644 types/query/pagination.pb.go create mode 100644 types/query/pagination_test.go diff --git a/proto/cosmos/bank/query.proto b/proto/cosmos/bank/query.proto index e5c4cfa08c..773786e4a9 100644 --- a/proto/cosmos/bank/query.proto +++ b/proto/cosmos/bank/query.proto @@ -1,6 +1,7 @@ syntax = "proto3"; package cosmos.bank; +import "cosmos/query/pagination.proto"; import "gogoproto/gogo.proto"; import "cosmos/cosmos.proto"; @@ -41,16 +42,20 @@ message QueryBalanceResponse { message QueryAllBalancesRequest { // address is the address to query balances for bytes address = 1 [(gogoproto.casttype) = "github.com/cosmos/cosmos-sdk/types.AccAddress"]; + + cosmos.query.PageRequest req = 2; } // QueryAllBalancesResponse is the response type for the Query/AllBalances RPC method message QueryAllBalancesResponse { // balances is the balances of the coins repeated cosmos.Coin balances = 1 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + + cosmos.query.PageResponse res = 2; } // QueryTotalSupplyRequest is the request type for the Query/TotalSupply RPC method -message QueryTotalSupplyRequest { } +message QueryTotalSupplyRequest {} // QueryTotalSupplyResponse is the response type for the Query/TotalSupply RPC method message QueryTotalSupplyResponse { diff --git a/proto/cosmos/query/pagination.proto b/proto/cosmos/query/pagination.proto new file mode 100644 index 0000000000..cd3a1f27bf --- /dev/null +++ b/proto/cosmos/query/pagination.proto @@ -0,0 +1,49 @@ +syntax = "proto3"; +package cosmos.query; + +option go_package = "github.com/cosmos/cosmos-sdk/types/query"; + +// PageRequest is to be embedded in gRPC request messages for efficient +// pagination. Ex: +// +// message SomeRequest { +// Foo some_parameter = 1; +// PageRequest page = 2; +// } +message PageRequest { + // 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. + bytes key = 1; + + // 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. + uint64 offset = 2; + + // 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. + uint64 limit = 3; + + // 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. + bool count_total = 4; +} + +// 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; +// } +message PageResponse { + // next_key is the key to be passed to PageRequest.key to + // query the next page most efficiently + bytes next_key = 1; + + // total is total number of results available if PageRequest.count_total + // was set, its value is undefined otherwise + uint64 total = 2; +} diff --git a/types/query/pagination.go b/types/query/pagination.go new file mode 100644 index 0000000000..595fe29b9d --- /dev/null +++ b/types/query/pagination.go @@ -0,0 +1,93 @@ +package query + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/store/types" +) + +// defaultLimit is the default `limit` for queries +// if the `limit` is not supplied, paginate will use `defaultLimit` +const defaultLimit = 100 + +// Paginate does pagination of all the results in the PrefixStore based on the +// provided PageRequest. onResult should be used to do actual unmarshaling. +func Paginate( + prefixStore types.KVStore, + req *PageRequest, + onResult func(key []byte, value []byte) error, +) (*PageResponse, error) { + offset := req.Offset + key := req.Key + limit := req.Limit + countTotal := req.CountTotal + + if offset > 0 && key != nil { + return nil, fmt.Errorf("invalid request, either offset or key is expected, got both") + } + + if limit == 0 { + limit = defaultLimit + + // count total results when the limit is zero/not supplied + countTotal = true + } + + if len(key) != 0 { + iterator := prefixStore.Iterator(key, nil) + defer iterator.Close() + + var count uint64 + var nextKey []byte + + for ; iterator.Valid(); iterator.Next() { + if count == limit { + nextKey = iterator.Key() + break + } + + err := onResult(iterator.Key(), iterator.Value()) + if err != nil { + return nil, err + } + + count++ + } + + return &PageResponse{ + NextKey: nextKey, + }, nil + } + + iterator := prefixStore.Iterator(nil, nil) + defer iterator.Close() + + end := offset + limit + + var count uint64 + var nextKey []byte + + for ; iterator.Valid(); iterator.Next() { + count++ + + if count <= offset { + continue + } + if count <= end { + err := onResult(iterator.Key(), iterator.Value()) + if err != nil { + return nil, err + } + } else if !countTotal { + nextKey = iterator.Key() + break + } + } + + res := &PageResponse{NextKey: nextKey} + if countTotal { + res.Total = count + } + + return res, nil +} diff --git a/types/query/pagination.pb.go b/types/query/pagination.pb.go new file mode 100644 index 0000000000..32d75937a3 --- /dev/null +++ b/types/query/pagination.pb.go @@ -0,0 +1,675 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: cosmos/query/pagination.proto + +package query + +import ( + fmt "fmt" + proto "github.com/gogo/protobuf/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// PageRequest is to be embedded in gRPC request messages for efficient +// pagination. Ex: +// +// message SomeRequest { +// Foo some_parameter = 1; +// PageRequest page = 2; +// } +type PageRequest struct { + // 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. + Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // 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. + Offset uint64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` + // 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. + Limit uint64 `protobuf:"varint,3,opt,name=limit,proto3" json:"limit,omitempty"` + // 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. + CountTotal bool `protobuf:"varint,4,opt,name=count_total,json=countTotal,proto3" json:"count_total,omitempty"` +} + +func (m *PageRequest) Reset() { *m = PageRequest{} } +func (m *PageRequest) String() string { return proto.CompactTextString(m) } +func (*PageRequest) ProtoMessage() {} +func (*PageRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_4353dcf7b0208338, []int{0} +} +func (m *PageRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PageRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PageRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PageRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_PageRequest.Merge(m, src) +} +func (m *PageRequest) XXX_Size() int { + return m.Size() +} +func (m *PageRequest) XXX_DiscardUnknown() { + xxx_messageInfo_PageRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_PageRequest proto.InternalMessageInfo + +func (m *PageRequest) GetKey() []byte { + if m != nil { + return m.Key + } + return nil +} + +func (m *PageRequest) GetOffset() uint64 { + if m != nil { + return m.Offset + } + return 0 +} + +func (m *PageRequest) GetLimit() uint64 { + if m != nil { + return m.Limit + } + return 0 +} + +func (m *PageRequest) GetCountTotal() bool { + if m != nil { + return m.CountTotal + } + return false +} + +// 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; +// } +type PageResponse struct { + // next_key is the key to be passed to PageRequest.key to + // query the next page most efficiently + NextKey []byte `protobuf:"bytes,1,opt,name=next_key,json=nextKey,proto3" json:"next_key,omitempty"` + // total is total number of results available if PageRequest.count_total + // was set, its value is undefined otherwise + Total uint64 `protobuf:"varint,2,opt,name=total,proto3" json:"total,omitempty"` +} + +func (m *PageResponse) Reset() { *m = PageResponse{} } +func (m *PageResponse) String() string { return proto.CompactTextString(m) } +func (*PageResponse) ProtoMessage() {} +func (*PageResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_4353dcf7b0208338, []int{1} +} +func (m *PageResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PageResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PageResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PageResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_PageResponse.Merge(m, src) +} +func (m *PageResponse) XXX_Size() int { + return m.Size() +} +func (m *PageResponse) XXX_DiscardUnknown() { + xxx_messageInfo_PageResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_PageResponse proto.InternalMessageInfo + +func (m *PageResponse) GetNextKey() []byte { + if m != nil { + return m.NextKey + } + return nil +} + +func (m *PageResponse) GetTotal() uint64 { + if m != nil { + return m.Total + } + return 0 +} + +func init() { + proto.RegisterType((*PageRequest)(nil), "cosmos.query.PageRequest") + proto.RegisterType((*PageResponse)(nil), "cosmos.query.PageResponse") +} + +func init() { proto.RegisterFile("cosmos/query/pagination.proto", fileDescriptor_4353dcf7b0208338) } + +var fileDescriptor_4353dcf7b0208338 = []byte{ + // 251 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0x90, 0xc1, 0x4a, 0xc3, 0x40, + 0x10, 0x86, 0xb3, 0xb6, 0xd6, 0x32, 0xcd, 0x41, 0x16, 0x91, 0x78, 0x70, 0x0d, 0x3d, 0xe5, 0x62, + 0x72, 0xf0, 0x01, 0x84, 0x5e, 0xbd, 0x48, 0xf0, 0xe4, 0xa5, 0xa4, 0x71, 0x1a, 0x97, 0x36, 0x3b, + 0x69, 0x77, 0x02, 0xe6, 0x2d, 0x7c, 0x2c, 0x8f, 0x3d, 0x7a, 0x94, 0xe4, 0x45, 0x24, 0xd9, 0x40, + 0x4f, 0xbb, 0xdf, 0xff, 0xc3, 0x7c, 0xf0, 0xc3, 0x7d, 0x4e, 0xb6, 0x24, 0x9b, 0x1c, 0x6a, 0x3c, + 0x36, 0x49, 0x95, 0x15, 0xda, 0x64, 0xac, 0xc9, 0xc4, 0xd5, 0x91, 0x98, 0xa4, 0xef, 0xea, 0x78, + 0xa8, 0x97, 0x06, 0x16, 0xaf, 0x59, 0x81, 0x29, 0x1e, 0x6a, 0xb4, 0x2c, 0xaf, 0x61, 0xb2, 0xc3, + 0x26, 0x10, 0xa1, 0x88, 0xfc, 0xb4, 0xff, 0xca, 0x5b, 0x98, 0xd1, 0x76, 0x6b, 0x91, 0x83, 0x8b, + 0x50, 0x44, 0xd3, 0x74, 0x24, 0x79, 0x03, 0x97, 0x7b, 0x5d, 0x6a, 0x0e, 0x26, 0x43, 0xec, 0x40, + 0x3e, 0xc0, 0x22, 0xa7, 0xda, 0xf0, 0x9a, 0x89, 0xb3, 0x7d, 0x30, 0x0d, 0x45, 0x34, 0x4f, 0x61, + 0x88, 0xde, 0xfa, 0x64, 0xf9, 0x0c, 0xbe, 0xf3, 0xd9, 0x8a, 0x8c, 0x45, 0x79, 0x07, 0x73, 0x83, + 0x5f, 0xbc, 0x3e, 0x5b, 0xaf, 0x7a, 0x7e, 0xc1, 0xa6, 0x37, 0xb8, 0x2b, 0x4e, 0xec, 0x60, 0xb5, + 0xfa, 0x69, 0x95, 0x38, 0xb5, 0x4a, 0xfc, 0xb5, 0x4a, 0x7c, 0x77, 0xca, 0x3b, 0x75, 0xca, 0xfb, + 0xed, 0x94, 0xf7, 0x1e, 0x15, 0x9a, 0x3f, 0xeb, 0x4d, 0x9c, 0x53, 0x99, 0x8c, 0x13, 0xb8, 0xe7, + 0xd1, 0x7e, 0xec, 0x12, 0x6e, 0x2a, 0x1c, 0x37, 0xd9, 0xcc, 0x86, 0x25, 0x9e, 0xfe, 0x03, 0x00, + 0x00, 0xff, 0xff, 0xe5, 0x66, 0x0a, 0x76, 0x2a, 0x01, 0x00, 0x00, +} + +func (m *PageRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PageRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PageRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CountTotal { + i-- + if m.CountTotal { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if m.Limit != 0 { + i = encodeVarintPagination(dAtA, i, uint64(m.Limit)) + i-- + dAtA[i] = 0x18 + } + if m.Offset != 0 { + i = encodeVarintPagination(dAtA, i, uint64(m.Offset)) + i-- + dAtA[i] = 0x10 + } + if len(m.Key) > 0 { + i -= len(m.Key) + copy(dAtA[i:], m.Key) + i = encodeVarintPagination(dAtA, i, uint64(len(m.Key))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *PageResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PageResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PageResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Total != 0 { + i = encodeVarintPagination(dAtA, i, uint64(m.Total)) + i-- + dAtA[i] = 0x10 + } + if len(m.NextKey) > 0 { + i -= len(m.NextKey) + copy(dAtA[i:], m.NextKey) + i = encodeVarintPagination(dAtA, i, uint64(len(m.NextKey))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintPagination(dAtA []byte, offset int, v uint64) int { + offset -= sovPagination(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *PageRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Key) + if l > 0 { + n += 1 + l + sovPagination(uint64(l)) + } + if m.Offset != 0 { + n += 1 + sovPagination(uint64(m.Offset)) + } + if m.Limit != 0 { + n += 1 + sovPagination(uint64(m.Limit)) + } + if m.CountTotal { + n += 2 + } + return n +} + +func (m *PageResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.NextKey) + if l > 0 { + n += 1 + l + sovPagination(uint64(l)) + } + if m.Total != 0 { + n += 1 + sovPagination(uint64(m.Total)) + } + return n +} + +func sovPagination(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozPagination(x uint64) (n int) { + return sovPagination(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *PageRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPagination + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PageRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PageRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPagination + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPagination + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPagination + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Key = append(m.Key[:0], dAtA[iNdEx:postIndex]...) + if m.Key == nil { + m.Key = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType) + } + m.Offset = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPagination + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Offset |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Limit", wireType) + } + m.Limit = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPagination + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Limit |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CountTotal", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPagination + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CountTotal = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipPagination(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPagination + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthPagination + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PageResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPagination + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PageResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PageResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NextKey", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPagination + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthPagination + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthPagination + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NextKey = append(m.NextKey[:0], dAtA[iNdEx:postIndex]...) + if m.NextKey == nil { + m.NextKey = []byte{} + } + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Total", wireType) + } + m.Total = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowPagination + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Total |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipPagination(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthPagination + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthPagination + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipPagination(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPagination + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPagination + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowPagination + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthPagination + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupPagination + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthPagination + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthPagination = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowPagination = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupPagination = fmt.Errorf("proto: unexpected end of group") +) diff --git a/types/query/pagination_test.go b/types/query/pagination_test.go new file mode 100644 index 0000000000..191fc8a648 --- /dev/null +++ b/types/query/pagination_test.go @@ -0,0 +1,213 @@ +package query_test + +import ( + gocontext "context" + "fmt" + "testing" + + "github.com/cosmos/cosmos-sdk/store/prefix" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + + "github.com/cosmos/cosmos-sdk/baseapp" + + "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tm-db" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" +) + +const ( + holder = "holder" + multiPerm = "multiple permissions account" + randomPerm = "random permission" + numBalances = 235 + defaultLimit = 100 + overLimit = 101 + underLimit = 10 + lastPageRecords = 35 +) + +func TestPagination(t *testing.T) { + app, ctx := setupTest() + queryHelper := baseapp.NewQueryServerTestHelper(ctx) + types.RegisterQueryServer(queryHelper, app.BankKeeper) + queryClient := types.NewQueryClient(queryHelper) + + var balances sdk.Coins + + for i := 0; i < numBalances; i++ { + denom := fmt.Sprintf("foo%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 100)) + } + + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + app.AccountKeeper.SetAccount(ctx, acc1) + require.NoError(t, app.BankKeeper.SetBalances(ctx, addr1, balances)) + + t.Log("verify empty page request results a max of defaultLimit records and counts total records") + pageReq := &query.PageRequest{} + request := types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err := queryClient.AllBalances(gocontext.Background(), request) + require.NoError(t, err) + require.Equal(t, res.Res.Total, uint64(numBalances)) + require.Nil(t, res.Res.NextKey) + require.LessOrEqual(t, res.Balances.Len(), defaultLimit) + + 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) + res, err = queryClient.AllBalances(gocontext.Background(), request) + require.NoError(t, err) + require.Equal(t, res.Res.Total, uint64(0)) + require.NotNil(t, res.Res.NextKey) + require.LessOrEqual(t, res.Balances.Len(), overLimit) + + t.Log("verify paginate with custom limit and countTotal true") + pageReq = &query.PageRequest{Limit: underLimit, CountTotal: true} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + require.NoError(t, err) + require.Equal(t, res.Balances.Len(), underLimit) + require.Nil(t, res.Res.NextKey) + require.Equal(t, res.Res.Total, uint64(numBalances)) + + t.Log("verify paginate with custom limit and countTotal false") + pageReq = &query.PageRequest{Limit: defaultLimit, CountTotal: false} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + require.NoError(t, err) + require.Equal(t, res.Balances.Len(), defaultLimit) + require.NotNil(t, res.Res.NextKey) + require.Equal(t, res.Res.Total, uint64(0)) + + t.Log("verify paginate with custom limit, key and countTotal false") + pageReq = &query.PageRequest{Key: res.Res.NextKey, Limit: defaultLimit, CountTotal: false} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + require.NoError(t, err) + require.Equal(t, res.Balances.Len(), defaultLimit) + require.NotNil(t, res.Res.NextKey) + require.Equal(t, res.Res.Total, uint64(0)) + + t.Log("verify paginate for last page, results in records less than max limit") + pageReq = &query.PageRequest{Key: res.Res.NextKey, Limit: defaultLimit, CountTotal: false} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + require.NoError(t, err) + require.LessOrEqual(t, res.Balances.Len(), defaultLimit) + require.Equal(t, res.Balances.Len(), lastPageRecords) + require.Nil(t, res.Res.NextKey) + require.Equal(t, res.Res.Total, uint64(0)) + + t.Log("verify paginate with offset and limit") + pageReq = &query.PageRequest{Offset: 200, Limit: defaultLimit, CountTotal: false} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + require.NoError(t, err) + require.LessOrEqual(t, res.Balances.Len(), defaultLimit) + require.Equal(t, res.Balances.Len(), lastPageRecords) + require.Nil(t, res.Res.NextKey) + require.Equal(t, res.Res.Total, uint64(0)) + + t.Log("verify paginate with offset and limit") + pageReq = &query.PageRequest{Offset: 100, Limit: defaultLimit, CountTotal: false} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + require.NoError(t, err) + require.LessOrEqual(t, res.Balances.Len(), defaultLimit) + require.NotNil(t, res.Res.NextKey) + require.Equal(t, res.Res.Total, uint64(0)) + + t.Log("verify paginate with offset and key - error") + pageReq = &query.PageRequest{Key: res.Res.NextKey, Offset: 100, Limit: defaultLimit, CountTotal: false} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + require.Error(t, err) + require.Equal(t, err.Error(), "invalid request, either offset or key is expected, got both") + + t.Log("verify paginate with offset greater than total results") + pageReq = &query.PageRequest{Offset: 300, Limit: defaultLimit, CountTotal: false} + request = types.NewQueryAllBalancesRequest(addr1, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), request) + require.NoError(t, err) + require.LessOrEqual(t, res.Balances.Len(), 0) + require.Nil(t, res.Res.NextKey) +} + +func ExamplePaginate() { + app, ctx := setupTest() + + var balances sdk.Coins + + for i := 0; i < 2; i++ { + denom := fmt.Sprintf("foo%ddenom", i) + balances = append(balances, sdk.NewInt64Coin(denom, 100)) + } + + addr1 := sdk.AccAddress([]byte("addr1")) + acc1 := app.AccountKeeper.NewAccountWithAddress(ctx, addr1) + app.AccountKeeper.SetAccount(ctx, acc1) + err := app.BankKeeper.SetBalances(ctx, addr1, balances) + if err != nil { + fmt.Println(err) + } + // Paginate example + pageReq := &query.PageRequest{Key: nil, Limit: 1, CountTotal: true} + request := types.NewQueryAllBalancesRequest(addr1, pageReq) + balResult := sdk.NewCoins() + authStore := ctx.KVStore(app.GetKey(authtypes.StoreKey)) + balancesStore := prefix.NewStore(authStore, types.BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr1.Bytes()) + res, err := query.Paginate(accountStore, request.Req, func(key []byte, value []byte) error { + var tempRes sdk.Coin + err := app.Codec().UnmarshalBinaryBare(value, &tempRes) + if err != nil { + return err + } + balResult = append(balResult, tempRes) + return nil + }) + if err != nil { // should return no error + fmt.Println(err) + } + fmt.Println(&types.QueryAllBalancesResponse{Balances: balResult, Res: res}) + // Output: + // balances: res: +} + +func setupTest() (*simapp.SimApp, sdk.Context) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, abci.Header{Height: 1}) + appCodec := app.AppCodec() + + db := dbm.NewMemDB() + ms := store.NewCommitMultiStore(db) + + ms.LoadLatestVersion() + + maccPerms := simapp.GetMaccPerms() + maccPerms[holder] = nil + maccPerms[authtypes.Burner] = []string{authtypes.Burner} + maccPerms[authtypes.Minter] = []string{authtypes.Minter} + maccPerms[multiPerm] = []string{authtypes.Burner, authtypes.Minter, authtypes.Staking} + maccPerms[randomPerm] = []string{"random"} + app.AccountKeeper = authkeeper.NewAccountKeeper( + appCodec, app.GetKey(authtypes.StoreKey), app.GetSubspace(authtypes.ModuleName), + authtypes.ProtoBaseAccount, maccPerms, + ) + app.BankKeeper = bankkeeper.NewBaseKeeper( + appCodec, app.GetKey(authtypes.StoreKey), app.AccountKeeper, + app.GetSubspace(types.ModuleName), make(map[string]bool), + ) + + return app, ctx +} diff --git a/x/bank/client/cli/query.go b/x/bank/client/cli/query.go index 87ec8a28f8..a310c76112 100644 --- a/x/bank/client/cli/query.go +++ b/x/bank/client/cli/query.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/bank/types" ) @@ -50,9 +51,9 @@ func GetBalancesCmd(clientCtx client.Context) *cobra.Command { } denom := viper.GetString(flagDenom) - + pageReq := &query.PageRequest{} if denom == "" { - params := types.NewQueryAllBalancesRequest(addr) + params := types.NewQueryAllBalancesRequest(addr, pageReq) res, err := queryClient.AllBalances(context.Background(), params) if err != nil { return err @@ -71,7 +72,6 @@ func GetBalancesCmd(clientCtx client.Context) *cobra.Command { } cmd.Flags().String(flagDenom, "", "The specific balance denomination to query for") - return flags.GetCommands(cmd)[0] } diff --git a/x/bank/client/rest/query.go b/x/bank/client/rest/query.go index f282115f7c..a599a7c1f9 100644 --- a/x/bank/client/rest/query.go +++ b/x/bank/client/rest/query.go @@ -49,7 +49,7 @@ func QueryBalancesRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { denom := r.FormValue("denom") if denom == "" { - params = types.NewQueryAllBalancesRequest(addr) + params = types.NewQueryAllBalancesRequest(addr, nil) route = fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryAllBalances) } else { params = types.NewQueryBalanceRequest(addr, denom) diff --git a/x/bank/keeper/grpc_query.go b/x/bank/keeper/grpc_query.go index 9f78cb41ee..b0422682d6 100644 --- a/x/bank/keeper/grpc_query.go +++ b/x/bank/keeper/grpc_query.go @@ -3,6 +3,8 @@ package keeper import ( "context" + "github.com/cosmos/cosmos-sdk/store/prefix" + "github.com/cosmos/cosmos-sdk/types/query" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -38,14 +40,33 @@ func (q BaseKeeper) AllBalances(c context.Context, req *types.QueryAllBalancesRe return nil, status.Errorf(codes.InvalidArgument, "empty request") } - if len(req.Address) == 0 { + addr := req.Address + if len(addr) == 0 { return nil, status.Errorf(codes.InvalidArgument, "invalid address") } ctx := sdk.UnwrapSDKContext(c) - balances := q.GetAllBalances(ctx, req.Address) - return &types.QueryAllBalancesResponse{Balances: balances}, nil + balances := sdk.NewCoins() + store := ctx.KVStore(q.storeKey) + balancesStore := prefix.NewStore(store, types.BalancesPrefix) + accountStore := prefix.NewStore(balancesStore, addr.Bytes()) + + res, err := query.Paginate(accountStore, req.Req, func(key []byte, value []byte) error { + var result sdk.Coin + err := q.cdc.UnmarshalBinaryBare(value, &result) + if err != nil { + return err + } + balances = append(balances, result) + return nil + }) + + if err != nil { + return &types.QueryAllBalancesResponse{}, err + } + + return &types.QueryAllBalancesResponse{Balances: balances, Res: res}, nil } // TotalSupply implements the Query/TotalSupply gRPC method diff --git a/x/bank/keeper/grpc_query_test.go b/x/bank/keeper/grpc_query_test.go index e25f2a6ac3..3902ed4ad9 100644 --- a/x/bank/keeper/grpc_query_test.go +++ b/x/bank/keeper/grpc_query_test.go @@ -3,6 +3,8 @@ package keeper_test import ( gocontext "context" + "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -52,13 +54,21 @@ func (suite *IntegrationTestSuite) TestQueryAllBalances() { _, err := queryClient.AllBalances(gocontext.Background(), &types.QueryAllBalancesRequest{}) suite.Require().Error(err) - req := types.NewQueryAllBalancesRequest(addr) + pageReq := &query.PageRequest{ + Key: nil, + Limit: 1, + CountTotal: false, + } + req := types.NewQueryAllBalancesRequest(addr, pageReq) res, err := queryClient.AllBalances(gocontext.Background(), req) suite.Require().NoError(err) suite.Require().NotNil(res) suite.True(res.Balances.IsZero()) - origCoins := sdk.NewCoins(newFooCoin(50), newBarCoin(30)) + fooCoins := newFooCoin(50) + barCoins := newBarCoin(30) + + origCoins := sdk.NewCoins(fooCoins, barCoins) acc := app.AccountKeeper.NewAccountWithAddress(ctx, addr) app.AccountKeeper.SetAccount(ctx, acc) @@ -67,7 +77,19 @@ func (suite *IntegrationTestSuite) TestQueryAllBalances() { res, err = queryClient.AllBalances(gocontext.Background(), req) suite.Require().NoError(err) suite.Require().NotNil(res) - suite.True(res.Balances.IsEqual(origCoins)) + suite.Equal(res.Balances.Len(), 1) + suite.NotNil(res.Res.NextKey) + + suite.T().Log("query second page with nextkey") + pageReq = &query.PageRequest{ + Key: res.Res.NextKey, + Limit: 1, + CountTotal: true, + } + req = types.NewQueryAllBalancesRequest(addr, pageReq) + res, err = queryClient.AllBalances(gocontext.Background(), req) + suite.Equal(res.Balances.Len(), 1) + suite.Nil(res.Res.NextKey) } func (suite *IntegrationTestSuite) TestQueryTotalSupply() { diff --git a/x/bank/keeper/keeper_test.go b/x/bank/keeper/keeper_test.go index 359bef9155..61219582ae 100644 --- a/x/bank/keeper/keeper_test.go +++ b/x/bank/keeper/keeper_test.go @@ -275,6 +275,7 @@ func (suite *IntegrationTestSuite) TestSendCoinsNewAccount() { addr2 := sdk.AccAddress([]byte("addr2")) suite.Require().Nil(app.AccountKeeper.GetAccount(ctx, addr2)) + app.BankKeeper.GetAllBalances(ctx, addr2) suite.Require().Empty(app.BankKeeper.GetAllBalances(ctx, addr2)) sendAmt := sdk.NewCoins(newFooCoin(50), newBarCoin(25)) diff --git a/x/bank/keeper/querier_test.go b/x/bank/keeper/querier_test.go index f7225f98db..5fb7122c62 100644 --- a/x/bank/keeper/querier_test.go +++ b/x/bank/keeper/querier_test.go @@ -61,7 +61,7 @@ func (suite *IntegrationTestSuite) TestQuerier_QueryAllBalances() { suite.Require().NotNil(err) suite.Require().Nil(res) - req.Data = app.Codec().MustMarshalJSON(types.NewQueryAllBalancesRequest(addr)) + req.Data = app.Codec().MustMarshalJSON(types.NewQueryAllBalancesRequest(addr, nil)) res, err = querier(ctx, []string{types.QueryAllBalances}, req) suite.Require().NoError(err) suite.Require().NotNil(res) diff --git a/x/bank/keeper/view.go b/x/bank/keeper/view.go index 40043f9c81..fa707e6beb 100644 --- a/x/bank/keeper/view.go +++ b/x/bank/keeper/view.go @@ -23,7 +23,6 @@ type ViewKeeper interface { GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin - LockedCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins diff --git a/x/bank/types/querier.go b/x/bank/types/querier.go index 5599f64afc..a2992a1b4b 100644 --- a/x/bank/types/querier.go +++ b/x/bank/types/querier.go @@ -2,6 +2,7 @@ package types import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" ) // Querier path constants @@ -18,8 +19,8 @@ func NewQueryBalanceRequest(addr sdk.AccAddress, denom string) *QueryBalanceRequ } // NewQueryAllBalancesRequest creates a new instance of QueryAllBalancesRequest. -func NewQueryAllBalancesRequest(addr sdk.AccAddress) *QueryAllBalancesRequest { - return &QueryAllBalancesRequest{Address: addr} +func NewQueryAllBalancesRequest(addr sdk.AccAddress, req *query.PageRequest) *QueryAllBalancesRequest { + return &QueryAllBalancesRequest{Address: addr, Req: req} } // QueryTotalSupply defines the params for the following queries: diff --git a/x/bank/types/query.pb.go b/x/bank/types/query.pb.go index f1fc663dbc..4c49242bd5 100644 --- a/x/bank/types/query.pb.go +++ b/x/bank/types/query.pb.go @@ -8,6 +8,7 @@ import ( fmt "fmt" github_com_cosmos_cosmos_sdk_types "github.com/cosmos/cosmos-sdk/types" types "github.com/cosmos/cosmos-sdk/types" + query "github.com/cosmos/cosmos-sdk/types/query" _ "github.com/gogo/protobuf/gogoproto" grpc1 "github.com/gogo/protobuf/grpc" proto "github.com/gogo/protobuf/proto" @@ -135,6 +136,7 @@ func (m *QueryBalanceResponse) GetBalance() *types.Coin { type QueryAllBalancesRequest struct { // address is the address to query balances for Address github_com_cosmos_cosmos_sdk_types.AccAddress `protobuf:"bytes,1,opt,name=address,proto3,casttype=github.com/cosmos/cosmos-sdk/types.AccAddress" json:"address,omitempty"` + Req *query.PageRequest `protobuf:"bytes,2,opt,name=req,proto3" json:"req,omitempty"` } func (m *QueryAllBalancesRequest) Reset() { *m = QueryAllBalancesRequest{} } @@ -177,10 +179,18 @@ func (m *QueryAllBalancesRequest) GetAddress() github_com_cosmos_cosmos_sdk_type return nil } +func (m *QueryAllBalancesRequest) GetReq() *query.PageRequest { + if m != nil { + return m.Req + } + return nil +} + // QueryAllBalancesResponse is the response type for the Query/AllBalances RPC method type QueryAllBalancesResponse struct { // balances is the balances of the coins Balances github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,1,rep,name=balances,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"balances"` + Res *query.PageResponse `protobuf:"bytes,2,opt,name=res,proto3" json:"res,omitempty"` } func (m *QueryAllBalancesResponse) Reset() { *m = QueryAllBalancesResponse{} } @@ -223,6 +233,13 @@ func (m *QueryAllBalancesResponse) GetBalances() github_com_cosmos_cosmos_sdk_ty return nil } +func (m *QueryAllBalancesResponse) GetRes() *query.PageResponse { + if m != nil { + return m.Res + } + return nil +} + // QueryTotalSupplyRequest is the request type for the Query/TotalSupply RPC method type QueryTotalSupplyRequest struct { } @@ -404,37 +421,40 @@ func init() { func init() { proto.RegisterFile("cosmos/bank/query.proto", fileDescriptor_1b02ea4db7d9aa9f) } var fileDescriptor_1b02ea4db7d9aa9f = []byte{ - // 473 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x54, 0x4d, 0x6f, 0xd3, 0x40, - 0x10, 0xb5, 0x8b, 0x9a, 0x94, 0x49, 0x4f, 0xdb, 0xa0, 0x06, 0x1f, 0xec, 0xb0, 0x82, 0x2a, 0x48, - 0x74, 0x0d, 0xe5, 0x8e, 0x14, 0x57, 0x42, 0x42, 0x1c, 0x00, 0x17, 0x71, 0xa8, 0x90, 0x90, 0x3f, - 0xb6, 0xa1, 0xaa, 0xed, 0x75, 0xbd, 0x36, 0x6a, 0xfe, 0x05, 0xbf, 0x83, 0x5f, 0xd2, 0x63, 0x8f, - 0x88, 0x43, 0x40, 0xc9, 0x8d, 0x9f, 0xc0, 0x09, 0x79, 0x77, 0x5d, 0x39, 0xb1, 0x15, 0x7a, 0xa0, - 0xb7, 0x64, 0xe6, 0xcd, 0x7b, 0x6f, 0xf6, 0xad, 0x17, 0x76, 0x03, 0xc6, 0x63, 0xc6, 0x6d, 0xdf, - 0x4b, 0xce, 0xec, 0xf3, 0x82, 0x66, 0x53, 0x92, 0x66, 0x2c, 0x67, 0xa8, 0x27, 0x1b, 0xa4, 0x6c, - 0x18, 0xfd, 0x09, 0x9b, 0x30, 0x51, 0xb7, 0xcb, 0x5f, 0x12, 0x62, 0xec, 0xa8, 0x59, 0x85, 0x14, - 0x45, 0x7c, 0x01, 0x3b, 0xef, 0x4a, 0x1a, 0xc7, 0x8b, 0xbc, 0x24, 0xa0, 0x2e, 0x3d, 0x2f, 0x28, - 0xcf, 0xd1, 0x6b, 0xe8, 0x7a, 0x61, 0x98, 0x51, 0xce, 0x07, 0xfa, 0x50, 0x1f, 0x6d, 0x3b, 0xcf, - 0xfe, 0xcc, 0xac, 0xfd, 0xc9, 0x69, 0xfe, 0xb9, 0xf0, 0x49, 0xc0, 0x62, 0x7b, 0x89, 0x6b, 0x9f, - 0x87, 0x67, 0x76, 0x3e, 0x4d, 0x29, 0x27, 0xe3, 0x20, 0x18, 0xcb, 0x41, 0xb7, 0x62, 0x40, 0x7d, - 0xd8, 0x0c, 0x69, 0xc2, 0xe2, 0xc1, 0xc6, 0x50, 0x1f, 0xdd, 0x75, 0xe5, 0x1f, 0xfc, 0x02, 0xfa, - 0xcb, 0xca, 0x3c, 0x65, 0x09, 0xa7, 0x68, 0x0f, 0xba, 0xbe, 0x2c, 0x09, 0xe9, 0xde, 0xc1, 0x36, - 0x51, 0x8e, 0x0f, 0xd9, 0x69, 0xe2, 0x56, 0x4d, 0x7c, 0x02, 0xbb, 0x62, 0x7e, 0x1c, 0x45, 0x8a, - 0x82, 0xdf, 0x86, 0x7b, 0xfc, 0x05, 0x06, 0x4d, 0x1d, 0xe5, 0xf5, 0x18, 0xb6, 0x94, 0x9d, 0x52, - 0xe9, 0xce, 0xaa, 0x59, 0xe7, 0xe9, 0xe5, 0xcc, 0xd2, 0xbe, 0xfd, 0xb4, 0x46, 0x37, 0xd0, 0x2e, - 0x07, 0xb8, 0x7b, 0xcd, 0x87, 0xef, 0xab, 0xfd, 0xde, 0xb3, 0xdc, 0x8b, 0x8e, 0x8a, 0x34, 0x8d, - 0xa6, 0x6a, 0x3f, 0x9c, 0x29, 0x4b, 0x4b, 0x2d, 0x65, 0xe9, 0x03, 0x74, 0xb8, 0xa8, 0xfc, 0x27, - 0x43, 0x8a, 0x0d, 0x3f, 0x51, 0x71, 0x49, 0xb9, 0x37, 0x27, 0xd5, 0x59, 0x5f, 0x87, 0xab, 0xd7, - 0xc3, 0xfd, 0x04, 0xf7, 0x56, 0xd0, 0xca, 0xde, 0x4b, 0xe8, 0x78, 0x31, 0x2b, 0x92, 0x5c, 0xe2, - 0x1d, 0x52, 0x1a, 0xfa, 0x31, 0xb3, 0xf6, 0x6e, 0x60, 0xe8, 0x55, 0x92, 0xbb, 0x6a, 0xfa, 0xe0, - 0xf7, 0x06, 0x6c, 0x0a, 0x05, 0xf4, 0x16, 0xba, 0x2a, 0x17, 0x34, 0x24, 0xb5, 0xaf, 0x80, 0xb4, - 0xdc, 0x6b, 0xe3, 0xc1, 0x1a, 0x84, 0x74, 0x88, 0x35, 0xf4, 0x11, 0x7a, 0xb5, 0xb0, 0xd1, 0xc3, - 0xe6, 0x4c, 0xf3, 0xce, 0x19, 0x8f, 0xfe, 0x81, 0xaa, 0xb3, 0xd7, 0x72, 0x6b, 0x63, 0x6f, 0x26, - 0xde, 0xc6, 0xde, 0x12, 0x3e, 0xd6, 0xd0, 0x11, 0x6c, 0x55, 0x67, 0x8e, 0x5a, 0x96, 0x5d, 0x49, - 0xcf, 0xc0, 0xeb, 0x20, 0x15, 0xa9, 0x73, 0x78, 0x39, 0x37, 0xf5, 0xab, 0xb9, 0xa9, 0xff, 0x9a, - 0x9b, 0xfa, 0xd7, 0x85, 0xa9, 0x5d, 0x2d, 0x4c, 0xed, 0xfb, 0xc2, 0xd4, 0x8e, 0x1f, 0xaf, 0x8d, - 0xed, 0x42, 0xbe, 0x53, 0x22, 0x3d, 0xbf, 0x23, 0x1e, 0x9c, 0xe7, 0x7f, 0x03, 0x00, 0x00, 0xff, - 0xff, 0x27, 0x7c, 0xfe, 0x36, 0xc3, 0x04, 0x00, 0x00, + // 527 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x94, 0xc1, 0x6e, 0xd3, 0x30, + 0x18, 0xc7, 0x93, 0x4d, 0x6b, 0x87, 0xbb, 0x93, 0x57, 0xb4, 0x2e, 0x12, 0x69, 0xb1, 0x60, 0x2a, + 0x62, 0x4b, 0xa0, 0xdc, 0x91, 0xda, 0x49, 0x48, 0x88, 0x03, 0x23, 0x43, 0x1c, 0x26, 0x24, 0x94, + 0xa6, 0x26, 0x54, 0x4b, 0xed, 0x34, 0x4e, 0xa4, 0xf5, 0x2d, 0x90, 0x78, 0x05, 0x4e, 0x3c, 0xc9, + 0x8e, 0x3b, 0x22, 0x0e, 0x05, 0xb5, 0x37, 0x1e, 0x81, 0x13, 0xb2, 0xfd, 0x65, 0x4a, 0xdb, 0xa8, + 0xec, 0xc0, 0x6e, 0x89, 0xfd, 0xff, 0xfe, 0xfe, 0x7d, 0xfe, 0x7f, 0x09, 0xda, 0x0b, 0xb8, 0x18, + 0x71, 0xe1, 0xf6, 0x7d, 0x76, 0xee, 0x8e, 0x33, 0x9a, 0x4c, 0x9c, 0x38, 0xe1, 0x29, 0xc7, 0x35, + 0xbd, 0xe1, 0xc8, 0x0d, 0xeb, 0x1e, 0xa8, 0x94, 0xc0, 0x8d, 0xfd, 0x70, 0xc8, 0xfc, 0x74, 0xc8, + 0x99, 0xd6, 0x5a, 0xf5, 0x90, 0x87, 0x5c, 0x3d, 0xba, 0xf2, 0x09, 0x56, 0x77, 0xa1, 0x08, 0x8c, + 0xd4, 0x22, 0xb9, 0x40, 0xbb, 0x6f, 0xa4, 0x49, 0xcf, 0x8f, 0x7c, 0x16, 0x50, 0x8f, 0x8e, 0x33, + 0x2a, 0x52, 0xfc, 0x0a, 0x55, 0xfd, 0xc1, 0x20, 0xa1, 0x42, 0x34, 0xcc, 0x96, 0xd9, 0xde, 0xe9, + 0x3d, 0xfd, 0x33, 0x6d, 0x1e, 0x85, 0xc3, 0xf4, 0x53, 0xd6, 0x77, 0x02, 0x3e, 0x72, 0x17, 0xbc, + 0x8e, 0xc4, 0xe0, 0xdc, 0x4d, 0x27, 0x31, 0x15, 0x4e, 0x37, 0x08, 0xba, 0xba, 0xd0, 0xcb, 0x1d, + 0x70, 0x1d, 0x6d, 0x0d, 0x28, 0xe3, 0xa3, 0xc6, 0x46, 0xcb, 0x6c, 0xdf, 0xf1, 0xf4, 0x0b, 0x79, + 0x8e, 0xea, 0x8b, 0x27, 0x8b, 0x98, 0x33, 0x41, 0xf1, 0x01, 0xaa, 0xf6, 0xf5, 0x92, 0x3a, 0xba, + 0xd6, 0xd9, 0x71, 0x80, 0xf8, 0x98, 0x0f, 0x99, 0x97, 0x6f, 0x92, 0x2f, 0x26, 0xda, 0x53, 0x06, + 0xdd, 0x28, 0x02, 0x0f, 0x71, 0x2b, 0xf8, 0x8f, 0xd1, 0x66, 0x42, 0xc7, 0x0a, 0xbe, 0xd6, 0xd9, + 0xcf, 0x61, 0x74, 0x36, 0x27, 0x7e, 0x98, 0xdf, 0x99, 0x27, 0x55, 0xe4, 0xab, 0x89, 0x1a, 0xab, + 0x54, 0xd0, 0xda, 0x19, 0xda, 0x06, 0x7a, 0xc9, 0xb5, 0xb9, 0xdc, 0x5b, 0xef, 0xc9, 0xe5, 0xb4, + 0x69, 0x7c, 0xfb, 0xd9, 0x6c, 0xdf, 0x80, 0x54, 0x16, 0x08, 0xef, 0xda, 0x0f, 0x1f, 0x4a, 0x4a, + 0x01, 0x94, 0x56, 0x19, 0xa5, 0x86, 0x90, 0x98, 0x82, 0xec, 0xc3, 0xdd, 0xbd, 0xe5, 0xa9, 0x1f, + 0x9d, 0x66, 0x71, 0x1c, 0x4d, 0xa0, 0x0d, 0x92, 0x40, 0x03, 0x0b, 0x5b, 0xd0, 0xc0, 0x3b, 0x54, + 0x11, 0x6a, 0xe5, 0x3f, 0xe1, 0x83, 0x1b, 0x39, 0x84, 0x59, 0xd0, 0xc7, 0xbd, 0xfe, 0x98, 0xe7, + 0x78, 0x3d, 0x39, 0x66, 0x71, 0x72, 0x3e, 0xa0, 0xbb, 0x4b, 0x6a, 0xc0, 0x7b, 0x81, 0x2a, 0xfe, + 0x88, 0x67, 0x2c, 0xd5, 0xfa, 0x9e, 0x23, 0x81, 0x7e, 0x4c, 0x9b, 0x07, 0x37, 0x00, 0x7a, 0xc9, + 0x52, 0x0f, 0xaa, 0x3b, 0xbf, 0x37, 0xd0, 0x96, 0x3a, 0x01, 0x9f, 0xa0, 0x2a, 0xa4, 0x88, 0x5b, + 0x4e, 0xe1, 0x0b, 0x74, 0x4a, 0x3e, 0x1a, 0xeb, 0xfe, 0x1a, 0x85, 0x26, 0x24, 0x06, 0x7e, 0x8f, + 0x6a, 0x85, 0xd1, 0xc0, 0x0f, 0x56, 0x6b, 0x56, 0xe7, 0xd9, 0x7a, 0xf8, 0x0f, 0x55, 0xd1, 0xbd, + 0x90, 0x5b, 0x99, 0xfb, 0x6a, 0xe2, 0x65, 0xee, 0x25, 0xe1, 0x13, 0x03, 0x9f, 0xa2, 0xed, 0xfc, + 0xce, 0x71, 0x49, 0xb3, 0x4b, 0xe9, 0x59, 0x64, 0x9d, 0x24, 0x37, 0xed, 0x1d, 0x5f, 0xce, 0x6c, + 0xf3, 0x6a, 0x66, 0x9b, 0xbf, 0x66, 0xb6, 0xf9, 0x79, 0x6e, 0x1b, 0x57, 0x73, 0xdb, 0xf8, 0x3e, + 0xb7, 0x8d, 0xb3, 0x47, 0x6b, 0x63, 0xbb, 0xd0, 0xff, 0x48, 0x95, 0x5e, 0xbf, 0xa2, 0xfe, 0x66, + 0xcf, 0xfe, 0x06, 0x00, 0x00, 0xff, 0xff, 0x6e, 0x62, 0xaf, 0x8a, 0x3f, 0x05, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -725,6 +745,18 @@ func (m *QueryAllBalancesRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l + if m.Req != nil { + { + size, err := m.Req.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if len(m.Address) > 0 { i -= len(m.Address) copy(dAtA[i:], m.Address) @@ -755,6 +787,18 @@ func (m *QueryAllBalancesResponse) MarshalToSizedBuffer(dAtA []byte) (int, error _ = i var l int _ = l + if m.Res != nil { + { + size, err := m.Res.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if len(m.Balances) > 0 { for iNdEx := len(m.Balances) - 1; iNdEx >= 0; iNdEx-- { { @@ -946,6 +990,10 @@ func (m *QueryAllBalancesRequest) Size() (n int) { if l > 0 { n += 1 + l + sovQuery(uint64(l)) } + if m.Req != nil { + l = m.Req.Size() + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -961,6 +1009,10 @@ func (m *QueryAllBalancesResponse) Size() (n int) { n += 1 + l + sovQuery(uint64(l)) } } + if m.Res != nil { + l = m.Res.Size() + n += 1 + l + sovQuery(uint64(l)) + } return n } @@ -1289,6 +1341,42 @@ func (m *QueryAllBalancesRequest) Unmarshal(dAtA []byte) error { m.Address = []byte{} } iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Req", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Req == nil { + m.Req = &query.PageRequest{} + } + if err := m.Req.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) @@ -1376,6 +1464,42 @@ func (m *QueryAllBalancesResponse) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Res", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Res == nil { + m.Res = &query.PageResponse{} + } + if err := m.Res.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:]) diff --git a/x/distribution/genesis.go b/x/distribution/genesis.go index a27885b6d3..1d9e9ba64e 100644 --- a/x/distribution/genesis.go +++ b/x/distribution/genesis.go @@ -48,7 +48,8 @@ func InitGenesis(ctx sdk.Context, ak types.AccountKeeper, bk types.BankKeeper, k panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) } - if bk.GetAllBalances(ctx, moduleAcc.GetAddress()).IsZero() { + balances := bk.GetAllBalances(ctx, moduleAcc.GetAddress()) + if balances.IsZero() { if err := bk.SetBalances(ctx, moduleAcc.GetAddress(), moduleHoldingsInt); err != nil { panic(err) }