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

Fix QueryUnreceivedPackets/Acks #7320

Merged
merged 12 commits into from
Sep 18, 2020
488 changes: 326 additions & 162 deletions client/grpc-gateway/swagger.json

Large diffs are not rendered by default.

51 changes: 38 additions & 13 deletions proto/ibc/channel/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,21 @@ service Query {
option (google.api.http).get = "/ibc/channel/v1beta1/channels/{channel_id}/ports/{port_id}/packet_acks/{sequence}";
}

// UnrelayedPackets returns all the unrelayed IBC packets associated with a
// UnreceivedPackets returns all the unrelayed IBC packets associated with a
// channel and sequences.
rpc UnrelayedPackets(QueryUnrelayedPacketsRequest) returns (QueryUnrelayedPacketsResponse) {
rpc UnreceivedPackets(QueryUnreceivedPacketsRequest) returns (QueryUnreceivedPacketsResponse) {
option (google.api.http).get = "/ibc/channel/v1beta1/channels/{channel_id}/ports/{port_id}/packet_commitments/"
"{packet_commitment_sequences}/packet_acks/{acknowledgements}/unrelayed_packets";
"{packet_commitment_sequences}/unreceived_packets";
}

// UnrelayedAcks returns all the unrelayed IBC acknowledgements associated with a
// channel and sequences.
rpc UnrelayedAcks(QueryUnrelayedAcksRequest) returns (QueryUnrelayedAcksResponse) {
option (google.api.http).get = "/ibc/channel/v1beta1/channels/{channel_id}/ports/{port_id}/packet_commitments/"
"{packet_commitment_sequences}/unrelayed_acks";
}


// NextSequenceReceive returns the next receive sequence for a given channel.
rpc NextSequenceReceive(QueryNextSequenceReceiveRequest) returns (QueryNextSequenceReceiveResponse) {
option (google.api.http).get = "/ibc/channel/v1beta1/channels/{channel_id}/ports/{port_id}/next_sequence";
Expand Down Expand Up @@ -250,24 +258,41 @@ message QueryPacketAcknowledgementResponse {
ibc.client.Height proof_height = 4 [(gogoproto.nullable) = false];
}

// QueryUnrelayedPacketsRequest is the request type for the
// Query/UnrelayedPackets RPC method
message QueryUnrelayedPacketsRequest {
// QueryUnreceivedPacketsRequest is the request type for the
// Query/UnreceivedPackets RPC method
message QueryUnreceivedPacketsRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
// list of packet sequences
repeated uint64 packet_commitment_sequences = 3;
// flag indicating if the return value is packet commitments or
// acknowledgements
bool acknowledgements = 4;
}

// QueryUnrelayedPacketsResponse is the request type for the
// Query/UnrelayedPacketCommitments RPC method
message QueryUnrelayedPacketsResponse {
// list of unrelayed packet sequences
// QueryUnreceivedPacketsResponse is the response type for the
// Query/UnreceivedPacketCommitments RPC method
message QueryUnreceivedPacketsResponse {
// list of unreceived packet sequences
repeated uint64 sequences = 1;
// query block height
ibc.client.Height height = 2 [(gogoproto.nullable) = false];
}

// QueryUnrelayedAcksRequest is the request type for the
// Query/UnrelayedAcks RPC method
message QueryUnrelayedAcksRequest {
// port unique identifier
string port_id = 1;
// channel unique identifier
string channel_id = 2;
// list of commitment sequences
repeated uint64 packet_commitment_sequences = 3;
}

// QueryUnrelayedAcksResponse is the response type for the
// Query/UnrelayedAcks RPC method
message QueryUnrelayedAcksResponse {
// list of unreceived acknowledgement sequences
jackzampolin marked this conversation as resolved.
Show resolved Hide resolved
repeated uint64 sequences = 1;
// query block height
ibc.client.Height height = 2 [(gogoproto.nullable) = false];
Expand Down
3 changes: 2 additions & 1 deletion x/ibc/04-channel/client/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ func GetQueryCmd() *cobra.Command {
GetCmdQueryChannelClientState(),
GetCmdQueryPacketCommitment(),
GetCmdQueryPacketCommitments(),
GetCmdQueryUnrelayedPackets(),
GetCmdQueryUnreceivedPackets(),
GetCmdQueryUnrelayedAcks(),
GetCmdQueryNextSequenceReceive(),
// TODO: next sequence Send ?
)
Expand Down
81 changes: 61 additions & 20 deletions x/ibc/04-channel/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import (
)

const (
flagSequences = "sequences"
flagAcknowledgements = "acknowledgements"
flagSequences = "sequences"
)

// GetCmdQueryChannels defines the command to query all the channels ends
Expand Down Expand Up @@ -253,20 +252,18 @@ func GetCmdQueryPacketCommitment() *cobra.Command {
return cmd
}

// GetCmdQueryUnrelayedPackets defines the command to query all the unrelayed
// packets for either packet commitments or acknowledgements.
func GetCmdQueryUnrelayedPackets() *cobra.Command {
// GetCmdQueryUnreceivedPackets defines the command to query all the unreceived
// packets on the receiving chain
func GetCmdQueryUnreceivedPackets() *cobra.Command {
cmd := &cobra.Command{
Use: "unrelayed-packets [port-id] [channel-id]",
Short: "Query all the unrelayed packets associated with a channel",
Long: `Determine if a packet, given a list of packet commitment sequences, is unrelayed.

If the '-acknowledgements' flag is false (default) then the return value represents:
- Unrelayed packet commitments: no acknowledgement exists for the given packet commitment sequence.

Otherwise, the return value represents:
- Unrelayed packet acknowledgements: an acknowledgement exists for the given packet commitment sequence.`,
Example: fmt.Sprintf("%s query %s %s unrelayed-packets [port-id] [channel-id] --sequences=1,2,3 --acknowledgements=false", version.AppName, host.ModuleName, types.SubModuleName),
Use: "unreceived-packets [port-id] [channel-id]",
Short: "Query all the unreceived packets associated with a channel",
Long: `Determine if a packet, given a list of packet commitment sequences, is unreceived.

The return value represents:
- Unrelayed packet commitments: no acknowledgement exists on receiving chain for the given packet commitment sequence on sending chain.
jackzampolin marked this conversation as resolved.
Show resolved Hide resolved
`,
Example: fmt.Sprintf("%s query %s %s unreceived-packets [port-id] [channel-id] --sequences=1,2,3", version.AppName, host.ModuleName, types.SubModuleName),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
Expand All @@ -281,7 +278,53 @@ Otherwise, the return value represents:
return err
}

acknowledgements, err := cmd.Flags().GetBool(flagAcknowledgements)
seqs := make([]uint64, len(seqSlice))
for i := range seqSlice {
seqs[i] = uint64(seqSlice[i])
}

req := &types.QueryUnreceivedPacketsRequest{
PortId: args[0],
ChannelId: args[1],
PacketCommitmentSequences: seqs,
}

res, err := queryClient.UnreceivedPackets(context.Background(), req)
if err != nil {
return err
}

return clientCtx.PrintOutput(res)
},
}

cmd.Flags().Int64Slice(flagSequences, []int64{}, "comma separated list of packet sequence numbers")
flags.AddQueryFlagsToCmd(cmd)

return cmd
}

// GetCmdQueryUnrelayedAcks defines the command to query all the unrelayed acks on the original sending chain
func GetCmdQueryUnrelayedAcks() *cobra.Command {
cmd := &cobra.Command{
Use: "unrelayed-acks [port-id] [channel-id]",
Short: "Query all the unrelayed acks associated with a channel",
Long: `Given a list of packet commitment sequences from counterparty, determine if an ack on executing chain has not been relayed to counterparty.

The return value represents:
- Unrelayed packet acknowledgement: packet commitment exists on original sending chain and ack exists on receiving (executing) chain.
`,
Example: fmt.Sprintf("%s query %s %s unrelayed-acks [port-id] [channel-id] --sequences=1,2,3", version.AppName, host.ModuleName, types.SubModuleName),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.ReadQueryCommandFlags(clientCtx, cmd.Flags())
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)

seqSlice, err := cmd.Flags().GetInt64Slice(flagSequences)
if err != nil {
return err
}
Expand All @@ -291,14 +334,13 @@ Otherwise, the return value represents:
seqs[i] = uint64(seqSlice[i])
}

req := &types.QueryUnrelayedPacketsRequest{
req := &types.QueryUnrelayedAcksRequest{
PortId: args[0],
ChannelId: args[1],
PacketCommitmentSequences: seqs,
Acknowledgements: acknowledgements,
}

res, err := queryClient.UnrelayedPackets(context.Background(), req)
res, err := queryClient.UnrelayedAcks(context.Background(), req)
if err != nil {
return err
}
Expand All @@ -308,7 +350,6 @@ Otherwise, the return value represents:
}

cmd.Flags().Int64Slice(flagSequences, []int64{}, "comma separated list of packet sequence numbers")
cmd.Flags().Bool(flagAcknowledgements, false, "boolean indicating if unrelayed acknowledgements (true) or unrelayed packet commitments (false) are returned.")
flags.AddQueryFlagsToCmd(cmd)

return cmd
Expand Down
76 changes: 67 additions & 9 deletions x/ibc/04-channel/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,17 +309,75 @@ func (q Keeper) PacketAcknowledgement(c context.Context, req *types.QueryPacketA
return types.NewQueryPacketAcknowledgementResponse(req.PortId, req.ChannelId, req.Sequence, acknowledgementBz, nil, selfHeight), nil
}

// UnrelayedPackets implements the Query/UnrelayedPackets gRPC method. Given
// UnreceivedPackets implements the Query/UnreceivedPackets gRPC method. Given
// a list of counterparty packet commitments, the querier checks if the packet
// sequence has an acknowledgement stored. If req.Acknowledgements is true then
// all unrelayed acknowledgements are returned (ack exists), otherwise all
// unrelayed packet commitments are returned (ack does not exist).
// has already been received by checking if an acknowledgement exists on this
// chain for the packet sequence. All packets that haven't been received yet
// are returned in the response
// Usage: To use this method correctly, first query all packet commitments on
// the sending chain using the Query/PacketCommitments gRPC method.
// Then input the returned sequences into the QueryUnreceivedPacketsRequest
// and send the request to this Query/UnreceivedPackets on the **receiving**
// chain. This gRPC method will then return the list of packet sequences that
// are yet to be received on the receiving chain.
//
// NOTE: The querier makes the assumption that the provided list of packet
// commitments is correct and will not function properly if the list
// is not up to date. Ideally the query height should equal the latest height
// on the counterparty's client which represents this chain.
func (q Keeper) UnrelayedPackets(c context.Context, req *types.QueryUnrelayedPacketsRequest) (*types.QueryUnrelayedPacketsResponse, error) {
// TODO: Replace GetPacketAcknowledgement with GetPacketReceipt once async
// acknowledgements issue is implemented.
// Issue #7254: https://github.com/cosmos/cosmos-sdk/issues/7254
func (q Keeper) UnreceivedPackets(c context.Context, req *types.QueryUnreceivedPacketsRequest) (*types.QueryUnreceivedPacketsResponse, 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 unreceivedSequences = []uint64{}

for i, seq := range req.PacketCommitmentSequences {
if seq == 0 {
return nil, status.Errorf(codes.InvalidArgument, "packet sequence %d cannot be 0", i)
}

// if acknowledgement exists on the receiving chain, then packet has already been received
if _, found := q.GetPacketAcknowledgement(ctx, req.PortId, req.ChannelId, seq); !found {
unreceivedSequences = append(unreceivedSequences, seq)
}

}

selfHeight := clienttypes.GetSelfHeight(ctx)
return &types.QueryUnreceivedPacketsResponse{
Sequences: unreceivedSequences,
Height: selfHeight,
}, nil
}

// UnrelayedAcks implements the Query/UnrelayedAcks gRPC method. Given
// a list of counterparty packet acknowledgements, the querier checks if the packet
// has already been received by checking if the packet commitment still exists on this
// chain (original sender) for the packet sequence.
// All acknowledgmeents that haven't been received yet are returned in the response.
// Usage: To use this method correctly, first query all packet commitments on
// the sending chain using the Query/PacketCommitments gRPC method.
// Then input the returned sequences into the QueryUnrelayedPacketsRequest
// and send the request to this Query/UnrelayedPackets on the **receiving**
// chain. This gRPC method will then return the list of packet sequences whose
// acknowledgements are already written on the receiving chain but haven't yet
// been relayed back to the sending chain.
//
// NOTE: The querier makes the assumption that the provided list of packet
// acknowledgements is correct and will not function properly if the list
// is not up to date. Ideally the query height should equal the latest height
// on the counterparty's client which represents this chain.
func (q Keeper) UnrelayedAcks(c context.Context, req *types.QueryUnrelayedAcksRequest) (*types.QueryUnrelayedAcksResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
Expand All @@ -337,16 +395,16 @@ func (q Keeper) UnrelayedPackets(c context.Context, req *types.QueryUnrelayedPac
return nil, status.Errorf(codes.InvalidArgument, "packet sequence %d cannot be 0", i)
}

// if req.Acknowledgements is true append sequences with an existing acknowledgement
// otherwise append sequences without an existing acknowledgement.
if _, found := q.GetPacketAcknowledgement(ctx, req.PortId, req.ChannelId, seq); found == req.Acknowledgements {
// if packet commitment still exists on the original sending chain, then packet ack has not been received
// since processing the ack will delete the packet commitment
if _, found := q.GetPacketAcknowledgement(ctx, req.PortId, req.ChannelId, seq); found {
unrelayedSequences = append(unrelayedSequences, seq)
}

}

selfHeight := clienttypes.GetSelfHeight(ctx)
return &types.QueryUnrelayedPacketsResponse{
return &types.QueryUnrelayedAcksResponse{
Sequences: unrelayedSequences,
Height: selfHeight,
}, nil
Expand Down
Loading