Skip to content

Commit

Permalink
chore: add channel consensus state rpc (#7619)
Browse files Browse the repository at this point in the history
  • Loading branch information
DimitrisJim authored Dec 16, 2024
1 parent a64877f commit a5b69ec
Show file tree
Hide file tree
Showing 7 changed files with 1,088 additions and 145 deletions.
32 changes: 32 additions & 0 deletions modules/core/04-channel/v2/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,38 @@ func (q *queryServer) ChannelClientState(ctx context.Context, req *types.QueryCh
return res, nil
}

// ChannelConsensusState implements the Query/ChannelConsensusState gRPC method
func (q *queryServer) ChannelConsensusState(ctx context.Context, req *types.QueryChannelConsensusStateRequest) (*types.QueryChannelConsensusStateResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}

if err := host.ChannelIdentifierValidator(req.ChannelId); err != nil {
return nil, status.Error(codes.InvalidArgument, err.Error())
}

channel, found := q.GetChannel(ctx, req.ChannelId)
if !found {
return nil, status.Error(codes.NotFound, errorsmod.Wrapf(types.ErrChannelNotFound, "channel-id: %s", req.ChannelId).Error())
}

consHeight := clienttypes.NewHeight(req.RevisionNumber, req.RevisionHeight)
consensusState, found := q.ClientKeeper.GetClientConsensusState(ctx, channel.ClientId, consHeight)
if !found {
return nil, status.Error(
codes.NotFound,
errorsmod.Wrapf(clienttypes.ErrConsensusStateNotFound, "client-id: %s", channel.ClientId).Error(),
)
}

anyConsensusState, err := clienttypes.PackConsensusState(consensusState)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}

return types.NewQueryChannelConsensusStateResponse(channel.ClientId, anyConsensusState, nil, clienttypes.GetSelfHeight(ctx)), nil
}

// NextSequenceSend implements the Query/NextSequenceSend gRPC method
func (q *queryServer) NextSequenceSend(ctx context.Context, req *types.QueryNextSequenceSendRequest) (*types.QueryNextSequenceSendResponse, error) {
if req == nil {
Expand Down
108 changes: 108 additions & 0 deletions modules/core/04-channel/v2/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/keeper"
"github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types"
commitmenttypes "github.com/cosmos/ibc-go/v9/modules/core/23-commitment/types"
"github.com/cosmos/ibc-go/v9/modules/core/exported"
ibctesting "github.com/cosmos/ibc-go/v9/testing"
)

Expand Down Expand Up @@ -190,6 +191,113 @@ func (suite *KeeperTestSuite) TestQueryChannelClientState() {
}
}

func (suite *KeeperTestSuite) TestQueryChannelConsensusState() {
var (
req *types.QueryChannelConsensusStateRequest
expConsensusState exported.ConsensusState
expClientID string
)

testCases := []struct {
msg string
malleate func()
expError error
}{
{
"success",
func() {
path := ibctesting.NewPath(suite.chainA, suite.chainB)
path.SetupV2()

expConsensusState, _ = suite.chainA.GetConsensusState(path.EndpointA.ClientID, path.EndpointA.GetClientLatestHeight())
suite.Require().NotNil(expConsensusState)
expClientID = path.EndpointA.ClientID

req = &types.QueryChannelConsensusStateRequest{
ChannelId: path.EndpointA.ChannelID,
RevisionNumber: path.EndpointA.GetClientLatestHeight().GetRevisionNumber(),
RevisionHeight: path.EndpointA.GetClientLatestHeight().GetRevisionHeight(),
}
},
nil,
},
{
"empty request",
func() {
req = nil
},
status.Error(codes.InvalidArgument, "empty request"),
},
{
"invalid channel ID",
func() {
req = &types.QueryChannelConsensusStateRequest{
ChannelId: "",
RevisionNumber: 0,
RevisionHeight: 1,
}
},
status.Error(codes.InvalidArgument, "identifier cannot be blank: invalid identifier"),
},
{
"channel not found",
func() {
req = &types.QueryChannelConsensusStateRequest{
ChannelId: "test-channel-id",
RevisionNumber: 0,
RevisionHeight: 1,
}
},
status.Error(codes.NotFound, fmt.Sprintf("channel-id: %s: channel not found", "test-channel-id")),
},
{
"consensus state for channel's connection not found",
func() {
path := ibctesting.NewPath(suite.chainA, suite.chainB)
path.SetupV2()

req = &types.QueryChannelConsensusStateRequest{
ChannelId: path.EndpointA.ChannelID,
RevisionNumber: 0,
RevisionHeight: uint64(suite.chainA.GetContext().BlockHeight()), // use current height
}
},
status.Error(codes.NotFound, fmt.Sprintf("client-id: %s: consensus state not found", "07-tendermint-0")),
},
}

for _, tc := range testCases {
tc := tc

suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset

tc.malleate()
ctx := suite.chainA.GetContext()

queryServer := keeper.NewQueryServer(suite.chainA.App.GetIBCKeeper().ChannelKeeperV2)
res, err := queryServer.ChannelConsensusState(ctx, req)

expPass := tc.expError == nil
if 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)

// ensure UnpackInterfaces is defined
cachedValue := res.ConsensusState.GetCachedValue()
suite.Require().NotNil(cachedValue)
} else {
suite.Require().ErrorIs(err, tc.expError)
suite.Require().Nil(res)
}
})
}
}

func (suite *KeeperTestSuite) TestQueryPacketCommitment() {
var (
expCommitment []byte
Expand Down
2 changes: 2 additions & 0 deletions modules/core/04-channel/v2/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ type ClientKeeper interface {
GetClientTimestampAtHeight(ctx context.Context, clientID string, height exported.Height) (uint64, error)
// GetClientState gets a particular client from the store
GetClientState(ctx context.Context, clientID string) (exported.ClientState, bool)
// GetClientConsensusState gets the stored consensus state from a client at a given height.
GetClientConsensusState(ctx context.Context, clientID string, height exported.Height) (exported.ConsensusState, bool)
}
16 changes: 15 additions & 1 deletion modules/core/04-channel/v2/types/query.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package types

import clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types"
import (
codectypes "github.com/cosmos/cosmos-sdk/codec/types"

clienttypes "github.com/cosmos/ibc-go/v9/modules/core/02-client/types"
)

// NewQueryChannelRequest creates and returns a new channel query request.
func NewQueryChannelRequest(channelID string) *QueryChannelRequest {
Expand Down Expand Up @@ -32,6 +36,16 @@ func NewQueryChannelClientStateResponse(identifiedClientState clienttypes.Identi
}
}

// NewQueryChannelConsensusStateResponse creates and returns a new ChannelConsensusState query response.
func NewQueryChannelConsensusStateResponse(clientID string, anyConsensusState *codectypes.Any, proof []byte, height clienttypes.Height) *QueryChannelConsensusStateResponse {
return &QueryChannelConsensusStateResponse{
ConsensusState: anyConsensusState,
ClientId: clientID,
Proof: proof,
ProofHeight: height,
}
}

// NewQueryNextSequenceSendRequest creates a new next sequence send query.
func NewQueryNextSequenceSendRequest(channelID string) *QueryNextSequenceSendRequest {
return &QueryNextSequenceSendRequest{
Expand Down
Loading

0 comments on commit a5b69ec

Please sign in to comment.