cosmos-sdk/x/ibc/04-channel/keeper/handshake_test.go

647 lines
26 KiB
Go

package keeper_test
import (
"fmt"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
)
type testCase = struct {
msg string
malleate func()
expPass bool
}
// TestChanOpenInit tests the OpenInit handshake call for channels. It uses message passing
// to enter into the appropriate state and then calls ChanOpenInit directly. The channel is
// being created on chainA. The port capability must be created on chainA before ChanOpenInit
// can succeed.
func (suite *KeeperTestSuite) TestChanOpenInit() {
var (
connA *ibctesting.TestConnection
connB *ibctesting.TestConnection
portCap *capabilitytypes.Capability
)
testCases := []testCase{
{"success", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
suite.chainA.CreatePortCapability(connA.NextTestChannel().PortID)
portCap = suite.chainA.GetPortCapability(connA.NextTestChannel().PortID)
}, true},
{"channel already exists", func() {
_, _, connA, connB, _, _ = suite.coordinator.Setup(suite.chainA, suite.chainB)
}, false},
{"connection doesn't exist", func() {
// any non-nil values of connA and connB are acceptable
suite.Require().NotNil(connA)
suite.Require().NotNil(connB)
}, false},
{"connection is UNINITIALIZED", func() {
// any non-nil values of connA and connB are acceptable
suite.Require().NotNil(connA)
suite.Require().NotNil(connB)
// set connection as UNINITIALIZED
counterparty := connectiontypes.NewCounterparty(clientIDB, connIDA, suite.chainB.GetPrefix())
connection := connectiontypes.NewConnectionEnd(connectiontypes.UNINITIALIZED, clientIDA, connIDA, counterparty, []string{ibctesting.ConnectionVersion})
suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), connA.ID, connection)
portCap = nil
}, false},
{"capability is incorrect", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
portCap = capabilitytypes.NewCapability(3)
}, false},
}
for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
// run test for all types of ordering
for _, order := range []types.Order{types.UNORDERED, types.ORDERED} {
suite.SetupTest() // reset
tc.malleate()
counterparty := types.NewCounterparty(connB.FirstOrNextTestChannel().PortID, connB.FirstOrNextTestChannel().ID)
channelA := connA.FirstOrNextTestChannel()
cap, err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenInit(
suite.chainA.GetContext(), order, []string{connA.ID},
channelA.PortID, channelA.ID, portCap, counterparty, ibctesting.ChannelVersion,
)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(cap)
chanCap, ok := suite.chainA.App.ScopedIBCKeeper.GetCapability(
suite.chainA.GetContext(),
host.ChannelCapabilityPath(channelA.PortID, channelA.ID),
)
suite.Require().True(ok, "could not retrieve channel capability after successful ChanOpenInit")
suite.Require().Equal(chanCap.String(), cap.String(), "channel capability is not correct")
} else {
suite.Require().Error(err)
}
}
})
}
}
// TestChanOpenTry tests the OpenTry handshake call for channels. It uses message passing
// to enter into the appropriate state and then calls ChanOpenTry directly. The channel
// is being created on chainB. The port capability must be created on chainB before
// ChanOpenTry can succeed.
func (suite *KeeperTestSuite) TestChanOpenTry() {
var (
connA *ibctesting.TestConnection
connB *ibctesting.TestConnection
portCap *capabilitytypes.Capability
heightDiff uint64
)
testCases := []testCase{
{"success", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.chainB.CreatePortCapability(connB.NextTestChannel().PortID)
portCap = suite.chainB.GetPortCapability(connB.NextTestChannel().PortID)
}, true},
{"previous channel with invalid state", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
// make previous channel have wrong ordering
suite.coordinator.ChanOpenInit(suite.chainB, suite.chainA, connB, connA, types.UNORDERED)
}, false},
{"connection doesn't exist", func() {
// any non-nil values of connA and connB are acceptable
suite.Require().NotNil(connA)
suite.Require().NotNil(connB)
// pass capability check
suite.chainB.CreatePortCapability(connB.FirstOrNextTestChannel().PortID)
portCap = suite.chainB.GetPortCapability(connB.FirstOrNextTestChannel().PortID)
}, false},
{"connection is not OPEN", func() {
clientA, clientB := suite.coordinator.SetupClients(suite.chainA, suite.chainB, clientexported.Tendermint)
// pass capability check
suite.chainB.CreatePortCapability(connB.FirstOrNextTestChannel().PortID)
portCap = suite.chainB.GetPortCapability(connB.FirstOrNextTestChannel().PortID)
var err error
connB, connA, err = suite.coordinator.ConnOpenInit(suite.chainB, suite.chainA, clientB, clientA)
suite.Require().NoError(err)
}, false},
{"consensus state not found", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.chainB.CreatePortCapability(connB.NextTestChannel().PortID)
portCap = suite.chainB.GetPortCapability(connB.NextTestChannel().PortID)
heightDiff = 3 // consensus state doesn't exist at this height
}, false},
{"channel verification failed", func() {
// not creating a channel on chainA will result in an invalid proof of existence
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
portCap = suite.chainB.GetPortCapability(connB.NextTestChannel().PortID)
}, false},
{"port capability not found", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
portCap = capabilitytypes.NewCapability(3)
}, false},
}
for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
heightDiff = 0 // must be explicitly changed in malleate
tc.malleate()
counterparty := types.NewCounterparty(connA.FirstOrNextTestChannel().PortID, connA.FirstOrNextTestChannel().ID)
channelB := connB.FirstOrNextTestChannel()
channelKey := host.KeyChannel(counterparty.PortID, counterparty.ChannelID)
proof, proofHeight := suite.chainA.QueryProof(channelKey)
cap, err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanOpenTry(
suite.chainB.GetContext(), types.ORDERED, []string{connB.ID},
channelB.PortID, channelB.ID, portCap, counterparty, ibctesting.ChannelVersion, ibctesting.ChannelVersion,
proof, proofHeight+heightDiff,
)
if tc.expPass {
suite.Require().NoError(err)
suite.Require().NotNil(cap)
chanCap, ok := suite.chainB.App.ScopedIBCKeeper.GetCapability(
suite.chainB.GetContext(),
host.ChannelCapabilityPath(channelB.PortID, channelB.ID),
)
suite.Require().True(ok, "could not retrieve channel capapbility after successful ChanOpenTry")
suite.Require().Equal(chanCap.String(), cap.String(), "channel capability is not correct")
} else {
suite.Require().Error(err)
}
})
}
}
// TestChanOpenAck tests the OpenAck handshake call for channels. It uses message passing
// to enter into the appropriate state and then calls ChanOpenAck directly. The handshake
// call is occurring on chainA.
func (suite *KeeperTestSuite) TestChanOpenAck() {
var (
connA *ibctesting.TestConnection
connB *ibctesting.TestConnection
channelCap *capabilitytypes.Capability
heightDiff uint64
)
testCases := []testCase{
{"success", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenTry(suite.chainB, suite.chainA, channelB, channelA, connB, types.ORDERED)
suite.Require().NoError(err)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, true},
{"channel doesn't exist", func() {}, false},
{"channel state is not INIT or TRYOPEN", func() {
// create fully open channels on both chains
_, _, connA, connB, _, _ = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelA := connA.Channels[0]
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"connection not found", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenTry(suite.chainB, suite.chainA, channelB, channelA, connB, types.ORDERED)
suite.Require().NoError(err)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
// set the channel's connection hops to wrong connection ID
channel := suite.chainA.GetChannel(channelA)
channel.ConnectionHops[0] = "doesnotexist"
suite.chainA.App.IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), channelA.PortID, channelA.ID, channel)
}, false},
{"connection is not OPEN", func() {
clientA, clientB := suite.coordinator.SetupClients(suite.chainA, suite.chainB, clientexported.Tendermint)
var err error
connA, connB, err = suite.coordinator.ConnOpenInit(suite.chainA, suite.chainB, clientA, clientB)
suite.Require().NoError(err)
// create channel in init
channelA, _, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.Require().NoError(err)
suite.chainA.CreateChannelCapability(channelA.PortID, channelA.ID)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"consensus state not found", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenTry(suite.chainB, suite.chainA, channelB, channelA, connB, types.ORDERED)
suite.Require().NoError(err)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
heightDiff = 3 // consensus state doesn't exist at this height
}, false},
{"channel verification failed", func() {
// chainB is INIT, chainA in TRYOPEN
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelB, channelA, err := suite.coordinator.ChanOpenInit(suite.chainB, suite.chainA, connB, connA, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenTry(suite.chainA, suite.chainB, channelA, channelB, connA, types.ORDERED)
suite.Require().NoError(err)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"channel capability not found", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.Require().NoError(err)
suite.coordinator.ChanOpenTry(suite.chainB, suite.chainA, channelB, channelA, connB, types.ORDERED)
channelCap = capabilitytypes.NewCapability(6)
}, false},
}
for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
heightDiff = 0 // must be explicitly changed
tc.malleate()
channelA := connA.FirstOrNextTestChannel()
channelB := connB.FirstOrNextTestChannel()
channelKey := host.KeyChannel(channelB.PortID, channelB.ID)
proof, proofHeight := suite.chainB.QueryProof(channelKey)
err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenAck(
suite.chainA.GetContext(), channelA.PortID, channelA.ID, channelCap, ibctesting.ChannelVersion,
proof, proofHeight+heightDiff,
)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
// TestChanOpenConfirm tests the OpenAck handshake call for channels. It uses message passing
// to enter into the appropriate state and then calls ChanOpenConfirm directly. The handshake
// call is occurring on chainB.
func (suite *KeeperTestSuite) TestChanOpenConfirm() {
var (
connA *ibctesting.TestConnection
connB *ibctesting.TestConnection
channelCap *capabilitytypes.Capability
heightDiff uint64
)
testCases := []testCase{
{"success", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenTry(suite.chainB, suite.chainA, channelB, channelA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenAck(suite.chainA, suite.chainB, channelA, channelB)
suite.Require().NoError(err)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, true},
{"channel doesn't exist", func() {}, false},
{"channel state is not TRYOPEN", func() {
// create fully open channels on both cahins
_, _, connA, connB, _, _ = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelB := connB.Channels[0]
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"connection not found", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenTry(suite.chainB, suite.chainA, channelB, channelA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenAck(suite.chainA, suite.chainB, channelA, channelB)
suite.Require().NoError(err)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
// set the channel's connection hops to wrong connection ID
channel := suite.chainB.GetChannel(channelB)
channel.ConnectionHops[0] = "doesnotexist"
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(suite.chainB.GetContext(), channelB.PortID, channelB.ID, channel)
}, false},
{"connection is not OPEN", func() {
clientA, clientB := suite.coordinator.SetupClients(suite.chainA, suite.chainB, clientexported.Tendermint)
var err error
connA, connB, err = suite.coordinator.ConnOpenInit(suite.chainB, suite.chainA, clientB, clientA)
suite.Require().NoError(err)
channelB := connB.FirstOrNextTestChannel()
suite.chainB.CreateChannelCapability(channelB.PortID, channelB.ID)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"consensus state not found", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenTry(suite.chainB, suite.chainA, channelB, channelA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenAck(suite.chainA, suite.chainB, channelA, channelB)
suite.Require().NoError(err)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
heightDiff = 3
}, false},
{"channel verification failed", func() {
// chainA is INIT, chainB in TRYOPEN
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenTry(suite.chainB, suite.chainA, channelB, channelA, connB, types.ORDERED)
suite.Require().NoError(err)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"channel capability not found", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, clientexported.Tendermint)
channelA, channelB, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenTry(suite.chainB, suite.chainA, channelB, channelA, connB, types.ORDERED)
suite.Require().NoError(err)
err = suite.coordinator.ChanOpenAck(suite.chainA, suite.chainB, channelA, channelB)
suite.Require().NoError(err)
channelCap = capabilitytypes.NewCapability(6)
}, false},
}
for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
heightDiff = 0 // must be explicitly changed
tc.malleate()
channelA := connA.FirstOrNextTestChannel()
channelB := connB.FirstOrNextTestChannel()
channelKey := host.KeyChannel(channelA.PortID, channelA.ID)
proof, proofHeight := suite.chainA.QueryProof(channelKey)
err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanOpenConfirm(
suite.chainB.GetContext(), channelB.PortID, channelB.ID,
channelCap, proof, proofHeight+heightDiff,
)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
// TestChanCloseInit tests the initial closing of a handshake on chainA by calling
// ChanCloseInit. Both chains will use message passing to setup OPEN channels.
func (suite *KeeperTestSuite) TestChanCloseInit() {
var (
connA *ibctesting.TestConnection
connB *ibctesting.TestConnection
channelCap *capabilitytypes.Capability
)
testCases := []testCase{
{"success", func() {
_, _, connA, connB, _, _ = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelA := connA.Channels[0]
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, true},
{"channel doesn't exist", func() {
// any non-nil values work for connections
suite.Require().NotNil(connA)
suite.Require().NotNil(connB)
channelA := connA.FirstOrNextTestChannel()
// ensure channel capability check passes
suite.chainA.CreateChannelCapability(channelA.PortID, channelA.ID)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"channel state is CLOSED", func() {
_, _, connA, connB, _, _ = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelA := connA.Channels[0]
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
// close channel
err := suite.coordinator.SetChannelClosed(suite.chainA, suite.chainB, channelA)
suite.Require().NoError(err)
}, false},
{"connection not found", func() {
_, _, connA, connB, _, _ = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelA := connA.Channels[0]
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
// set the channel's connection hops to wrong connection ID
channel := suite.chainA.GetChannel(channelA)
channel.ConnectionHops[0] = "doesnotexist"
suite.chainA.App.IBCKeeper.ChannelKeeper.SetChannel(suite.chainA.GetContext(), channelA.PortID, channelA.ID, channel)
}, false},
{"connection is not OPEN", func() {
clientA, clientB := suite.coordinator.SetupClients(suite.chainA, suite.chainB, clientexported.Tendermint)
var err error
connA, connB, err = suite.coordinator.ConnOpenInit(suite.chainA, suite.chainB, clientA, clientB)
suite.Require().NoError(err)
// create channel in init
channelA, _, err := suite.coordinator.ChanOpenInit(suite.chainA, suite.chainB, connA, connB, types.ORDERED)
// ensure channel capability check passes
suite.chainA.CreateChannelCapability(channelA.PortID, channelA.ID)
channelCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
}, false},
{"channel capability not found", func() {
_, _, connA, connB, _, _ = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelCap = capabilitytypes.NewCapability(3)
}, false},
}
for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
tc.malleate()
channelA := connA.FirstOrNextTestChannel()
err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanCloseInit(
suite.chainA.GetContext(), channelA.PortID, channelA.ID, channelCap,
)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}
// TestChanCloseConfirm tests the confirming closing channel ends by calling ChanCloseConfirm
// on chainB. Both chains will use message passing to setup OPEN channels. ChanCloseInit is
// bypassed on chainA by setting the channel state in the ChannelKeeper.
func (suite *KeeperTestSuite) TestChanCloseConfirm() {
var (
connA *ibctesting.TestConnection
connB *ibctesting.TestConnection
channelA ibctesting.TestChannel
channelB ibctesting.TestChannel
channelCap *capabilitytypes.Capability
heightDiff uint64
)
testCases := []testCase{
{"success", func() {
_, _, connA, connB, channelA, channelB = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
err := suite.coordinator.SetChannelClosed(suite.chainA, suite.chainB, channelA)
suite.Require().NoError(err)
}, true},
{"channel doesn't exist", func() {
// any non-nil values work for connections
suite.Require().NotNil(connA)
suite.Require().NotNil(connB)
channelB = connB.FirstOrNextTestChannel()
// ensure channel capability check passes
suite.chainB.CreateChannelCapability(channelB.PortID, channelB.ID)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"channel state is CLOSED", func() {
_, _, connA, connB, _, channelB = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
err := suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
suite.Require().NoError(err)
}, false},
{"connection not found", func() {
_, _, connA, connB, _, channelB = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
// set the channel's connection hops to wrong connection ID
channel := suite.chainB.GetChannel(channelB)
channel.ConnectionHops[0] = "doesnotexist"
suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(suite.chainB.GetContext(), channelB.PortID, channelB.ID, channel)
}, false},
{"connection is not OPEN", func() {
clientA, clientB := suite.coordinator.SetupClients(suite.chainA, suite.chainB, clientexported.Tendermint)
var err error
connB, connA, err = suite.coordinator.ConnOpenInit(suite.chainB, suite.chainA, clientB, clientA)
suite.Require().NoError(err)
// create channel in init
channelB, _, err := suite.coordinator.ChanOpenInit(suite.chainB, suite.chainA, connB, connA, types.ORDERED)
suite.Require().NoError(err)
// ensure channel capability check passes
suite.chainB.CreateChannelCapability(channelB.PortID, channelB.ID)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"consensus state not found", func() {
_, _, connA, connB, _, channelB = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
err := suite.coordinator.SetChannelClosed(suite.chainA, suite.chainB, channelA)
suite.Require().NoError(err)
heightDiff = 3
}, false},
{"channel verification failed", func() {
// channel not closed
_, _, connA, connB, _, channelB = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
}, false},
{"channel capability not found", func() {
_, _, connA, connB, channelA, channelB = suite.coordinator.Setup(suite.chainA, suite.chainB)
channelCap = suite.chainB.GetChannelCapability(channelB.PortID, channelB.ID)
err := suite.coordinator.SetChannelClosed(suite.chainA, suite.chainB, channelA)
suite.Require().NoError(err)
channelCap = capabilitytypes.NewCapability(3)
}, false},
}
for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
heightDiff = 0 // must explicitly be changed
tc.malleate()
channelA = connA.FirstOrNextTestChannel()
channelB = connB.FirstOrNextTestChannel()
channelKey := host.KeyChannel(channelA.PortID, channelA.ID)
proof, proofHeight := suite.chainA.QueryProof(channelKey)
err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanCloseConfirm(
suite.chainB.GetContext(), channelB.PortID, channelB.ID, channelCap,
proof, proofHeight+heightDiff,
)
if tc.expPass {
suite.Require().NoError(err)
} else {
suite.Require().Error(err)
}
})
}
}