Skip to content

Commit

Permalink
msgTimeout test
Browse files Browse the repository at this point in the history
  • Loading branch information
bznein committed Oct 15, 2024
1 parent 063814c commit 9a91acb
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 12 deletions.
20 changes: 8 additions & 12 deletions modules/core/04-channel/v2/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func (k *Keeper) Timeout(ctx context.Context, timeout *channeltypesv2.MsgTimeout
sdkCtx := sdk.UnwrapSDKContext(ctx)
if err := k.timeoutPacket(ctx, timeout.Packet, timeout.ProofUnreceived, timeout.ProofHeight); err != nil {
sdkCtx.Logger().Error("Timeout packet failed", "source-channel", timeout.Packet.SourceChannel, "destination-channel", timeout.Packet.DestinationChannel, "error", errorsmod.Wrap(err, "timeout packet failed"))
return nil, errorsmod.Wrapf(err, "send packet failed for source id: %s and destination id: %s", timeout.Packet.SourceChannel, timeout.Packet.DestinationChannel)
return nil, errorsmod.Wrapf(err, "timeout packet failed for source id: %s and destination id: %s", timeout.Packet.SourceChannel, timeout.Packet.DestinationChannel)
}

signer, err := sdk.AccAddressFromBech32(timeout.Signer)
Expand All @@ -176,17 +176,13 @@ func (k *Keeper) Timeout(ctx context.Context, timeout *channeltypesv2.MsgTimeout
return nil, errorsmod.Wrap(err, "invalid address for msg Signer")
}

_ = signer

// TODO: implement once app router is wired up.
// https://github.com/cosmos/ibc-go/issues/7384
// for _, pd := range timeout.Packet.Data {
// cbs := k.PortKeeper.AppRouter.Route(pd.SourcePort)
// err := cbs.OnTimeoutPacket(timeout.Packet.SourceChannel, timeout.Packet.TimeoutTimestamp, signer)
// if err != nil {
// return err, err
// }
// }
for _, pd := range timeout.Packet.Data {
cbs := k.Router.Route(pd.SourcePort)
err := cbs.OnTimeoutPacket(ctx, timeout.Packet.SourceChannel, timeout.Packet.DestinationChannel, pd, signer)
if err != nil {
return nil, errorsmod.Wrapf(err, "failed OnTimeoutPacket for source port %s, source channel %s, destination channel %s", pd.SourcePort, timeout.Packet.SourceChannel, timeout.Packet.DestinationChannel)
}
}

return &channeltypesv2.MsgTimeoutResponse{Result: channeltypesv1.SUCCESS}, nil
}
Expand Down
110 changes: 110 additions & 0 deletions modules/core/04-channel/v2/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"

Expand Down Expand Up @@ -471,3 +472,112 @@ func (suite *KeeperTestSuite) TestMsgAcknowledgement() {
})
}
}

func (suite *KeeperTestSuite) TestMsgTimeout() {
var (
path *ibctesting.Path
msgTimeout *channeltypesv2.MsgTimeout
packet channeltypesv2.Packet
)

testCases := []struct {
name string
malleate func()
expError error
}{
{
name: "success",
malleate: func() {},
},
{
name: "failure: no-op",
malleate: func() {
suite.chainA.App.GetIBCKeeper().ChannelKeeperV2.SetPacketCommitment(suite.chainA.GetContext(), packet.SourceChannel, packet.Sequence, []byte{})

// Modify the callback to return an error.
// This way, we can verify that the callback is not executed in a No-op case.
path.EndpointA.Chain.GetSimApp().MockModuleV2A.IBCApp.OnTimeoutPacket = func(context.Context, string, string, channeltypesv2.PacketData, sdk.AccAddress) error {
return errors.New("OnAcknowledgementPacket callback failed")
}
},
expError: channeltypesv1.ErrNoOpMsg,
},
{
name: "failure: invalid signer",
malleate: func() {
msgTimeout.Signer = ""
},
expError: errors.New("empty address string is not allowed"),
},
{
name: "failure: callback fails",
malleate: func() {
path.EndpointA.Chain.GetSimApp().MockModuleV2A.IBCApp.OnTimeoutPacket = func(context.Context, string, string, channeltypesv2.PacketData, sdk.AccAddress) error {
return errors.New("OnTimeoutPacket callback failed")
}
},
expError: errors.New("OnTimeoutPacket callback failed"),
},
{
name: "failure: counterparty not found",
malleate: func() {
// change the source id to a non-existent channel.
msgTimeout.Packet.SourceChannel = "not-existent-channel"
},
expError: channeltypesv2.ErrChannelNotFound,
},
{
name: "failure: invalid commitment",
malleate: func() {
suite.chainA.App.GetIBCKeeper().ChannelKeeperV2.SetPacketCommitment(suite.chainA.GetContext(), packet.SourceChannel, packet.Sequence, []byte("foo"))
},
expError: channeltypesv2.ErrInvalidPacket,
},
{
name: "failure: failed membership verification",
malleate: func() {
msgTimeout.ProofHeight = clienttypes.ZeroHeight()
},
expError: clienttypes.ErrConsensusStateNotFound,
},
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
suite.SetupTest()

path = ibctesting.NewPath(suite.chainA, suite.chainB)
path.SetupV2()

// Send packet from A to B
timeoutTimestamp := suite.chainA.GetTimeoutTimestamp()

mockData := mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB)
msgSendPacket := channeltypesv2.NewMsgSendPacket(path.EndpointA.ChannelID, timeoutTimestamp, suite.chainA.SenderAccount.GetAddress().String(), mockData)
res, err := path.EndpointA.Chain.SendMsgs(msgSendPacket)
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().NoError(path.EndpointB.UpdateClient())

suite.coordinator.IncrementTimeBy(time.Hour * 20)
suite.Require().NoError(path.EndpointA.UpdateClient())

packet = channeltypesv2.NewPacket(1, path.EndpointA.ChannelID, path.EndpointB.ChannelID, timeoutTimestamp, mockData)

packetKey := hostv2.PacketReceiptKey(packet.DestinationChannel, packet.Sequence)
proof, proofHeight := path.EndpointB.QueryProof(packetKey)
msgTimeout = channeltypesv2.NewMsgTimeout(packet, proof, proofHeight, 1, suite.chainA.SenderAccount.GetAddress().String())

tc.malleate()

res, err = suite.chainA.SendMsgs(msgTimeout)

expPass := tc.expError == nil
if expPass {
suite.Require().NoError(err)
suite.NotNil(res)
} else {
ibctesting.RequireErrorIsOrContains(suite.T(), err, tc.expError, "expected error %q, got %q instead", tc.expError, err)
}
})
}
}
11 changes: 11 additions & 0 deletions modules/core/04-channel/v2/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,14 @@ func NewMsgAcknowledgement(packet Packet, acknowledgement Acknowledgement, proof
Signer: signer,
}
}

// NewMsgTimeout creates a new MsgTimeout instance
func NewMsgTimeout(packet Packet, proofUnreceived []byte, proofHeight clienttypes.Height, nextSequenceRecv uint64, signer string) *MsgTimeout {
return &MsgTimeout{
Packet: packet,
ProofUnreceived: proofUnreceived,
ProofHeight: proofHeight,
NextSequenceRecv: nextSequenceRecv,
Signer: signer,
}
}

0 comments on commit 9a91acb

Please sign in to comment.