x/ibc: querying support for unordered channels (#6294)

* pause

* add querying for packet commitments and unrelayed acks

* add get all packet commitments test

* add query channels test

* add query connection channels test

* add test for query packet commitments

* fix key path and add unrelayed acks test

* fix part of lint

* add unrelayed packetsends func

* fix godoc

* add nolint directive

* fix lint

Co-authored-by: Federico Kunze <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
colin axner 2020-06-06 16:25:45 -07:00 committed by GitHub
parent 626f9b62c5
commit b9b578d6de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 798 additions and 86 deletions

View File

@ -2,8 +2,8 @@ package channel
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper
// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types
// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper
import (
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/keeper"
@ -11,62 +11,99 @@ import (
)
const (
SubModuleName = types.SubModuleName
StoreKey = types.StoreKey
RouterKey = types.RouterKey
QuerierRoute = types.QuerierRoute
QueryAllChannels = types.QueryAllChannels
QueryConnectionChannels = types.QueryConnectionChannels
QueryChannel = types.QueryChannel
UNINITIALIZED = types.UNINITIALIZED
INIT = types.INIT
TRYOPEN = types.TRYOPEN
OPEN = types.OPEN
CLOSED = types.CLOSED
NONE = types.NONE
UNORDERED = types.UNORDERED
ORDERED = types.ORDERED
AttributeKeyConnectionID = types.AttributeKeyConnectionID
AttributeKeyPortID = types.AttributeKeyPortID
AttributeKeyChannelID = types.AttributeKeyChannelID
AttributeCounterpartyPortID = types.AttributeCounterpartyPortID
AttributeCounterpartyChannelID = types.AttributeCounterpartyChannelID
EventTypeSendPacket = types.EventTypeSendPacket
EventTypeRecvPacket = types.EventTypeRecvPacket
EventTypeAcknowledgePacket = types.EventTypeAcknowledgePacket
EventTypeCleanupPacket = types.EventTypeCleanupPacket
EventTypeTimeoutPacket = types.EventTypeTimeoutPacket
AttributeKeyData = types.AttributeKeyData
AttributeKeyAck = types.AttributeKeyAck
AttributeKeyTimeoutHeight = types.AttributeKeyTimeoutHeight
AttributeKeyTimeoutTimestamp = types.AttributeKeyTimeoutTimestamp
AttributeKeySequence = types.AttributeKeySequence
AttributeKeySrcPort = types.AttributeKeySrcPort
AttributeKeySrcChannel = types.AttributeKeySrcChannel
AttributeKeyDstPort = types.AttributeKeyDstPort
AttributeKeyDstChannel = types.AttributeKeyDstChannel
SubModuleName = types.SubModuleName
StoreKey = types.StoreKey
RouterKey = types.RouterKey
QuerierRoute = types.QuerierRoute
QueryAllChannels = types.QueryAllChannels
QueryChannel = types.QueryChannel
QueryConnectionChannels = types.QueryConnectionChannels
QueryPacketCommitments = types.QueryPacketCommitments
QueryUnrelayedAcknowledgements = types.QueryUnrelayedAcknowledgements
QueryUnrelayedPacketSends = types.QueryUnrelayedPacketSends
UNINITIALIZED = types.UNINITIALIZED
INIT = types.INIT
TRYOPEN = types.TRYOPEN
OPEN = types.OPEN
CLOSED = types.CLOSED
NONE = types.NONE
UNORDERED = types.UNORDERED
ORDERED = types.ORDERED
)
var (
// functions aliases
NewKeeper = keeper.NewKeeper
QuerierChannels = keeper.QuerierChannels
QuerierConnectionChannels = keeper.QuerierConnectionChannels
NewChannel = types.NewChannel
NewCounterparty = types.NewCounterparty
NewIdentifiedChannel = types.NewIdentifiedChannel
RegisterCodec = types.RegisterCodec
RegisterInterfaces = types.RegisterInterfaces
ErrChannelExists = types.ErrChannelExists
ErrChannelNotFound = types.ErrChannelNotFound
ErrInvalidCounterparty = types.ErrInvalidCounterparty
ErrChannelCapabilityNotFound = types.ErrChannelCapabilityNotFound
ErrInvalidPacket = types.ErrInvalidPacket
ErrSequenceSendNotFound = types.ErrSequenceSendNotFound
ErrSequenceReceiveNotFound = types.ErrSequenceReceiveNotFound
ErrPacketTimeout = types.ErrPacketTimeout
ErrInvalidChannel = types.ErrInvalidChannel
ErrInvalidChannelState = types.ErrInvalidChannelState
ErrAcknowledgementTooLong = types.ErrAcknowledgementTooLong
NewMsgChannelOpenInit = types.NewMsgChannelOpenInit
NewMsgChannelOpenTry = types.NewMsgChannelOpenTry
NewMsgChannelOpenAck = types.NewMsgChannelOpenAck
NewMsgChannelOpenConfirm = types.NewMsgChannelOpenConfirm
NewMsgChannelCloseInit = types.NewMsgChannelCloseInit
NewMsgChannelCloseConfirm = types.NewMsgChannelCloseConfirm
NewMsgPacket = types.NewMsgPacket
NewMsgTimeout = types.NewMsgTimeout
NewMsgAcknowledgement = types.NewMsgAcknowledgement
NewPacket = types.NewPacket
NewPacketAckCommitment = types.NewPacketAckCommitment
NewPacketSequence = types.NewPacketSequence
NewChannelResponse = types.NewChannelResponse
DefaultGenesisState = types.DefaultGenesisState
NewGenesisState = types.NewGenesisState
NewChannel = types.NewChannel
NewCounterparty = types.NewCounterparty
NewIdentifiedChannel = types.NewIdentifiedChannel
RegisterCodec = types.RegisterCodec
RegisterInterfaces = types.RegisterInterfaces
NewPacketAckCommitment = types.NewPacketAckCommitment
NewPacketSequence = types.NewPacketSequence
NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState
NewMsgChannelOpenInit = types.NewMsgChannelOpenInit
NewMsgChannelOpenTry = types.NewMsgChannelOpenTry
NewMsgChannelOpenAck = types.NewMsgChannelOpenAck
NewMsgChannelOpenConfirm = types.NewMsgChannelOpenConfirm
NewMsgChannelCloseInit = types.NewMsgChannelCloseInit
NewMsgChannelCloseConfirm = types.NewMsgChannelCloseConfirm
NewMsgPacket = types.NewMsgPacket
NewMsgTimeout = types.NewMsgTimeout
NewMsgAcknowledgement = types.NewMsgAcknowledgement
CommitPacket = types.CommitPacket
CommitAcknowledgement = types.CommitAcknowledgement
NewPacket = types.NewPacket
NewChannelResponse = types.NewChannelResponse
NewQueryAllChannelsParams = types.NewQueryAllChannelsParams
NewQueryConnectionChannelsParams = types.NewQueryConnectionChannelsParams
NewQueryPacketCommitmentsParams = types.NewQueryPacketCommitmentsParams
NewQueryUnrelayedPacketsParams = types.NewQueryUnrelayedPacketsParams
NewPacketResponse = types.NewPacketResponse
NewRecvResponse = types.NewRecvResponse
NewKeeper = keeper.NewKeeper
QuerierChannels = keeper.QuerierChannels
QuerierConnectionChannels = keeper.QuerierConnectionChannels
QuerierPacketCommitments = keeper.QuerierPacketCommitments
QuerierUnrelayedAcknowledgements = keeper.QuerierUnrelayedAcknowledgements
QuerierUnrelayedPacketSends = keeper.QuerierUnrelayedPacketSends
// variable aliases
SubModuleCdc = types.SubModuleCdc
ErrChannelExists = types.ErrChannelExists
ErrChannelNotFound = types.ErrChannelNotFound
ErrInvalidChannel = types.ErrInvalidChannel
ErrInvalidChannelState = types.ErrInvalidChannelState
ErrInvalidChannelOrdering = types.ErrInvalidChannelOrdering
ErrInvalidCounterparty = types.ErrInvalidCounterparty
ErrInvalidChannelCapability = types.ErrInvalidChannelCapability
ErrChannelCapabilityNotFound = types.ErrChannelCapabilityNotFound
ErrSequenceSendNotFound = types.ErrSequenceSendNotFound
ErrSequenceReceiveNotFound = types.ErrSequenceReceiveNotFound
ErrSequenceAckNotFound = types.ErrSequenceAckNotFound
ErrInvalidPacket = types.ErrInvalidPacket
ErrPacketTimeout = types.ErrPacketTimeout
ErrTooManyConnectionHops = types.ErrTooManyConnectionHops
ErrAcknowledgementTooLong = types.ErrAcknowledgementTooLong
EventTypeChannelOpenInit = types.EventTypeChannelOpenInit
EventTypeChannelOpenTry = types.EventTypeChannelOpenTry
EventTypeChannelOpenAck = types.EventTypeChannelOpenAck
@ -74,31 +111,40 @@ var (
EventTypeChannelCloseInit = types.EventTypeChannelCloseInit
EventTypeChannelCloseConfirm = types.EventTypeChannelCloseConfirm
AttributeValueCategory = types.AttributeValueCategory
ErrInvalidLengthTypes = types.ErrInvalidLengthTypes
ErrIntOverflowTypes = types.ErrIntOverflowTypes
ErrUnexpectedEndOfGroupTypes = types.ErrUnexpectedEndOfGroupTypes
)
// nolint: golint
type (
Keeper = keeper.Keeper
Channel = types.Channel
Counterparty = types.Counterparty
State = types.State
Order = types.Order
IdentifiedChannel = types.IdentifiedChannel
ClientKeeper = types.ClientKeeper
ConnectionKeeper = types.ConnectionKeeper
PortKeeper = types.PortKeeper
MsgChannelOpenInit = types.MsgChannelOpenInit
MsgChannelOpenTry = types.MsgChannelOpenTry
MsgChannelOpenAck = types.MsgChannelOpenAck
MsgChannelOpenConfirm = types.MsgChannelOpenConfirm
MsgChannelCloseInit = types.MsgChannelCloseInit
MsgChannelCloseConfirm = types.MsgChannelCloseConfirm
MsgPacket = types.MsgPacket
MsgAcknowledgement = types.MsgAcknowledgement
MsgTimeout = types.MsgTimeout
Packet = types.Packet
ChannelResponse = types.ChannelResponse
PacketAckCommitment = types.PacketAckCommitment
PacketSequence = types.PacketSequence
GenesisState = types.GenesisState
IdentifiedChannel = types.IdentifiedChannel
ClientKeeper = types.ClientKeeper
ConnectionKeeper = types.ConnectionKeeper
PortKeeper = types.PortKeeper
PacketAckCommitment = types.PacketAckCommitment
PacketSequence = types.PacketSequence
GenesisState = types.GenesisState
ChannelResponse = types.ChannelResponse
QueryAllChannelsParams = types.QueryAllChannelsParams
QueryConnectionChannelsParams = types.QueryConnectionChannelsParams
QueryPacketCommitmentsParams = types.QueryPacketCommitmentsParams
QueryUnrelayedPacketsParams = types.QueryUnrelayedPacketsParams
PacketResponse = types.PacketResponse
RecvResponse = types.RecvResponse
State = types.State
Order = types.Order
MsgChannelOpenInit = types.MsgChannelOpenInit
MsgChannelOpenTry = types.MsgChannelOpenTry
MsgChannelOpenAck = types.MsgChannelOpenAck
MsgChannelOpenConfirm = types.MsgChannelOpenConfirm
MsgChannelCloseInit = types.MsgChannelCloseInit
MsgChannelCloseConfirm = types.MsgChannelCloseConfirm
MsgPacket = types.MsgPacket
MsgTimeout = types.MsgTimeout
MsgAcknowledgement = types.MsgAcknowledgement
Channel = types.Channel
Counterparty = types.Counterparty
Packet = types.Packet
Keeper = keeper.Keeper
)

View File

@ -230,7 +230,7 @@ func (k Keeper) GetAllPacketAckSeqs(ctx sdk.Context) (seqs []types.PacketSequenc
}
// IteratePacketCommitment provides an iterator over all PacketCommitment objects. For each
// aknowledgement, cb will be called. If the cb returns true, the iterator will close
// packet commitment, cb will be called. If the cb returns true, the iterator will close
// and stop.
func (k Keeper) IteratePacketCommitment(ctx sdk.Context, cb func(portID, channelID string, sequence uint64, hash []byte) bool) {
store := ctx.KVStore(k.storeKey)
@ -248,6 +248,26 @@ func (k Keeper) GetAllPacketCommitments(ctx sdk.Context) (commitments []types.Pa
return commitments
}
// IteratePacketCommitmentAtChannel provides an iterator over all PacketCommmitment objects
// at a specified channel. For each packet commitment, cb will be called. If the cb returns
// true, the iterator will close and stop.
func (k Keeper) IteratePacketCommitmentAtChannel(ctx sdk.Context, portID, channelID string, cb func(_, _ string, sequence uint64, hash []byte) bool) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, []byte(host.PacketCommitmentPrefixPath(portID, channelID)))
k.iterateHashes(ctx, iterator, cb)
}
// GetAllPacketCommitmentsAtChannel returns all stored PacketCommitments objects for a specified
// port ID and channel ID.
func (k Keeper) GetAllPacketCommitmentsAtChannel(ctx sdk.Context, portID, channelID string) (commitments []types.PacketAckCommitment) {
k.IteratePacketCommitmentAtChannel(ctx, portID, channelID, func(_, _ string, sequence uint64, hash []byte) bool {
pc := types.NewPacketAckCommitment(portID, channelID, sequence, hash)
commitments = append(commitments, pc)
return false
})
return commitments
}
// IteratePacketAcknowledgement provides an iterator over all PacketAcknowledgement objects. For each
// aknowledgement, cb will be called. If the cb returns true, the iterator will close
// and stop.
@ -306,7 +326,7 @@ func (k Keeper) LookupModuleByChannel(ctx sdk.Context, portID, channelID string)
return porttypes.GetModuleOwner(modules), cap, nil
}
// common functionality for IteratePacketCommitment and IteratePacketAcknowledgemen
// common functionality for IteratePacketCommitment and IteratePacketAcknowledgement
func (k Keeper) iterateHashes(_ sdk.Context, iterator db.Iterator, cb func(portID, channelID string, sequence uint64, hash []byte) bool) {
defer iterator.Close()

View File

@ -18,6 +18,7 @@ import (
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
ibckeeper "github.com/cosmos/cosmos-sdk/x/ibc/keeper"
"github.com/cosmos/cosmos-sdk/x/staking"
)
@ -51,10 +52,16 @@ const (
disabledTimeoutHeight = 0
)
var (
testPacketCommitment = []byte("packet commitment")
testAcknowledgement = []byte("acknowledgement")
)
type KeeperTestSuite struct {
suite.Suite
cdc *codec.Codec
cdc *codec.Codec
querier sdk.Querier
chainA *TestChain
chainB *TestChain
@ -65,6 +72,7 @@ func (suite *KeeperTestSuite) SetupTest() {
suite.chainB = NewTestChain(testClientIDB)
suite.cdc = suite.chainA.App.Codec()
suite.querier = ibckeeper.NewQuerier(*suite.chainA.App.IBCKeeper)
}
func (suite *KeeperTestSuite) TestSetChannel() {
@ -200,17 +208,61 @@ func (suite *KeeperTestSuite) TestSetSequence() {
suite.Equal(nextSeqAck, storedNextSeqAck)
}
func (suite *KeeperTestSuite) TestPackageCommitment() {
// TestPacketCommitment does basic verification of setting and getting of packet commitments within
// the Channel Keeper.
func (suite *KeeperTestSuite) TestPacketCommitment() {
ctx := suite.chainB.GetContext()
seq := uint64(10)
storedCommitment := suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, testPort1, testChannel1, seq)
suite.Equal([]byte(nil), storedCommitment)
commitment := []byte("commitment")
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctx, testPort1, testChannel1, seq, commitment)
storedCommitment := suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, testPort1, testChannel1, seq)
suite.Nil(storedCommitment)
suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctx, testPort1, testChannel1, seq, testPacketCommitment)
storedCommitment = suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, testPort1, testChannel1, seq)
suite.Equal(commitment, storedCommitment)
suite.Equal(testPacketCommitment, storedCommitment)
}
// TestGetAllPacketCommitmentsAtChannel verifies that iterator returns all stored packet commitments
// for a specific channel.
func (suite *KeeperTestSuite) TestGetAllPacketCommitmentsAtChannel() {
// setup
ctx := suite.chainB.GetContext()
expectedSeqs := make(map[uint64]bool)
seq := uint64(15)
maxSeq := uint64(25)
suite.Require().Greater(maxSeq, seq)
// create consecutive commitments
for i := uint64(1); i < seq; i++ {
suite.chainB.storePacketCommitment(ctx, testPort1, testChannel1, i)
expectedSeqs[i] = true
}
// add non-consecutive commitments
for i := seq; i < maxSeq; i += 2 {
suite.chainB.storePacketCommitment(ctx, testPort1, testChannel1, i)
expectedSeqs[i] = true
}
// add sequence on different channel/port
suite.chainB.storePacketCommitment(ctx, testPort2, testChannel2, maxSeq+1)
commitments := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllPacketCommitmentsAtChannel(ctx, testPort1, testChannel1)
suite.Equal(len(expectedSeqs), len(commitments))
suite.NotEqual(0, len(commitments))
// verify that all the packet commitments were stored
for _, packet := range commitments {
suite.True(expectedSeqs[packet.Sequence])
suite.Equal(testPort1, packet.PortID)
suite.Equal(testChannel1, packet.ChannelID)
// prevent duplicates from passing checks
expectedSeqs[packet.Sequence] = false
}
}
func (suite *KeeperTestSuite) TestSetPacketAcknowledgement() {
@ -442,6 +494,16 @@ func (chain *TestChain) createChannel(
return channel
}
// storePacketCommitment is a helper function that sets a packet commitment in the Channel Keeper.
func (chain *TestChain) storePacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64) {
chain.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctx, portID, channelID, sequence, testPacketCommitment)
}
// storeAcknowledgement is a helper function that sets a packet commitment in the Channel Keeper.
func (chain *TestChain) storeAcknowledgement(ctx sdk.Context, portID, channelID string, sequence uint64) {
chain.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctx, portID, channelID, sequence, testAcknowledgement)
}
func nextHeader(chain *TestChain) ibctmtypes.Header {
return ibctmtypes.CreateTestHeader(chain.Header.SignedHeader.Header.ChainID, int64(chain.Header.GetHeight())+1,
chain.Header.Time.Add(time.Minute), chain.Vals, chain.Signers)

View File

@ -66,3 +66,79 @@ func QuerierConnectionChannels(ctx sdk.Context, req abci.RequestQuery, k Keeper)
return res, nil
}
// QuerierPacketCommitments defines the sdk.Querier to query all packet commitments on a
// specified channel.
func QuerierPacketCommitments(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
var params types.QueryPacketCommitmentsParams
if err := k.cdc.UnmarshalJSON(req.Data, &params); err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}
packetCommitments := k.GetAllPacketCommitmentsAtChannel(ctx, params.PortID, params.ChannelID)
sequences := make([]uint64, 0, len(packetCommitments))
for _, pc := range packetCommitments {
sequences = append(sequences, pc.Sequence)
}
start, end := client.Paginate(len(sequences), params.Page, params.Limit, 100)
if start < 0 || end < 0 {
sequences = []uint64{}
} else {
sequences = sequences[start:end]
}
res, err := codec.MarshalJSONIndent(k.cdc, sequences)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return res, nil
}
// QuerierUnrelayedAcknowledgements defines the sdk.Querier to query all unrelayed
// acknowledgements for a specified channel end.
func QuerierUnrelayedAcknowledgements(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
return queryUnrelayedPackets(ctx, req, k, true)
}
// QuerierUnrelayedPacketSends defines the sdk.Querier to query all unrelayed packets for a
// specified channel end.
func QuerierUnrelayedPacketSends(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, error) {
return queryUnrelayedPackets(ctx, req, k, false)
}
// helper function to query for unrelayed packets as specified by the isForAcks boolean. If
// set to true it will return unrelayed acknowledgements otherwise it will return unrelayed
// packet sends.
func queryUnrelayedPackets(ctx sdk.Context, req abci.RequestQuery, k Keeper, isForAcks bool) ([]byte, error) {
var params types.QueryUnrelayedPacketsParams
if err := k.cdc.UnmarshalJSON(req.Data, &params); err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}
var unrelayedPackets []uint64
for _, seq := range params.Sequences {
if _, found := k.GetPacketAcknowledgement(ctx, params.PortID, params.ChannelID, seq); found == isForAcks {
unrelayedPackets = append(unrelayedPackets, seq)
}
}
start, end := client.Paginate(len(unrelayedPackets), params.Page, params.Limit, 100)
if start < 0 || end < 0 {
unrelayedPackets = []uint64{}
} else {
unrelayedPackets = unrelayedPackets[start:end]
}
res, err := codec.MarshalJSONIndent(k.cdc, unrelayedPackets)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
}
return res, nil
}

