Skip to content

Commit

Permalink
Fix query unrelayed packets logic (cosmos#6733)
Browse files Browse the repository at this point in the history
* add some query functions to channel keeper

* update grpc queries and cli cmd and tests

* rerun proto gen after merging master

* fix build broken from merge conflicts

* add test and update proto

* Update x/ibc/04-channel/client/cli/query.go

Co-authored-by: Federico Kunze <[email protected]>
  • Loading branch information
colin-axner and fedekunze authored Jul 20, 2020
1 parent 5c0e3b4 commit 1d63448
Show file tree
Hide file tree
Showing 9 changed files with 1,091 additions and 290 deletions.
44 changes: 34 additions & 10 deletions proto/ibc/channel/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ service Query {
// PacketCommitments returns the all the packet commitments hashes associated with a channel.
rpc PacketCommitments(QueryPacketCommitmentsRequest) returns (QueryPacketCommitmentsResponse) {}

// PacketAcknowledgement queries a stored packet acknowledgement hash.
rpc PacketAcknowledgement(QueryPacketAcknowledgementRequest) returns (QueryPacketAcknowledgementResponse) {}

// UnrelayedPackets returns all the unrelayed IBC packets associated with a channel and sequences.
rpc UnrelayedPackets(QueryUnrelayedPacketsRequest) returns (QueryUnrelayedPacketsResponse) {}

Expand Down Expand Up @@ -133,26 +136,47 @@ message QueryPacketCommitmentsResponse {
int64 height = 3;
}

// QueryUnrelayedPacketsRequest is the request type for the Query/QueryConnectionChannels RPC method
// QueryPacketAcknowledgementRequest is the request type for the Query/PacketAcknowledgement RPC method
message QueryPacketAcknowledgementRequest {
// port unique identifier
string port_id = 1 [(gogoproto.customname) = "PortID"];
// channel unique identifier
string channel_id = 2 [(gogoproto.customname) = "ChannelID"];
// packet sequence
uint64 sequence = 3;
}

// QueryPacketAcknowledgementResponse defines the client query response for a packet which also
// includes a proof, its path and the height form which the proof was retrieved
message QueryPacketAcknowledgementResponse {
// packet associated with the request fields
bytes acknowledgement = 1;
// merkle proof of existence
bytes proof = 2;
// merkle proof path
string proof_path = 3;
// height at which the proof was retrieved
uint64 proof_height = 4;
}

// QueryUnrelayedPacketsRequest is the request type for the Query/UnrelayedPackets RPC method
message QueryUnrelayedPacketsRequest {
// port unique identifier
string port_id = 1 [(gogoproto.customname) = "PortID"];
// channel unique identifier
string channel_id = 2 [(gogoproto.customname) = "ChannelID"];
// list of packet sequences
repeated uint64 sequences = 3;
// pagination request
cosmos.query.PageRequest req = 4;
repeated uint64 packet_commitment_sequences = 3 [(gogoproto.customname) = "PacketCommitmentSequences"];
// flag indicating if the return value is packet commitments or acknowledgements
bool acknowledgements = 4;
}

// QueryUnrelayedPacketsResponse is the request type for the Query/QueryConnectionChannels RPC method
// QueryUnrelayedPacketsResponse is the request type for the Query/UnrelayedPacketCommitments RPC method
message QueryUnrelayedPacketsResponse {
// list of unrelayed packets sequences
repeated uint64 packets = 1;
// pagination response
cosmos.query.PageResponse res = 2;
// list of unrelayed packet sequences
repeated uint64 sequences = 1;
// query block height
int64 height = 3;
int64 height = 2;
}

// QueryNextSequenceReceiveRequest is the request type for the Query/QueryNextSequenceReceiveRequest RPC method
Expand Down
4 changes: 1 addition & 3 deletions x/ibc/02-client/types/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ import (

// query routes supported by the IBC client Querier
const (
QueryAllClients = "client_states"
QueryClientState = "client_state"
QueryConsensusState = "consensus_state"
QueryAllClients = "client_states"
)

// QueryAllClientsParams defines the parameters necessary for querying for all
Expand Down
7 changes: 0 additions & 7 deletions x/ibc/03-connection/types/querier.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,6 @@ import (
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)

// query routes supported by the IBC connection Querier
const (
QueryAllConnections = "connections"
QueryClientConnections = "client_connections"
QueryAllClientConnections = "all_client_connections"
)

// NewQueryConnectionResponse creates a new QueryConnectionResponse instance
func NewQueryConnectionResponse(
connection ConnectionEnd, proof []byte, height int64,
Expand Down
45 changes: 24 additions & 21 deletions x/ibc/04-channel/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import (
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)

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

// GetCmdQueryChannels defines the command to query all the channels ends
// that this chain mantains.
Expand Down Expand Up @@ -265,18 +268,21 @@ func GetCmdQueryPacketCommitment() *cobra.Command {
return cmd
}

// GetCmdQueryUnrelayedPackets defines the command to query all the unrelayed packets.
// GetCmdQueryUnrelayedPackets defines the command to query all the unrelayed
// packets for either packet commitments or acknowledgements.
func GetCmdQueryUnrelayedPackets() *cobra.Command {
cmd := &cobra.Command{
Use: "unrelayed-packets [port-id] [channel-id]",
Short: "Query all the unrelayed packets associated with a channel",
Long: `It indicates if a packet, given a list of packet commitment sequences, is unrelayed.
An unrelayed packet corresponds to:
Long: `Determine if a packet, given a list of packet commitment sequences, is unrelayed.
- Unrelayed packet commitments: when no acknowledgement exists for the given sequence.
- Unrelayed packet acknowledgements: when an acknowledgement exists and a packet commitment also exists.`,
Example: fmt.Sprintf("%s query %s %s unrelayed-packets [port-id] [channel-id] --sequences=1,2,3", version.AppName, host.ModuleName, types.SubModuleName),
Args: cobra.ExactArgs(2),
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),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx := client.GetClientContextFromCmd(cmd)
clientCtx, err := client.ReadQueryCommandFlags(clientCtx, cmd.Flags())
Expand All @@ -290,37 +296,34 @@ An unrelayed packet corresponds to:
return err
}

acknowledgements, err := cmd.Flags().GetBool(flagAcknowledgements)
if err != nil {
return err
}

seqs := make([]uint64, len(seqSlice))
for i := range seqSlice {
seqs[i] = uint64(seqSlice[i])
}

offset, _ := cmd.Flags().GetInt(flags.FlagPage)
limit, _ := cmd.Flags().GetInt(flags.FlagLimit)

req := &types.QueryUnrelayedPacketsRequest{
PortID: args[0],
ChannelID: args[1],
Sequences: seqs,
Req: &query.PageRequest{
Offset: uint64(offset),
Limit: uint64(limit),
},
PortID: args[0],
ChannelID: args[1],
PacketCommitmentSequences: seqs,
Acknowledgements: acknowledgements,
}

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

clientCtx = clientCtx.WithHeight(res.Height)
return clientCtx.PrintOutput(res)
},
}

cmd.Flags().Int64Slice(flagSequences, []int64{}, "comma separated list of packet sequence numbers")
cmd.Flags().Int(flags.FlagPage, 1, "pagination page of light clients to to query for")
cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of light clients to query for")
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
62 changes: 42 additions & 20 deletions x/ibc/04-channel/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,40 @@ func (q Keeper) PacketCommitments(c context.Context, req *types.QueryPacketCommi
}, nil
}

// UnrelayedPackets implements the Query/UnrelayedPackets gRPC method
// PacketAcknowledgement implements the Query/PacketAcknowledgement gRPC method
func (q Keeper) PacketAcknowledgement(c context.Context, req *types.QueryPacketAcknowledgementRequest) (*types.QueryPacketAcknowledgementResponse, 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)

acknowledgementBz, found := q.GetPacketAcknowledgement(ctx, req.PortID, req.ChannelID, req.Sequence)
if !found || len(acknowledgementBz) == 0 {
return nil, status.Error(codes.NotFound, "packet acknowledgement hash not found")
}

return types.NewQueryPacketAcknowledgementResponse(req.PortID, req.ChannelID, req.Sequence, acknowledgementBz, nil, ctx.BlockHeight()), nil
}

// UnrelayedPackets implements the Query/UnrelayedPackets 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).
//
// 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) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
Expand All @@ -201,34 +234,23 @@ func (q Keeper) UnrelayedPackets(c context.Context, req *types.QueryUnrelayedPac

ctx := sdk.UnwrapSDKContext(c)

var (
unrelayedPackets = []uint64{}
store sdk.KVStore
res *query.PageResponse
err error
)
var unrelayedSequences = []uint64{}

for i, seq := range req.Sequences {
for i, seq := range req.PacketCommitmentSequences {
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
// 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 {
unrelayedSequences = append(unrelayedSequences, seq)
}

unrelayedPackets = append(unrelayedPackets, seq)
}
return &types.QueryUnrelayedPacketsResponse{
Packets: unrelayedPackets,
Res: res,
Height: ctx.BlockHeight(),
Sequences: unrelayedSequences,
Height: ctx.BlockHeight(),
}, nil
}

Expand Down
Loading

0 comments on commit 1d63448

Please sign in to comment.