Add clientState and consensusState gRPC support to connection (#7017)

* add proto querys for connection

* add client state and consensus state grpc for connection

* update client utils
This commit is contained in:
colin axnér 2020-08-12 14:54:38 +02:00 committed by GitHub
parent d752a7b21f
commit 3a4e608930
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1736 additions and 109 deletions

View File

@ -3,31 +3,51 @@ package ibc.connection;
import "gogoproto/gogo.proto";
import "cosmos/base/query/v1beta1/pagination.proto";
import "ibc/client/client.proto";
import "ibc/connection/connection.proto";
import "google/protobuf/any.proto";
option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types";
// Query provides defines the gRPC querier service
service Query {
// Connection queries an IBC connection end.
rpc Connection(QueryConnectionRequest) returns (QueryConnectionResponse) {}
rpc Connection(QueryConnectionRequest) returns (QueryConnectionResponse) {
}
// Connections queries all the IBC connections of a chain.
rpc Connections(QueryConnectionsRequest) returns (QueryConnectionsResponse) {}
rpc Connections(QueryConnectionsRequest) returns (QueryConnectionsResponse) {
}
// ClientConnections queries the connection paths associated with a client state.
rpc ClientConnections(QueryClientConnectionsRequest) returns (QueryClientConnectionsResponse) {}
// ClientConnections queries the connection paths associated with a client
// state.
rpc ClientConnections(QueryClientConnectionsRequest)
returns (QueryClientConnectionsResponse) {
}
// ConnectionClientState queries the client state associated with the
// connection
rpc ConnectionClientState(QueryConnectionClientStateRequest)
returns (QueryConnectionClientStateResponse) {
}
// ConnectionConsensusState queries the consensus state associated with the
// connection
rpc ConnectionConsensusState(QueryConnectionConsensusStateRequest)
returns (QueryConnectionConsensusStateResponse) {
}
}
// QueryConnectionRequest is the request type for the Query/Connection RPC method
// QueryConnectionRequest is the request type for the Query/Connection RPC
// method
message QueryConnectionRequest {
// connection unique identifier
string connection_id = 1 [(gogoproto.customname) = "ConnectionID"];
}
// QueryConnectionResponse is the response type for the Query/Connection RPC method.
// Besides the connection end, it includes a proof and the height from which the
// proof was retrieved.
// QueryConnectionResponse is the response type for the Query/Connection RPC
// method. Besides the connection end, it includes a proof and the height from
// which the proof was retrieved.
message QueryConnectionResponse {
// connection associated with the request identifier
ibc.connection.ConnectionEnd connection = 1;
@ -39,12 +59,14 @@ message QueryConnectionResponse {
uint64 proof_height = 4;
}
// QueryConnectionsRequest is the request type for the Query/Connections RPC method
// QueryConnectionsRequest is the request type for the Query/Connections RPC
// method
message QueryConnectionsRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
// QueryConnectionsResponse is the response type for the Query/Connections RPC method.
// QueryConnectionsResponse is the response type for the Query/Connections RPC
// method.
message QueryConnectionsResponse {
// list of stored connections of the chain.
repeated ibc.connection.IdentifiedConnection connections = 1;
@ -54,15 +76,15 @@ message QueryConnectionsResponse {
int64 height = 3;
}
// QueryClientConnectionsRequest is the request type for the Query/ClientConnections
// RPC method
// QueryClientConnectionsRequest is the request type for the
// Query/ClientConnections RPC method
message QueryClientConnectionsRequest {
// client identifier associated with a connection
string client_id = 1 [(gogoproto.customname) = "ClientID"];
}
// QueryClientConnectionsResponse is the response type for the Query/ClientConnections
// RPC method
// QueryClientConnectionsResponse is the response type for the
// Query/ClientConnections RPC method
message QueryClientConnectionsResponse {
// slice of all the connection paths associated with a client.
repeated string connection_paths = 1;
@ -73,3 +95,52 @@ message QueryClientConnectionsResponse {
// height at which the proof was generated
uint64 proof_height = 4;
}
// QueryConnectionClientStateRequest is the request type for the
// Query/ConnectionClientState RPC method
message QueryConnectionClientStateRequest {
// connection identifier
string id = 1 [
(gogoproto.customname) = "ConnectionID",
(gogoproto.moretags) = "yaml:\"connection_id\""
];
}
// QueryConnectionClientStateResponse is the response type for the
// Query/ConnectionClientState RPC method
message QueryConnectionClientStateResponse {
// client state associated with the channel
ibc.client.IdentifiedClientState identified_client_state = 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;
}
// QueryConnectionConsensusStateRequest is the request type for the
// Query/ConnectionConsensusState RPC method
message QueryConnectionConsensusStateRequest {
// connection identifier
string connection_id = 1 [
(gogoproto.customname) = "ConnectionID",
(gogoproto.moretags) = "yaml:\"connection_id\""
];
uint64 height = 2;
}
// QueryConnectionConsensusStateResponse is the response type for the
// Query/ConnectionConsensusState RPC method
message QueryConnectionConsensusStateResponse {
// consensus state associated with the channel
google.protobuf.Any consensus_state = 1;
// client ID associated with the consensus state
string client_id = 2 [(gogoproto.customname) = "ClientID"];
// merkle proof of existence
bytes proof = 3;
// merkle proof path
string proof_path = 4;
// height at which the proof was retrieved
uint64 proof_height = 5;
}

View File

@ -67,7 +67,7 @@ to the counterparty channel. Any timeout set to 0 is disabled.`),
// if the timeouts are not absolute, retrieve latest block height and block timestamp
// for the consensus state connected to the destination port/channel
if !absoluteTimeouts {
consensusState, _, err := channelutils.QueryCounterpartyConsensusState(clientCtx, srcPort, srcChannel)
consensusState, _, err := channelutils.QueryCounterpartyConsensusState(clientCtx, srcPort, srcChannel, uint64(clientCtx.Height))
if err != nil {
return err
}

View File

@ -11,6 +11,8 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/codec"
clientutils "github.com/cosmos/cosmos-sdk/x/ibc/02-client/client/utils"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
@ -102,6 +104,78 @@ func queryClientConnectionsABCI(clientCtx client.Context, clientID string) (*typ
return types.NewQueryClientConnectionsResponse(clientID, paths, proofBz, res.Height), nil
}
// QueryConnectionClientState returns the ClientState of a connection end. If
// prove is true, it performs an ABCI store query in order to retrieve the
// merkle proof. Otherwise, it uses the gRPC query client.
func QueryConnectionClientState(
clientCtx client.Context, connectionID string, prove bool,
) (*types.QueryConnectionClientStateResponse, error) {
queryClient := types.NewQueryClient(clientCtx)
req := &types.QueryConnectionClientStateRequest{
ConnectionID: connectionID,
}
res, err := queryClient.ConnectionClientState(context.Background(), req)
if err != nil {
return nil, err
}
if prove {
clientState, proof, proofHeight, err := clientutils.QueryClientStateABCI(clientCtx, res.IdentifiedClientState.ID)
if err != nil {
return nil, err
}
// use client state returned from ABCI query in case query height differs
identifiedClientState := clienttypes.NewIdentifiedClientState(res.IdentifiedClientState.ID, clientState)
res = types.NewQueryConnectionClientStateResponse(identifiedClientState, proof, int64(proofHeight))
}
return res, nil
}
// QueryConnectionConsensusState returns the ConsensusState of a connection end. If
// prove is true, it performs an ABCI store query in order to retrieve the
// merkle proof. Otherwise, it uses the gRPC query client.
func QueryConnectionConsensusState(
clientCtx client.Context, connectionID string, height uint64, prove bool,
) (*types.QueryConnectionConsensusStateResponse, error) {
queryClient := types.NewQueryClient(clientCtx)
req := &types.QueryConnectionConsensusStateRequest{
ConnectionID: connectionID,
Height: height,
}
res, err := queryClient.ConnectionConsensusState(context.Background(), req)
if err != nil {
return nil, err
}
consensusState, err := clienttypes.UnpackConsensusState(res.ConsensusState)
if err != nil {
return nil, err
}
if prove {
consensusState, proof, proofHeight, err := clientutils.QueryConsensusStateABCI(clientCtx, res.ClientID, consensusState.GetHeight())
if err != nil {
return nil, err
}
// use consensus state returned from ABCI query in case query height differs
anyConsensusState, err := clienttypes.PackConsensusState(consensusState)
if err != nil {
return nil, err
}
res = types.NewQueryConnectionConsensusStateResponse(res.ClientID, anyConsensusState, consensusState.GetHeight(), proof, int64(proofHeight))
}
return res, nil
}
// ParsePrefix unmarshals an cmd input argument from a JSON string to a commitment
// Prefix. If the input is not a JSON, it looks for a path to the JSON file.
func ParsePrefix(cdc *codec.LegacyAmino, arg string) (commitmenttypes.MerklePrefix, error) {

View File

@ -10,6 +10,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/query"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)
@ -103,3 +104,73 @@ func (q Keeper) ClientConnections(c context.Context, req *types.QueryClientConne
ProofHeight: uint64(ctx.BlockHeight()),
}, nil
}
// ConnectionClientState implements the Query/ConnectionClientState gRPC method
func (q Keeper) ConnectionClientState(c context.Context, req *types.QueryConnectionClientStateRequest) (*types.QueryConnectionClientStateResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if err := host.ConnectionIdentifierValidator(req.ConnectionID); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
ctx := sdk.UnwrapSDKContext(c)
connection, found := q.GetConnection(ctx, req.ConnectionID)
if !found {
return nil, status.Error(
codes.NotFound,
sdkerrors.Wrapf(types.ErrConnectionNotFound, "connection-id: %s", req.ConnectionID).Error(),
)
}
clientState, found := q.clientKeeper.GetClientState(ctx, connection.ClientID)
if !found {
return nil, status.Error(
codes.NotFound,
sdkerrors.Wrapf(clienttypes.ErrClientNotFound, "client-id: %s", connection.ClientID).Error(),
)
}
identifiedClientState := clienttypes.NewIdentifiedClientState(connection.ClientID, clientState)
return types.NewQueryConnectionClientStateResponse(identifiedClientState, nil, ctx.BlockHeight()), nil
}
// ConnectionConsensusState implements the Query/ConnectionConsensusState gRPC method
func (q Keeper) ConnectionConsensusState(c context.Context, req *types.QueryConnectionConsensusStateRequest) (*types.QueryConnectionConsensusStateResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if err := host.ConnectionIdentifierValidator(req.ConnectionID); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}
ctx := sdk.UnwrapSDKContext(c)
connection, found := q.GetConnection(ctx, req.ConnectionID)
if !found {
return nil, status.Error(
codes.NotFound,
sdkerrors.Wrapf(types.ErrConnectionNotFound, "connection-id: %s", req.ConnectionID).Error(),
)
}
consensusState, found := q.clientKeeper.GetClientConsensusState(ctx, connection.ClientID, req.Height)
if !found {
return nil, status.Error(
codes.NotFound,
sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "client-id: %s", connection.ClientID).Error(),
)
}
anyConsensusState, err := clienttypes.PackConsensusState(consensusState)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return types.NewQueryConnectionConsensusStateResponse(connection.ClientID, anyConsensusState, consensusState.GetHeight(), nil, ctx.BlockHeight()), nil
}

View File

@ -6,6 +6,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/query"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
@ -227,3 +228,180 @@ func (suite *KeeperTestSuite) TestQueryClientConnections() {
})
}
}
func (suite *KeeperTestSuite) TestQueryConnectionClientState() {
var (
req *types.QueryConnectionClientStateRequest
expIdentifiedClientState clienttypes.IdentifiedClientState
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty request",
func() {
req = nil
},
false,
},
{
"invalid connection ID",
func() {
req = &types.QueryConnectionClientStateRequest{
ConnectionID: "",
}
},
false,
},
{
"connection not found",
func() {
req = &types.QueryConnectionClientStateRequest{
ConnectionID: "test-connection-id",
}
},
false,
},
{
"client state not found",
func() {
_, _, connA, _, _, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
// set connection to empty so clientID is empty
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), connA.ID, types.ConnectionEnd{})
req = &types.QueryConnectionClientStateRequest{
ConnectionID: connA.ID,
}
}, false,
},
{
"success",
func() {
clientA, _, connA, _ := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
expClientState := suite.chainA.GetClientState(clientA)
expIdentifiedClientState = clienttypes.NewIdentifiedClientState(clientA, expClientState)
req = &types.QueryConnectionClientStateRequest{
ConnectionID: connA.ID,
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.chainA.GetContext())
res, err := suite.chainA.QueryServer.ConnectionClientState(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().Equal(&expIdentifiedClientState, res.IdentifiedClientState)
} else {
suite.Require().Error(err)
}
})
}
}
func (suite *KeeperTestSuite) TestQueryConnectionConsensusState() {
var (
req *types.QueryConnectionConsensusStateRequest
expConsensusState clientexported.ConsensusState
expClientID string
)
testCases := []struct {
msg string
malleate func()
expPass bool
}{
{
"empty request",
func() {
req = nil
},
false,
},
{
"invalid connection ID",
func() {
req = &types.QueryConnectionConsensusStateRequest{
ConnectionID: "",
Height: 1,
}
},
false,
},
{
"connection not found",
func() {
req = &types.QueryConnectionConsensusStateRequest{
ConnectionID: "test-connection-id",
Height: 1,
}
},
false,
},
{
"consensus state not found",
func() {
_, _, connA, _, _, _ := suite.coordinator.Setup(suite.chainA, suite.chainB)
req = &types.QueryConnectionConsensusStateRequest{
ConnectionID: connA.ID,
Height: uint64(suite.chainA.GetContext().BlockHeight()), // use current height
}
}, false,
},
{
"success",
func() {
clientA, _, connA, _ := suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
clientState := suite.chainA.GetClientState(clientA)
expConsensusState, _ = suite.chainA.GetConsensusState(clientA, clientState.GetLatestHeight())
suite.Require().NotNil(expConsensusState)
expClientID = clientA
req = &types.QueryConnectionConsensusStateRequest{
ConnectionID: connA.ID,
Height: expConsensusState.GetHeight(),
}
},
true,
},
}
for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
ctx := sdk.WrapSDKContext(suite.chainA.GetContext())
res, err := suite.chainA.QueryServer.ConnectionConsensusState(ctx, req)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
consensusState, err := clienttypes.UnpackConsensusState(res.ConsensusState)
suite.Require().NoError(err)
suite.Require().Equal(expConsensusState, consensusState)
suite.Require().Equal(expClientID, res.ClientID)
} else {
suite.Require().Error(err)
}
})
}
}

View File

@ -1,41 +0,0 @@
package types
import (
"strings"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)
// NewQueryConnectionResponse creates a new QueryConnectionResponse instance
func NewQueryConnectionResponse(
connectionID string, connection ConnectionEnd, proof []byte, height int64,
) *QueryConnectionResponse {
path := commitmenttypes.NewMerklePath(strings.Split(host.ConnectionPath(connectionID), "/"))
return &QueryConnectionResponse{
Connection: &connection,
Proof: proof,
ProofPath: path.Pretty(),
ProofHeight: uint64(height),
}
}
// NewQueryClientConnectionsResponse creates a new ConnectionPaths instance
func NewQueryClientConnectionsResponse(
clientID string, connectionPaths []string, proof []byte, height int64,
) *QueryClientConnectionsResponse {
path := commitmenttypes.NewMerklePath(strings.Split(host.ClientConnectionsPath(clientID), "/"))
return &QueryClientConnectionsResponse{
ConnectionPaths: connectionPaths,
Proof: proof,
ProofPath: path.Pretty(),
ProofHeight: uint64(height),
}
}
// NewQueryClientConnectionsRequest creates a new QueryClientConnectionsRequest instance
func NewQueryClientConnectionsRequest(clientID string) *QueryClientConnectionsRequest {
return &QueryClientConnectionsRequest{
ClientID: clientID,
}
}

View File

@ -0,0 +1,66 @@
package types
import (
"strings"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)
// NewQueryConnectionResponse creates a new QueryConnectionResponse instance
func NewQueryConnectionResponse(
connectionID string, connection ConnectionEnd, proof []byte, height int64,
) *QueryConnectionResponse {
path := commitmenttypes.NewMerklePath(strings.Split(host.ConnectionPath(connectionID), "/"))
return &QueryConnectionResponse{
Connection: &connection,
Proof: proof,
ProofPath: path.Pretty(),
ProofHeight: uint64(height),
}
}
// NewQueryClientConnectionsResponse creates a new ConnectionPaths instance
func NewQueryClientConnectionsResponse(
clientID string, connectionPaths []string, proof []byte, height int64,
) *QueryClientConnectionsResponse {
path := commitmenttypes.NewMerklePath(strings.Split(host.ClientConnectionsPath(clientID), "/"))
return &QueryClientConnectionsResponse{
ConnectionPaths: connectionPaths,
Proof: proof,
ProofPath: path.Pretty(),
ProofHeight: uint64(height),
}
}
// NewQueryClientConnectionsRequest creates a new QueryClientConnectionsRequest instance
func NewQueryClientConnectionsRequest(clientID string) *QueryClientConnectionsRequest {
return &QueryClientConnectionsRequest{
ClientID: clientID,
}
}
// NewQueryConnectionClientStateResponse creates a newQueryConnectionClientStateResponse instance
func NewQueryConnectionClientStateResponse(identifiedClientState clienttypes.IdentifiedClientState, proof []byte, height int64) *QueryConnectionClientStateResponse {
path := commitmenttypes.NewMerklePath(strings.Split(host.FullClientPath(identifiedClientState.ID, host.ClientStatePath()), "/"))
return &QueryConnectionClientStateResponse{
IdentifiedClientState: &identifiedClientState,
Proof: proof,
ProofPath: path.Pretty(),
ProofHeight: uint64(height),
}
}
// NewQueryConnectionConsensusStateResponse creates a newQueryConnectionConsensusStateResponse instance
func NewQueryConnectionConsensusStateResponse(clientID string, anyConsensusState *codectypes.Any, consensusStateHeight uint64, proof []byte, height int64) *QueryConnectionConsensusStateResponse {
path := commitmenttypes.NewMerklePath(strings.Split(host.FullClientPath(clientID, host.ConsensusStatePath(consensusStateHeight)), "/"))
return &QueryConnectionConsensusStateResponse{
ConsensusState: anyConsensusState,
ClientID: clientID,
Proof: proof,
ProofPath: path.Pretty(),
ProofHeight: uint64(height),
}
}

File diff suppressed because it is too large Load Diff

View File

@ -139,13 +139,14 @@ func QueryChannelClientState(
// prove is true, it performs an ABCI store query in order to retrieve the
// merkle proof. Otherwise, it uses the gRPC query client.
func QueryChannelConsensusState(
clientCtx client.Context, portID, channelID string, prove bool,
clientCtx client.Context, portID, channelID string, height uint64, prove bool,
) (*types.QueryChannelConsensusStateResponse, error) {
queryClient := types.NewQueryClient(clientCtx)
req := &types.QueryChannelConsensusStateRequest{
PortID: portID,
ChannelID: channelID,
Height: height,
}
res, err := queryClient.ChannelConsensusState(context.Background(), req)
@ -179,7 +180,7 @@ func QueryChannelConsensusState(
// QueryCounterpartyConsensusState uses the channel Querier to return the
// counterparty ConsensusState given the source port ID and source channel ID.
func QueryCounterpartyConsensusState(
clientCtx client.Context, portID, channelID string,
clientCtx client.Context, portID, channelID string, height uint64,
) (clientexported.ConsensusState, uint64, error) {
channelRes, err := QueryChannel(clientCtx, portID, channelID, false)
if err != nil {
@ -187,7 +188,7 @@ func QueryCounterpartyConsensusState(
}
counterparty := channelRes.Channel.Counterparty
res, err := QueryChannelConsensusState(clientCtx, counterparty.PortID, counterparty.ChannelID, false)
res, err := QueryChannelConsensusState(clientCtx, counterparty.PortID, counterparty.ChannelID, height, false)
if err != nil {
return nil, 0, err
}

View File

@ -332,7 +332,8 @@ func (suite *KeeperTestSuite) TestQueryChannelClientState() {
},
false,
},
{"channel not found",
{
"channel not found",
func() {
req = &types.QueryChannelClientStateRequest{
PortID: "test-port-id",
@ -454,7 +455,8 @@ func (suite *KeeperTestSuite) TestQueryChannelConsensusState() {
},
false,
},
{"channel not found",
{
"channel not found",
func() {
req = &types.QueryChannelConsensusStateRequest{
PortID: "test-port-id",

View File

@ -22,6 +22,16 @@ func (q Keeper) ClientConnections(c context.Context, req *connectiontypes.QueryC
return q.ConnectionKeeper.ClientConnections(c, req)
}
// ConnectionClientState implements the IBC QueryServer interface
func (q Keeper) ConnectionClientState(c context.Context, req *connectiontypes.QueryConnectionClientStateRequest) (*connectiontypes.QueryConnectionClientStateResponse, error) {
return q.ConnectionKeeper.ConnectionClientState(c, req)
}
// ConnectionConsensusState implements the IBC QueryServer interface
func (q Keeper) ConnectionConsensusState(c context.Context, req *connectiontypes.QueryConnectionConsensusStateRequest) (*connectiontypes.QueryConnectionConsensusStateResponse, error) {
return q.ConnectionKeeper.ConnectionConsensusState(c, req)
}
// Channel implements the IBC QueryServer interface
func (q Keeper) Channel(c context.Context, req *channeltypes.QueryChannelRequest) (*channeltypes.QueryChannelResponse, error) {
return q.ChannelKeeper.Channel(c, req)