View File

@ -0,0 +1,436 @@
package keeper_test
import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec"
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
)
// TestQueryChannels tests singular, muliple, and no connection for
// correct retrieval of all channels.
func (suite *KeeperTestSuite) TestQueryChannels() {
path := []string{types.SubModuleName, types.QueryAllChannels}
var (
expRes []byte
err error
)
params := types.NewQueryAllChannelsParams(1, 100)
data, err := suite.cdc.MarshalJSON(params)
suite.NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
testCases := []struct {
name string
setup func()
}{
{
"success with different connection channels",
func() {
suite.SetupTest()
channels := make([]types.IdentifiedChannel, 0, 2)
// create channels on different connections
suite.chainA.createConnection(
testConnectionIDA, testConnectionIDB,
testClientIDA, testClientIDB,
connection.OPEN,
)
channels = append(channels,
types.NewIdentifiedChannel(testPort1, testChannel1,
suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2,
types.OPEN, types.ORDERED, testConnectionIDA,
),
),
)
suite.chainA.createConnection(
testConnectionIDB, testConnectionIDA,
testClientIDB, testClientIDA,
connection.OPEN,
)
channels = append(channels,
types.NewIdentifiedChannel(testPort2, testChannel2,
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1,
types.OPEN, types.ORDERED, testConnectionIDB,
),
),
)
// set expected result
expRes, err = codec.MarshalJSONIndent(suite.cdc, channels)
suite.NoError(err)
},
},
{
"success with singular connection channels",
func() {
suite.SetupTest()
channels := make([]types.IdentifiedChannel, 0, 2)
// create channels on singular connections
suite.chainA.createConnection(
testConnectionIDA, testConnectionIDB,
testClientIDA, testClientIDB,
connection.OPEN,
)
channels = append(channels,
types.NewIdentifiedChannel(testPort1, testChannel1,
suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2,
types.OPEN, types.ORDERED, testConnectionIDA,
),
),
)
channels = append(channels,
types.NewIdentifiedChannel(testPort2, testChannel2,
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1,
types.OPEN, types.UNORDERED, testConnectionIDA,
),
),
)
// set expected result
expRes, err = codec.MarshalJSONIndent(suite.cdc, channels)
suite.NoError(err)
},
},
{
"success no channels",
func() {
suite.SetupTest()
expRes, err = codec.MarshalJSONIndent(suite.cdc, []types.IdentifiedChannel{})
suite.NoError(err)
},
},
}
for i, tc := range testCases {
tc.setup()
bz, err := suite.querier(suite.chainA.GetContext(), path, query)
suite.NoError(err, "test case %d failed: %s", i, tc.name)
suite.Equal(expRes, bz, "test case %d failed: %s", i, tc.name)
}
}
// TestQueryConnectionChannel tests querying existing channels on a singular connection.
func (suite *KeeperTestSuite) TestQueryConnectionChannels() {
path := []string{types.SubModuleName, types.QueryConnectionChannels}
var (
expRes []byte
err error
)
params := types.NewQueryConnectionChannelsParams(testConnectionIDA, 1, 100)
data, err := suite.cdc.MarshalJSON(params)
suite.NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
testCases := []struct {
name string
setup func()
}{
{
"success with singular connection channels",
func() {
suite.SetupTest()
channels := make([]types.IdentifiedChannel, 0, 2)
// create channels on singular connections
suite.chainA.createConnection(
testConnectionIDA, testConnectionIDB,
testClientIDA, testClientIDB,
connection.OPEN,
)
channels = append(channels,
types.NewIdentifiedChannel(testPort1, testChannel1,
suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2,
types.OPEN, types.ORDERED, testConnectionIDA,
),
),
)
channels = append(channels,
types.NewIdentifiedChannel(testPort2, testChannel2,
suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1,
types.OPEN, types.UNORDERED, testConnectionIDA,
),
),
)
// set expected result
expRes, err = codec.MarshalJSONIndent(suite.cdc, channels)
suite.NoError(err)
},
},
{
"success multiple connection channels",
func() {
suite.SetupTest()
channels := make([]types.IdentifiedChannel, 0, 1)
// create channels on different connections
suite.chainA.createConnection(
testConnectionIDA, testConnectionIDB,
testClientIDA, testClientIDB,
connection.OPEN,
)
channels = append(channels,
types.NewIdentifiedChannel(testPort1, testChannel1,
suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2,
types.OPEN, types.ORDERED, testConnectionIDA,
),
),
)
suite.chainA.createConnection(
testConnectionIDB, testConnectionIDA,
testClientIDB, testClientIDA,
connection.OPEN,
)
suite.chainA.createChannel(
testPort2, testChannel2, testPort1, testChannel1,
types.OPEN, types.ORDERED, testConnectionIDB,
)
// set expected result
expRes, err = codec.MarshalJSONIndent(suite.cdc, channels)
suite.NoError(err)
},
},
{
"success no channels",
func() {
suite.SetupTest()
expRes, err = codec.MarshalJSONIndent(suite.cdc, []types.IdentifiedChannel{})
suite.NoError(err)
},
},
}
for i, tc := range testCases {
tc.setup()
bz, err := suite.querier(suite.chainA.GetContext(), path, query)
suite.NoError(err, "test case %d failed: %s", i, tc.name)
suite.Equal(expRes, bz, "test case %d failed: %s", i, tc.name)
}
}
// TestQueryPacketCommitments tests querying packet commitments on a specified channel end.
func (suite *KeeperTestSuite) TestQueryPacketCommitments() {
path := []string{types.SubModuleName, types.QueryPacketCommitments}
var (
expRes []byte
)
params := types.NewQueryPacketCommitmentsParams(testPort1, testChannel1, 1, 100)
data, err := suite.cdc.MarshalJSON(params)
suite.NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
testCases := []struct {
name string
setup func()
}{
{
"success",
func() {
suite.SetupTest()
ctx := suite.chainA.GetContext()
seq := uint64(1)
commitments := []uint64{}
// create several commitments on the same channel and port
for i := seq; i < 10; i++ {
suite.chainA.storePacketCommitment(ctx, testPort1, testChannel1, i)
commitments = append(commitments, i)
}
expRes, err = codec.MarshalJSONIndent(suite.cdc, commitments)
suite.NoError(err)
},
},
{
"success with multiple channels",
func() {
suite.SetupTest()
ctx := suite.chainA.GetContext()
seq := uint64(1)
commitments := []uint64{}
// create several commitments on the same channel and port
for i := seq; i < 10; i++ {
suite.chainA.storePacketCommitment(ctx, testPort1, testChannel1, i)
commitments = append(commitments, i)
}
// create several commitments on a different channel and port
for i := seq; i < 10; i++ {
suite.chainA.storePacketCommitment(ctx, testPort2, testChannel2, i)
}
expRes, err = codec.MarshalJSONIndent(suite.cdc, commitments)
suite.NoError(err)
},
},
{
"success no packet commitments",
func() {
suite.SetupTest()
expRes, err = codec.MarshalJSONIndent(suite.cdc, []uint64{})
suite.NoError(err)
},
},
}
for i, tc := range testCases {
tc.setup()
bz, err := suite.querier(suite.chainA.GetContext(), path, query)
suite.NoError(err, "test case %d failed: %s", i, tc.name)
suite.Equal(expRes, bz, "test case %d failed: %s", i, tc.name)
}
}
// TestQueryUnrelayedPackets tests querying unrelayed acknowledgements and unrelayed packets sends
// on a specified channel end.
func (suite *KeeperTestSuite) TestQueryUnrelayedAcks() {
pathAck := []string{types.SubModuleName, types.QueryUnrelayedAcknowledgements}
pathSend := []string{types.SubModuleName, types.QueryUnrelayedPacketSends}
sequences := []uint64{1, 2, 3, 4, 5}
var (
expResAck []byte
expResSend []byte
)
params := types.NewQueryUnrelayedPacketsParams(testPort1, testChannel1, sequences, 1, 100)
data, err := suite.cdc.MarshalJSON(params)
suite.NoError(err)
query := abci.RequestQuery{
Path: "",
Data: data,
}
testCases := []struct {
name string
setup func()
}{
{
"success",
func() {
suite.SetupTest()
ctx := suite.chainA.GetContext()
unrelayedAcks := []uint64{}
unrelayedSends := []uint64{}
// create acknowledgements for first 3 sequences
for _, seq := range sequences {
if seq < 4 {
suite.chainA.storeAcknowledgement(ctx, testPort1, testChannel1, seq)
unrelayedAcks = append(unrelayedAcks, seq)
} else {
unrelayedSends = append(unrelayedSends, seq)
}
}
expResAck, err = codec.MarshalJSONIndent(suite.cdc, unrelayedAcks)
suite.NoError(err)
expResSend, err = codec.MarshalJSONIndent(suite.cdc, unrelayedSends)
suite.NoError(err)
},
},
{
"success with multiple channels",
func() {
suite.SetupTest()
ctx := suite.chainA.GetContext()
unrelayedAcks := []uint64{}
unrelayedSends := []uint64{}
// create acknowledgements for first 3 sequences
for _, seq := range sequences {
if seq < 4 {
suite.chainA.storeAcknowledgement(ctx, testPort1, testChannel1, seq)
unrelayedAcks = append(unrelayedAcks, seq)
} else {
unrelayedSends = append(unrelayedSends, seq)
}
}
// create acknowledgements for other sequences on different channel/port
for _, seq := range sequences {
if seq >= 4 {
suite.chainA.storeAcknowledgement(ctx, testPort2, testChannel2, seq)
}
}
expResAck, err = codec.MarshalJSONIndent(suite.cdc, unrelayedAcks)
suite.NoError(err)
expResSend, err = codec.MarshalJSONIndent(suite.cdc, unrelayedSends)
suite.NoError(err)
},
},
{
"success no unrelayed acks",
func() {
suite.SetupTest()
ctx := suite.chainA.GetContext()
// create acknowledgements for all sequences
for _, seq := range sequences {
suite.chainA.storeAcknowledgement(ctx, testPort1, testChannel1, seq)
}
expResSend, err = codec.MarshalJSONIndent(suite.cdc, []uint64{})
suite.NoError(err)
expResAck, err = codec.MarshalJSONIndent(suite.cdc, sequences)
suite.NoError(err)
},
},
}
for i, tc := range testCases {
tc.setup()
bz, err := suite.querier(suite.chainA.GetContext(), pathAck, query)
suite.NoError(err, "test case %d failed: %s", i, tc.name)
suite.Equal(expResAck, bz, "test case %d failed: %s", i, tc.name)
bz, err = suite.querier(suite.chainA.GetContext(), pathSend, query)
suite.NoError(err, "test case %d failed: %s", i, tc.name)
suite.Equal(expResSend, bz, "test case %d failed: %s", i, tc.name)
}
}

