268 lines
7.8 KiB
Go
268 lines
7.8 KiB
Go
package keeper
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
|
|
"github.com/cosmos/cosmos-sdk/store/prefix"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
"github.com/cosmos/cosmos-sdk/types/query"
|
|
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
|
|
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
|
)
|
|
|
|
var _ types.QueryServer = (*Keeper)(nil)
|
|
|
|
// Channel implements the Query/Channel gRPC method
|
|
func (q Keeper) Channel(c context.Context, req *types.QueryChannelRequest) (*types.QueryChannelResponse, error) {
|
|
if req == nil {
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
}
|
|
|
|
if err := validategRPCRequest(req.PortID, req.ChannelID); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
channel, found := q.GetChannel(ctx, req.PortID, req.ChannelID)
|
|
if !found {
|
|
return nil, status.Error(
|
|
codes.NotFound,
|
|
sdkerrors.Wrapf(types.ErrChannelNotFound, "port-id: %s, channel-id %s", req.PortID, req.ChannelID).Error(),
|
|
)
|
|
}
|
|
|
|
return types.NewQueryChannelResponse(req.PortID, req.ChannelID, channel, nil, ctx.BlockHeight()), nil
|
|
}
|
|
|
|
// Channels implements the Query/Channels gRPC method
|
|
func (q Keeper) Channels(c context.Context, req *types.QueryChannelsRequest) (*types.QueryChannelsResponse, error) {
|
|
if req == nil {
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
}
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
channels := []*types.IdentifiedChannel{}
|
|
store := prefix.NewStore(ctx.KVStore(q.storeKey), []byte(host.KeyChannelPrefix))
|
|
|
|
res, err := query.Paginate(store, req.Req, func(key, value []byte) error {
|
|
var result types.Channel
|
|
if err := q.cdc.UnmarshalBinaryBare(value, &result); err != nil {
|
|
return err
|
|
}
|
|
|
|
portID, channelID, err := host.ParseChannelPath(string(key))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
identifiedChannel := types.NewIdentifiedChannel(portID, channelID, result)
|
|
channels = append(channels, &identifiedChannel)
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.QueryChannelsResponse{
|
|
Channels: channels,
|
|
Res: res,
|
|
Height: ctx.BlockHeight(),
|
|
}, nil
|
|
}
|
|
|
|
// ConnectionChannels implements the Query/ConnectionChannels gRPC method
|
|
func (q Keeper) ConnectionChannels(c context.Context, req *types.QueryConnectionChannelsRequest) (*types.QueryConnectionChannelsResponse, error) {
|
|
if req == nil {
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
}
|
|
|
|
if err := host.ConnectionIdentifierValidator(req.Connection); err != nil {
|
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
|
}
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
channels := []*types.IdentifiedChannel{}
|
|
store := prefix.NewStore(ctx.KVStore(q.storeKey), []byte(host.KeyChannelPrefix))
|
|
|
|
res, err := query.Paginate(store, req.Req, func(key, value []byte) error {
|
|
var result types.Channel
|
|
if err := q.cdc.UnmarshalBinaryBare(value, &result); err != nil {
|
|
return err
|
|
}
|
|
|
|
// ignore channel and continue to the next item if the connection is
|
|
// different than the requested one
|
|
if result.ConnectionHops[0] != req.Connection {
|
|
return nil
|
|
}
|
|
|
|
portID, channelID, err := host.ParseChannelPath(string(key))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
identifiedChannel := types.NewIdentifiedChannel(portID, channelID, result)
|
|
channels = append(channels, &identifiedChannel)
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.QueryConnectionChannelsResponse{
|
|
Channels: channels,
|
|
Res: res,
|
|
Height: ctx.BlockHeight(),
|
|
}, nil
|
|
}
|
|
|
|
// PacketCommitment implements the Query/PacketCommitment gRPC method
|
|
func (q Keeper) PacketCommitment(c context.Context, req *types.QueryPacketCommitmentRequest) (*types.QueryPacketCommitmentResponse, error) {
|
|
if req == nil {
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
}
|
|
|
|
if err := validategRPCRequest(req.PortID, req.ChannelID); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if req.Sequence == 0 {
|
|
return nil, status.Error(codes.InvalidArgument, "packet sequence cannot be 0")
|
|
}
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
commitmentBz := q.GetPacketCommitment(ctx, req.PortID, req.ChannelID, req.Sequence)
|
|
if len(commitmentBz) == 0 {
|
|
return nil, status.Error(codes.NotFound, "packet commitment hash not found")
|
|
}
|
|
|
|
return types.NewQueryPacketCommitmentResponse(req.PortID, req.ChannelID, req.Sequence, commitmentBz, nil, ctx.BlockHeight()), nil
|
|
}
|
|
|
|
// PacketCommitments implements the Query/PacketCommitments gRPC method
|
|
func (q Keeper) PacketCommitments(c context.Context, req *types.QueryPacketCommitmentsRequest) (*types.QueryPacketCommitmentsResponse, error) {
|
|
if req == nil {
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
}
|
|
|
|
if err := validategRPCRequest(req.PortID, req.ChannelID); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
commitments := []*types.PacketAckCommitment{}
|
|
store := prefix.NewStore(ctx.KVStore(q.storeKey), []byte(host.PacketCommitmentPrefixPath(req.PortID, req.ChannelID)))
|
|
|
|
res, err := query.Paginate(store, req.Req, func(key, value []byte) error {
|
|
keySplit := strings.Split(string(key), "/")
|
|
|
|
sequence, err := strconv.ParseUint(keySplit[len(keySplit)-1], 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
commitment := types.NewPacketAckCommitment(req.PortID, req.ChannelID, sequence, value)
|
|
commitments = append(commitments, &commitment)
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &types.QueryPacketCommitmentsResponse{
|
|
Commitments: commitments,
|
|
Res: res,
|
|
Height: ctx.BlockHeight(),
|
|
}, nil
|
|
}
|
|
|
|
// UnrelayedPackets implements the Query/UnrelayedPackets gRPC method
|
|
func (q Keeper) UnrelayedPackets(c context.Context, req *types.QueryUnrelayedPacketsRequest) (*types.QueryUnrelayedPacketsResponse, error) {
|
|
if req == nil {
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
}
|
|
|
|
if err := validategRPCRequest(req.PortID, req.ChannelID); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
|
|
var (
|
|
unrelayedPackets = []uint64{}
|
|
store sdk.KVStore
|
|
res *query.PageResponse
|
|
err error
|
|
)
|
|
|
|
for i, seq := range req.Sequences {
|
|
if seq == 0 {
|
|
return nil, status.Errorf(codes.InvalidArgument, "packet sequence %d cannot be 0", i)
|
|
}
|
|
|
|
store = prefix.NewStore(ctx.KVStore(q.storeKey), host.KeyPacketAcknowledgement(req.PortID, req.ChannelID, seq))
|
|
res, err = query.Paginate(store, req.Req, func(_, _ []byte) error {
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
// ignore error and continue to the next sequence item
|
|
continue
|
|
}
|
|
|
|
unrelayedPackets = append(unrelayedPackets, seq)
|
|
}
|
|
return &types.QueryUnrelayedPacketsResponse{
|
|
Packets: unrelayedPackets,
|
|
Res: res,
|
|
Height: ctx.BlockHeight(),
|
|
}, nil
|
|
}
|
|
|
|
// NextSequenceReceive implements the Query/NextSequenceReceive gRPC method
|
|
func (q Keeper) NextSequenceReceive(c context.Context, req *types.QueryNextSequenceReceiveRequest) (*types.QueryNextSequenceReceiveResponse, error) {
|
|
if req == nil {
|
|
return nil, status.Error(codes.InvalidArgument, "empty request")
|
|
}
|
|
|
|
if err := validategRPCRequest(req.PortID, req.ChannelID); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ctx := sdk.UnwrapSDKContext(c)
|
|
sequence, found := q.GetNextSequenceRecv(ctx, req.PortID, req.ChannelID)
|
|
if !found {
|
|
return nil, status.Error(
|
|
codes.NotFound,
|
|
sdkerrors.Wrapf(types.ErrSequenceReceiveNotFound, "port-id: %s, channel-id %s", req.PortID, req.ChannelID).Error(),
|
|
)
|
|
}
|
|
|
|
return types.NewQueryNextSequenceReceiveResponse(req.PortID, req.ChannelID, sequence, nil, ctx.BlockHeight()), nil
|
|
}
|
|
|
|
func validategRPCRequest(portID, channelID string) error {
|
|
if err := host.PortIdentifierValidator(portID); err != nil {
|
|
return status.Error(codes.InvalidArgument, err.Error())
|
|
}
|
|
|
|
if err := host.ChannelIdentifierValidator(channelID); err != nil {
|
|
return status.Error(codes.InvalidArgument, err.Error())
|
|
}
|
|
|
|
return nil
|
|
}
|