351 lines
19 KiB
Go
351 lines
19 KiB
Go
package keeper_test
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
|
|
"github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types"
|
|
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
|
|
"github.com/cosmos/cosmos-sdk/x/ibc/exported"
|
|
ibctesting "github.com/cosmos/cosmos-sdk/x/ibc/testing"
|
|
)
|
|
|
|
// TestTimeoutPacket test the TimeoutPacket call on chainA by ensuring the timeout has passed
|
|
// on chainB, but that no ack has been written yet. Test cases expected to reach proof
|
|
// verification must specify which proof to use using the ordered bool.
|
|
func (suite *KeeperTestSuite) TestTimeoutPacket() {
|
|
var (
|
|
packet types.Packet
|
|
nextSeqRecv uint64
|
|
ordered bool
|
|
)
|
|
|
|
testCases := []testCase{
|
|
{"success: ORDERED", func() {
|
|
ordered = true
|
|
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
// need to update chainA's client representing chainB to prove missing ack
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
}, true},
|
|
{"success: UNORDERED", func() {
|
|
ordered = false
|
|
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), disabledTimeoutTimestamp)
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
// need to update chainA's client representing chainB to prove missing ack
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
}, true},
|
|
{"channel not found", func() {
|
|
// use wrong channel naming
|
|
_, _, _, _, _, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
|
|
}, false},
|
|
{"channel not open", func() {
|
|
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
|
|
|
|
err := suite.coordinator.SetChannelClosed(suite.chainA, suite.chainB, channelA)
|
|
suite.Require().NoError(err)
|
|
}, false},
|
|
{"packet destination port ≠ channel counterparty port", func() {
|
|
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
// use wrong port for dest
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, ibctesting.InvalidID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
|
|
}, false},
|
|
{"packet destination channel ID ≠ channel counterparty channel ID", func() {
|
|
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
// use wrong channel for dest
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, ibctesting.InvalidID, timeoutHeight, disabledTimeoutTimestamp)
|
|
}, false},
|
|
{"connection not found", func() {
|
|
channelA := ibctesting.TestChannel{PortID: portID, ID: channelIDA}
|
|
channelB := ibctesting.TestChannel{PortID: portID, ID: channelIDB}
|
|
// pass channel check
|
|
suite.chainA.App.IBCKeeper.ChannelKeeper.SetChannel(
|
|
suite.chainA.GetContext(),
|
|
channelA.PortID, channelA.ID,
|
|
types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(channelB.PortID, channelB.ID), []string{connIDA}, channelA.Version),
|
|
)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
|
|
}, false},
|
|
{"timeout", func() {
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
}, false},
|
|
{"packet already received ", func() {
|
|
ordered = true
|
|
nextSeqRecv = 2
|
|
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
}, false},
|
|
{"packet hasn't been sent", func() {
|
|
clientA, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
}, false},
|
|
{"next seq receive verification failed", func() {
|
|
// set ordered to false resulting in wrong proof provided
|
|
ordered = false
|
|
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), disabledTimeoutTimestamp)
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
}, false},
|
|
{"packet ack verification failed", func() {
|
|
// set ordered to true resulting in wrong proof provided
|
|
ordered = true
|
|
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), disabledTimeoutTimestamp)
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
}, false},
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
tc := tc
|
|
suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() {
|
|
var (
|
|
proof []byte
|
|
proofHeight uint64
|
|
)
|
|
|
|
suite.SetupTest() // reset
|
|
nextSeqRecv = 1 // must be explicitly changed
|
|
tc.malleate()
|
|
|
|
orderedPacketKey := host.KeyNextSequenceRecv(packet.GetDestPort(), packet.GetDestChannel())
|
|
unorderedPacketKey := host.KeyPacketAcknowledgement(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
|
|
|
|
if ordered {
|
|
proof, proofHeight = suite.chainB.QueryProof(orderedPacketKey)
|
|
} else {
|
|
proof, proofHeight = suite.chainB.QueryProof(unorderedPacketKey)
|
|
}
|
|
|
|
err := suite.chainA.App.IBCKeeper.ChannelKeeper.TimeoutPacket(suite.chainA.GetContext(), packet, proof, proofHeight, nextSeqRecv)
|
|
|
|
if tc.expPass {
|
|
suite.Require().NoError(err)
|
|
} else {
|
|
suite.Require().Error(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestTimeoutExectued verifies that packet commitments are deleted on chainA after the
|
|
// channel capabilities are verified.
|
|
func (suite *KeeperTestSuite) TestTimeoutExecuted() {
|
|
var (
|
|
packet types.Packet
|
|
chanCap *capabilitytypes.Capability
|
|
)
|
|
|
|
testCases := []testCase{
|
|
{"success ORDERED", func() {
|
|
_, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, true},
|
|
{"channel not found", func() {
|
|
// use wrong channel naming
|
|
_, _, _, _, _, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
|
|
}, false},
|
|
{"incorrect capability", func() {
|
|
_, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
|
|
chanCap = capabilitytypes.NewCapability(100)
|
|
}, false},
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
tc := tc
|
|
suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() {
|
|
suite.SetupTest() // reset
|
|
|
|
tc.malleate()
|
|
|
|
err := suite.chainA.App.IBCKeeper.ChannelKeeper.TimeoutExecuted(suite.chainA.GetContext(), chanCap, packet)
|
|
pc := suite.chainA.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(suite.chainA.GetContext(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())
|
|
|
|
if tc.expPass {
|
|
suite.NoError(err)
|
|
suite.Nil(pc)
|
|
} else {
|
|
suite.Error(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestTimeoutOnClose tests the call TimeoutOnClose on chainA by closing the corresponding
|
|
// channel on chainB after the packet commitment has been created.
|
|
func (suite *KeeperTestSuite) TestTimeoutOnClose() {
|
|
var (
|
|
packet types.Packet
|
|
chanCap *capabilitytypes.Capability
|
|
nextSeqRecv uint64
|
|
ordered bool
|
|
)
|
|
|
|
testCases := []testCase{
|
|
{"success: ORDERED", func() {
|
|
ordered = true
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
|
|
// need to update chainA's client representing chainB to prove missing ack
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, true},
|
|
{"success: UNORDERED", func() {
|
|
ordered = false
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), disabledTimeoutTimestamp)
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
|
|
// need to update chainA's client representing chainB to prove missing ack
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, true},
|
|
{"channel not found", func() {
|
|
// use wrong channel naming
|
|
_, _, _, _, _, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
|
|
}, false},
|
|
{"packet dest port ≠ channel counterparty port", func() {
|
|
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
// use wrong port for dest
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, ibctesting.InvalidID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, false},
|
|
{"packet dest channel ID ≠ channel counterparty channel ID", func() {
|
|
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
// use wrong channel for dest
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, ibctesting.InvalidID, timeoutHeight, disabledTimeoutTimestamp)
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, false},
|
|
{"connection not found", func() {
|
|
channelA := ibctesting.TestChannel{PortID: portID, ID: channelIDA}
|
|
channelB := ibctesting.TestChannel{PortID: portID, ID: channelIDB}
|
|
// pass channel check
|
|
suite.chainA.App.IBCKeeper.ChannelKeeper.SetChannel(
|
|
suite.chainA.GetContext(),
|
|
channelA.PortID, channelA.ID,
|
|
types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(channelB.PortID, channelB.ID), []string{connIDA}, channelA.Version),
|
|
)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, timeoutHeight, disabledTimeoutTimestamp)
|
|
|
|
// create chancap
|
|
suite.chainA.CreateChannelCapability(channelA.PortID, channelA.ID)
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, false},
|
|
{"packet hasn't been sent", func() {
|
|
_, _, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, false},
|
|
{"packet already received", func() {
|
|
nextSeqRecv = 2
|
|
ordered = true
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
|
|
// need to update chainA's client representing chainB to prove missing ack
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, false},
|
|
{"channel verification failed", func() {
|
|
ordered = true
|
|
_, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, false},
|
|
{"next seq receive verification failed", func() {
|
|
// set ordered to false providing the wrong proof for ORDERED case
|
|
ordered = false
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, false},
|
|
{"packet ack verification failed", func() {
|
|
// set ordered to true providing the wrong proof for UNORDERED case
|
|
ordered = true
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.UNORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), disabledTimeoutTimestamp)
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
chanCap = suite.chainA.GetChannelCapability(channelA.PortID, channelA.ID)
|
|
}, false},
|
|
{"channel capability not found", func() {
|
|
ordered = true
|
|
clientA, clientB, _, _, channelA, channelB := suite.coordinator.Setup(suite.chainA, suite.chainB, types.ORDERED)
|
|
packet = types.NewPacket(validPacketData, 1, channelA.PortID, channelA.ID, channelB.PortID, channelB.ID, uint64(suite.chainB.GetContext().BlockHeight()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
|
|
suite.coordinator.SendPacket(suite.chainA, suite.chainB, packet, clientB)
|
|
suite.coordinator.SetChannelClosed(suite.chainB, suite.chainA, channelB)
|
|
// need to update chainA's client representing chainB to prove missing ack
|
|
suite.coordinator.UpdateClient(suite.chainA, suite.chainB, clientA, exported.Tendermint)
|
|
|
|
chanCap = capabilitytypes.NewCapability(100)
|
|
}, false},
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
tc := tc
|
|
suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() {
|
|
var proof []byte
|
|
|
|
suite.SetupTest() // reset
|
|
nextSeqRecv = 1 // must be explicitly changed
|
|
tc.malleate()
|
|
|
|
channelKey := host.KeyChannel(packet.GetDestPort(), packet.GetDestChannel())
|
|
unorderedPacketKey := host.KeyPacketAcknowledgement(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())
|
|
orderedPacketKey := host.KeyNextSequenceRecv(packet.GetDestPort(), packet.GetDestChannel())
|
|
|
|
proofClosed, proofHeight := suite.chainB.QueryProof(channelKey)
|
|
|
|
if ordered {
|
|
proof, _ = suite.chainB.QueryProof(orderedPacketKey)
|
|
} else {
|
|
proof, _ = suite.chainB.QueryProof(unorderedPacketKey)
|
|
}
|
|
|
|
err := suite.chainA.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(suite.chainA.GetContext(), chanCap, packet, proof, proofClosed, proofHeight, nextSeqRecv)
|
|
|
|
if tc.expPass {
|
|
suite.Require().NoError(err)
|
|
} else {
|
|
suite.Require().Error(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
}
|