Skip to content

Commit

Permalink
add multihop timeout test and logic
Browse files Browse the repository at this point in the history
  • Loading branch information
dshiell committed Jan 12, 2023
1 parent e9365de commit 8ed6ba2
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 265 deletions.
260 changes: 24 additions & 236 deletions modules/core/04-channel/keeper/multihop_timeout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import (
"errors"
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"

clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
"github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
Expand All @@ -14,186 +14,36 @@ import (
ibctesting "github.com/cosmos/ibc-go/v6/testing"
)

type timeoutTestCase = struct {
msg string
orderedChannel bool
malleate func()
expPass bool
}

// 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 *MultihopTestSuite) TestTimeoutPacket() {
var (
//path *ibctesting.Path
packet *types.Packet
nextSeqRecv uint64
ordered bool
err error
expError *sdkerrors.Error
)

testCases := []testCase{
{"success: ORDERED", func() {
ordered = true
suite.chanPath.SetChannelOrdered()
//path.SetChannelOrdered()
//suite.coordinator.Setup(path)

testCases := []timeoutTestCase{
{"success: ORDERED", true, func() {
timeoutHeight := clienttypes.GetSelfHeight(suite.Z().Chain.GetContext())
timeoutTimestamp := uint64(suite.Z().Chain.GetContext().BlockTime().UnixNano())

//sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData)
packet, err = suite.A().SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData)
suite.Require().NoError(err)
// packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp)
// need to update chainA's client representing chainB to prove missing ack
// path.EndpointA.UpdateClient()
}, true},
{"success: UNORDERED", func() {
ordered = false
{"success: UNORDERED", false, func() {
timeoutHeight := clienttypes.GetSelfHeight(suite.Z().Chain.GetContext())

// sequence, err := path.EndpointA.SendPacket(timeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData)
packet, err = suite.A().SendPacket(timeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData)
suite.Require().NoError(err)
// packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp)
// need to update chainA's client representing chainB to prove missing ack
// path.EndpointA.UpdateClient()
}, true},
// {"packet already timed out: ORDERED", func() {
// expError = types.ErrNoOpMsg
// ordered = true
// path.SetChannelOrdered()
// suite.coordinator.Setup(path)

// timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext())
// timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano())

// sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData)
// suite.Require().NoError(err)
// // need to update chainA's client representing chainB to prove missing ack
// path.EndpointA.UpdateClient()

// packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp)
// err = path.EndpointA.TimeoutPacket(packet)
// suite.Require().NoError(err)
// }, false},
// {"packet already timed out: UNORDERED", func() {
// expError = types.ErrNoOpMsg
// ordered = false
// suite.coordinator.Setup(path)

// timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext())

// sequence, err := path.EndpointA.SendPacket(timeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData)
// suite.Require().NoError(err)
// // need to update chainA's client representing chainB to prove missing ack
// path.EndpointA.UpdateClient()

// packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp)
// err = path.EndpointA.TimeoutPacket(packet)
// suite.Require().NoError(err)
// }, false},
// {"channel not found", func() {
// expError = types.ErrChannelNotFound
// // use wrong channel naming
// suite.coordinator.Setup(path)
// packet = types.NewPacket(ibctesting.MockPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp)
// }, false},
// {"channel not open", func() {
// expError = types.ErrInvalidChannelState
// suite.coordinator.Setup(path)

// timeoutHeight := path.EndpointA.GetClientState().GetLatestHeight().Increment().(clienttypes.Height)

// sequence, err := path.EndpointA.SendPacket(timeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData)
// suite.Require().NoError(err)
// packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp)
// // need to update chainA's client representing chainB to prove missing ack
// path.EndpointA.UpdateClient()

// err = path.EndpointA.SetChannelClosed()
// suite.Require().NoError(err)
// }, false},
// {"packet destination port ≠ channel counterparty port", func() {
// expError = types.ErrInvalidPacket
// suite.coordinator.Setup(path)
// // use wrong port for dest
// packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, ibctesting.InvalidID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp)
// }, false},
// {"packet destination channel ID ≠ channel counterparty channel ID", func() {
// expError = types.ErrInvalidPacket
// suite.coordinator.Setup(path)
// // use wrong channel for dest
// packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, ibctesting.InvalidID, defaultTimeoutHeight, disabledTimeoutTimestamp)
// }, false},
// {"connection not found", func() {
// expError = connectiontypes.ErrConnectionNotFound
// // pass channel check
// suite.chainA.App.GetIBCKeeper().ChannelKeeper.SetChannel(
// suite.chainA.GetContext(),
// path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID,
// types.NewChannel(types.OPEN, types.ORDERED, types.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID), []string{connIDA}, path.EndpointA.ChannelConfig.Version),
// )
// packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp)
// }, false},
// {"timeout", func() {
// expError = types.ErrPacketTimeout
// suite.coordinator.Setup(path)
// sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData)
// suite.Require().NoError(err)
// packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp)
// path.EndpointA.UpdateClient()
// }, false},
// {"packet already received ", func() {
// expError = types.ErrPacketReceived
// ordered = true
// path.SetChannelOrdered()
// suite.coordinator.Setup(path)

// nextSeqRecv = 2
// timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano())

// sequence, err := path.EndpointA.SendPacket(defaultTimeoutHeight, timeoutTimestamp, ibctesting.MockPacketData)
// suite.Require().NoError(err)
// packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, timeoutTimestamp)
// path.EndpointA.UpdateClient()
// }, false},
// {"packet hasn't been sent", func() {
// expError = types.ErrNoOpMsg
// ordered = true
// path.SetChannelOrdered()

// suite.coordinator.Setup(path)
// packet = types.NewPacket(ibctesting.MockPacketData, 1, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
// path.EndpointA.UpdateClient()
// }, false},
// {"next seq receive verification failed", func() {
// // skip error check, error occurs in light-clients

// // set ordered to false resulting in wrong proof provided
// ordered = false

// path.SetChannelOrdered()
// suite.coordinator.Setup(path)

// timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext())

// sequence, err := path.EndpointA.SendPacket(timeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData)
// suite.Require().NoError(err)
// packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp)
// path.EndpointA.UpdateClient()
// }, false},
// {"packet ack verification failed", func() {
// // skip error check, error occurs in light-clients

// // set ordered to true resulting in wrong proof provided
// ordered = true

// suite.coordinator.Setup(path)

// timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext())

// sequence, err := path.EndpointA.SendPacket(timeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData)
// suite.Require().NoError(err)
// packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp)
// path.EndpointA.UpdateClient()
// }, false},
}

for i, tc := range testCases {
Expand All @@ -204,23 +54,28 @@ func (suite *MultihopTestSuite) TestTimeoutPacket() {
proofHeight exported.Height
)

suite.SetupTest() // reset
suite.SetupTest() // reset
if tc.orderedChannel {
suite.chanPath.SetChannelOrdered()
}
expError = nil // must be expliticly changed by failed cases
nextSeqRecv = 1 // must be explicitly changed
suite.SetupChannels() // setup multihop channels
//path = ibctesting.NewPath(suite.chainA, suite.chainB)

tc.malleate()

orderedPacketKey := host.NextSequenceRecvKey(packet.GetDestPort(), packet.GetDestChannel())
unorderedPacketKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence())

if suite.Z().ConnectionID != "" {
if ordered {
proof, proofHeight = suite.Z().QueryProof(orderedPacketKey)
if tc.orderedChannel {
// proof of inclusion of next sequence number
key := host.NextSequenceRecvKey(packet.SourcePort, packet.SourceChannel)
val := sdk.Uint64ToBigEndian(nextSeqRecv)
proof = suite.Z().QueryMultihopProof(key, val, fmt.Sprintf("ordered packet timeout: %s", packet.String()))
} else {
proof, proofHeight = suite.Z().QueryProof(unorderedPacketKey)
// proof of absence of packet receipt
key := host.PacketReceiptKey(packet.SourcePort, packet.SourceChannel, packet.Sequence)
proof = suite.Z().QueryMultihopProof(key, []byte(nil), fmt.Sprintf("unordered packet timeout: %s", packet.String()))
}
proofHeight = suite.A().ProofHeight()
}

err := suite.A().Chain.App.GetIBCKeeper().ChannelKeeper.TimeoutPacket(suite.A().Chain.GetContext(), packet, proof, proofHeight, nextSeqRecv)
Expand All @@ -238,73 +93,6 @@ func (suite *MultihopTestSuite) TestTimeoutPacket() {
}
}

// TestTimeoutExectued verifies that packet commitments are deleted on chainA after the
// channel capabilities are verified.
func (suite *MultihopTestSuite) TestTimeoutExecuted() {
var (
path *ibctesting.Path
packet *types.Packet
chanCap *capabilitytypes.Capability
err error
)

testCases := []testCase{
{"success ORDERED", func() {
// path.SetChannelOrdered()
// suite.coordinator.Setup(path)
suite.chanPath.SetChannelOrdered()

timeoutHeight := clienttypes.GetSelfHeight(suite.Z().Chain.GetContext())
timeoutTimestamp := uint64(suite.Z().Chain.GetContext().BlockTime().UnixNano())

packet, err = suite.A().SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData)
suite.Require().NoError(err)

//packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp)
chanCap = suite.A().Chain.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
}, true},
// {"channel not found", func() {
// // use wrong channel naming
// //suite.coordinator.Setup(path)
// packet = types.NewPacket(ibctesting.MockPacketData, 1, ibctesting.InvalidID, ibctesting.InvalidID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, defaultTimeoutHeight, disabledTimeoutTimestamp)
// }, false},
// {"incorrect capability ORDERED", func() {
// path.SetChannelOrdered()
// suite.coordinator.Setup(path)

// timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext())
// timeoutTimestamp := uint64(suite.chainB.GetContext().BlockTime().UnixNano())

// sequence, err := path.EndpointA.SendPacket(timeoutHeight, timeoutTimestamp, ibctesting.MockPacketData)
// suite.Require().NoError(err)

// packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, timeoutTimestamp)
// 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
suite.SetupChannels() // setup multihop channels
//path = ibctesting.NewPath(suite.chainA, suite.chainB)

tc.malleate()

err := suite.A().Chain.App.GetIBCKeeper().ChannelKeeper.TimeoutExecuted(suite.A().Chain.GetContext(), chanCap, packet)
pc := suite.A().Chain.App.GetIBCKeeper().ChannelKeeper.GetPacketCommitment(suite.A().Chain.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() {
Expand Down
Loading

0 comments on commit 8ed6ba2

Please sign in to comment.