View File

@ -11,9 +11,12 @@ import (
// query routes supported by the IBC channel Querier
const (
QueryAllChannels = "channels"
QueryChannel = "channel"
QueryConnectionChannels = "connection-channels"
QueryAllChannels = "channels"
QueryChannel = "channel"
QueryConnectionChannels = "connection-channels"
QueryPacketCommitments = "packet-commitments"
QueryUnrelayedAcknowledgements = "unrelayed-acknowledgements"
QueryUnrelayedPacketSends = "unrelayed-packet-sends"
)
// ChannelResponse defines the client query response for a channel which also
@ -70,6 +73,46 @@ func NewQueryConnectionChannelsParams(connection string, page, limit int) QueryC
}
}
// QueryPacketCommitmentsParams defines the parameters necessary for querying
// all packet commitments at an associated port ID and channel ID.
type QueryPacketCommitmentsParams struct {
PortID string `json:"port_id" yaml:"port_id"`
ChannelID string `json:"channel_id" yaml:"channel_id"`
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
}
// NewQueryPacketCommitmentsParams creates a new QueryPacketCommitmentsParams instance.
func NewQueryPacketCommitmentsParams(portID, channelID string, page, limit int) QueryPacketCommitmentsParams {
return QueryPacketCommitmentsParams{
PortID: portID,
ChannelID: channelID,
Page: page,
Limit: limit,
}
}
// QueryUnrelayedPacketsParams defines the parameters necessary for querying
// unrelayed packets at an associated port ID and channel ID.
type QueryUnrelayedPacketsParams struct {
PortID string `json:"port_id" yaml:"port_id"`
ChannelID string `json:"channel_id" yaml:"channel_id"`
Sequences []uint64 `json:"sequences" yaml:"sequences"`
Page int `json:"page" yaml:"page"`
Limit int `json:"limit" yaml:"limit"`
}
// NewQueryUnrealyedPacketsParams creates a new QueryUnrelayedPacketsParams instance.
func NewQueryUnrelayedPacketsParams(portID, channelID string, sequences []uint64, page, limit int) QueryUnrelayedPacketsParams {
return QueryUnrelayedPacketsParams{
PortID: portID,
ChannelID: channelID,
Sequences: sequences,
Page: page,
Limit: limit,
}
}
// PacketResponse defines the client query response for a packet which also
// includes a proof, its path and the height form which the proof was retrieved
type PacketResponse struct {

View File

@ -139,6 +139,11 @@ func PacketCommitmentPath(portID, channelID string, sequence uint64) string {
return fmt.Sprintf("%s/", KeyPacketCommitmentPrefix) + channelPath(portID, channelID) + fmt.Sprintf("/packets/%d", sequence)
}
// PacketCommitmentPrefixPath defines the prefix for commitments to packet data fields store path.
func PacketCommitmentPrefixPath(portID, channelID string) string {
return fmt.Sprintf("%s/", KeyPacketCommitmentPrefix) + channelPath(portID, channelID)
}
// PacketAcknowledgementPath defines the packet acknowledgement store path
func PacketAcknowledgementPath(portID, channelID string, sequence uint64) string {
return fmt.Sprintf("%s/", KeyPacketAckPrefix) + channelPath(portID, channelID) + fmt.Sprintf("/acknowledgements/%d", sequence)

View File

@ -43,11 +43,17 @@ func NewQuerier(k Keeper) sdk.Querier {
res, err = channel.QuerierChannels(ctx, req, k.ChannelKeeper)
case channel.QueryConnectionChannels:
res, err = channel.QuerierConnectionChannels(ctx, req, k.ChannelKeeper)
case channel.QueryPacketCommitments:
res, err = channel.QuerierPacketCommitments(ctx, req, k.ChannelKeeper)
case channel.QueryUnrelayedAcknowledgements:
res, err = channel.QuerierUnrelayedAcknowledgements(ctx, req, k.ChannelKeeper)
case channel.QueryUnrelayedPacketSends:
res, err = channel.QuerierUnrelayedPacketSends(ctx, req, k.ChannelKeeper)
default:
err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown IBC %s query endpoint", channel.SubModuleName)
}
default:
err = sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown IBC query endpoint")
err = sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown IBC query endpoint")
}
return res, err

View File

@ -91,6 +91,24 @@ func (suite *KeeperTestSuite) TestNewQuerier() {
false,
"",
},
{
"channel - QuerierPacketCommitments",
[]string{channel.SubModuleName, channel.QueryPacketCommitments},
false,
"",
},
{
"channel - QuerierUnrelayedAcknowledgements",
[]string{channel.SubModuleName, channel.QueryUnrelayedAcknowledgements},
false,
"",
},
{
"channel - QuerierUnrelayedPacketSends",
[]string{channel.SubModuleName, channel.QueryUnrelayedPacketSends},
false,
"",
},
{
"channel - invalid query",
[]string{channel.SubModuleName, "foo"},