Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add helper functions for MsgSendPacket, MsgRecvPacket and MsgAcknowledgePacket #7465

Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 37 additions & 75 deletions modules/core/04-channel/v2/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
channeltypesv1 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/types"
channeltypesv2 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types"
commitmenttypes "github.com/cosmos/ibc-go/v9/modules/core/23-commitment/types"
hostv2 "github.com/cosmos/ibc-go/v9/modules/core/24-host/v2"
ibcerrors "github.com/cosmos/ibc-go/v9/modules/core/errors"
ibctesting "github.com/cosmos/ibc-go/v9/testing"
"github.com/cosmos/ibc-go/v9/testing/mock"
Expand All @@ -20,9 +19,10 @@ import (

func (suite *KeeperTestSuite) TestMsgSendPacket() {
var (
path *ibctesting.Path
msg *channeltypesv2.MsgSendPacket
expectedPacket channeltypesv2.Packet
path *ibctesting.Path
expectedPacket channeltypesv2.Packet
timeoutTimestamp uint64
packetData channeltypesv2.PacketData
)

testCases := []struct {
Expand All @@ -39,7 +39,7 @@ func (suite *KeeperTestSuite) TestMsgSendPacket() {
name: "failure: timeout elapsed",
malleate: func() {
// ensure a message timeout.
msg.TimeoutTimestamp = uint64(1)
timeoutTimestamp = uint64(1)
},
expError: channeltypesv1.ErrTimeoutElapsed,
},
Expand All @@ -62,14 +62,14 @@ func (suite *KeeperTestSuite) TestMsgSendPacket() {
{
name: "failure: counterparty not found",
malleate: func() {
msg.SourceChannel = "foo"
path.EndpointA.ChannelID = "foo"
},
expError: channeltypesv1.ErrChannelNotFound,
},
{
name: "failure: route to non existing app",
malleate: func() {
msg.PacketData[0].SourcePort = "foo"
packetData.SourcePort = "foo"
},
expError: fmt.Errorf("no route for foo"),
},
Expand All @@ -84,19 +84,19 @@ func (suite *KeeperTestSuite) TestMsgSendPacket() {
path = ibctesting.NewPath(suite.chainA, suite.chainB)
path.SetupV2()

timeoutTimestamp := suite.chainA.GetTimeoutTimestamp()
msg = channeltypesv2.NewMsgSendPacket(path.EndpointA.ChannelID, timeoutTimestamp, suite.chainA.SenderAccount.GetAddress().String(), mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB))
timeoutTimestamp = suite.chainA.GetTimeoutTimestamp()
packetData = mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB)

expectedPacket = channeltypesv2.NewPacket(1, path.EndpointA.ChannelID, path.EndpointB.ChannelID, timeoutTimestamp, mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB))
expectedPacket = channeltypesv2.NewPacket(1, path.EndpointA.ChannelID, path.EndpointB.ChannelID, timeoutTimestamp, packetData)

tc.malleate()

res, err := path.EndpointA.Chain.SendMsgs(msg)
packet, err := path.EndpointA.MsgSendPacket(timeoutTimestamp, packetData)

expPass := tc.expError == nil
if expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().NotEmpty(packet)

ck := path.EndpointA.Chain.GetSimApp().IBCKeeper.ChannelKeeperV2

Expand All @@ -108,6 +108,8 @@ func (suite *KeeperTestSuite) TestMsgSendPacket() {
suite.Require().True(ok)
suite.Require().Equal(uint64(2), nextSequenceSend, "next sequence send was not incremented correctly")

suite.Require().Equal(expectedPacket, packet)

} else {
suite.Require().Error(err)
ibctesting.RequireErrorIsOrContains(suite.T(), err, tc.expError)
Expand All @@ -119,8 +121,7 @@ func (suite *KeeperTestSuite) TestMsgSendPacket() {
func (suite *KeeperTestSuite) TestMsgRecvPacket() {
var (
path *ibctesting.Path
msg *channeltypesv2.MsgRecvPacket
recvPacket channeltypesv2.Packet
packet channeltypesv2.Packet
expectedAck channeltypesv2.Acknowledgement
)

Expand Down Expand Up @@ -169,23 +170,23 @@ func (suite *KeeperTestSuite) TestMsgRecvPacket() {
{
name: "success: NoOp",
malleate: func() {
suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.SetPacketReceipt(suite.chainB.GetContext(), recvPacket.SourceChannel, recvPacket.Sequence)
suite.chainB.App.GetIBCKeeper().ChannelKeeperV2.SetPacketReceipt(suite.chainB.GetContext(), packet.SourceChannel, packet.Sequence)
expectedAck = channeltypesv2.Acknowledgement{}
},
},
{
name: "failure: counterparty not found",
malleate: func() {
// change the destination id to a non-existent channel.
recvPacket.DestinationChannel = "not-existent-channel"
packet.DestinationChannel = "not-existent-channel"
},
expError: channeltypesv2.ErrChannelNotFound,
},
{
name: "failure: invalid proof",
malleate: func() {
// proof verification fails because the packet commitment is different due to a different sequence.
recvPacket.Sequence = 10
packet.Sequence = 10
},
expError: commitmenttypes.ErrInvalidProof,
},
Expand All @@ -201,15 +202,10 @@ func (suite *KeeperTestSuite) TestMsgRecvPacket() {
path.SetupV2()

timeoutTimestamp := suite.chainA.GetTimeoutTimestamp()
msgSendPacket := channeltypesv2.NewMsgSendPacket(path.EndpointA.ChannelID, timeoutTimestamp, suite.chainA.SenderAccount.GetAddress().String(), mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB))

res, err := path.EndpointA.Chain.SendMsgs(msgSendPacket)
var err error
packet, err = path.EndpointA.MsgSendPacket(timeoutTimestamp, mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB))
suite.Require().NoError(err)
suite.Require().NotNil(res)

suite.Require().NoError(path.EndpointB.UpdateClient())

recvPacket = channeltypesv2.NewPacket(1, path.EndpointA.ChannelID, path.EndpointB.ChannelID, timeoutTimestamp, mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB))

// default expected ack is a single successful recv result for moduleB.
expectedAck = channeltypesv2.Acknowledgement{
Expand All @@ -226,27 +222,19 @@ func (suite *KeeperTestSuite) TestMsgRecvPacket() {

tc.malleate()

// get proof of packet commitment from chainA
packetKey := hostv2.PacketCommitmentKey(recvPacket.SourceChannel, recvPacket.Sequence)
proof, proofHeight := path.EndpointA.QueryProof(packetKey)

msg = channeltypesv2.NewMsgRecvPacket(recvPacket, proof, proofHeight, suite.chainB.SenderAccount.GetAddress().String())

res, err = path.EndpointB.Chain.SendMsgs(msg)
suite.Require().NoError(path.EndpointA.UpdateClient())
err = path.EndpointB.MsgRecvPacket(packet)

ck := path.EndpointB.Chain.GetSimApp().IBCKeeper.ChannelKeeperV2

expPass := tc.expError == nil
if expPass {
suite.Require().NoError(err)
suite.Require().NotNil(res)

// packet receipt should be written
_, ok := ck.GetPacketReceipt(path.EndpointB.Chain.GetContext(), recvPacket.SourceChannel, recvPacket.Sequence)
_, ok := ck.GetPacketReceipt(path.EndpointB.Chain.GetContext(), packet.SourceChannel, packet.Sequence)
suite.Require().True(ok)

ackWritten := ck.HasPacketAcknowledgement(path.EndpointB.Chain.GetContext(), recvPacket.DestinationChannel, recvPacket.Sequence)
ackWritten := ck.HasPacketAcknowledgement(path.EndpointB.Chain.GetContext(), packet.DestinationChannel, packet.Sequence)

if len(expectedAck.AcknowledgementResults) == 0 || expectedAck.AcknowledgementResults[0].RecvPacketResult.Status == channeltypesv2.PacketStatus_Async {
// ack should not be written for async app or if the packet receipt was already present.
Expand All @@ -256,13 +244,13 @@ func (suite *KeeperTestSuite) TestMsgRecvPacket() {
suite.Require().True(ackWritten)
expectedBz := channeltypesv2.CommitAcknowledgement(expectedAck)

actualAckBz := ck.GetPacketAcknowledgement(path.EndpointB.Chain.GetContext(), recvPacket.DestinationChannel, recvPacket.Sequence)
actualAckBz := ck.GetPacketAcknowledgement(path.EndpointB.Chain.GetContext(), packet.DestinationChannel, packet.Sequence)
suite.Require().Equal(expectedBz, actualAckBz)
}

} else {
ibctesting.RequireErrorIsOrContains(suite.T(), err, tc.expError)
_, ok := ck.GetPacketReceipt(path.EndpointB.Chain.GetContext(), recvPacket.SourceChannel, recvPacket.Sequence)
_, ok := ck.GetPacketReceipt(path.EndpointB.Chain.GetContext(), packet.SourceChannel, packet.Sequence)
suite.Require().False(ok)
}
})
Expand Down Expand Up @@ -344,9 +332,9 @@ func (suite *KeeperTestSuite) TestProvideCounterparty() {

func (suite *KeeperTestSuite) TestMsgAcknowledgement() {
var (
path *ibctesting.Path
msgAckPacket *channeltypesv2.MsgAcknowledgement
recvPacket channeltypesv2.Packet
path *ibctesting.Path
packet channeltypesv2.Packet
ack channeltypesv2.Acknowledgement
)
testCases := []struct {
name string
Expand All @@ -360,7 +348,7 @@ func (suite *KeeperTestSuite) TestMsgAcknowledgement() {
{
name: "success: NoOp",
malleate: func() {
suite.chainA.App.GetIBCKeeper().ChannelKeeperV2.SetPacketCommitment(suite.chainA.GetContext(), recvPacket.SourceChannel, recvPacket.Sequence, []byte{})
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.
Expand All @@ -369,13 +357,6 @@ func (suite *KeeperTestSuite) TestMsgAcknowledgement() {
}
},
},
{
name: "failure: invalid signer",
malleate: func() {
msgAckPacket.Signer = ""
},
expError: errors.New("empty address string is not allowed"),
},
{
name: "failure: callback fails",
malleate: func() {
Expand All @@ -389,21 +370,21 @@ func (suite *KeeperTestSuite) TestMsgAcknowledgement() {
name: "failure: counterparty not found",
malleate: func() {
// change the source id to a non-existent channel.
msgAckPacket.Packet.SourceChannel = "not-existent-channel"
packet.SourceChannel = "not-existent-channel"
},
expError: channeltypesv2.ErrChannelNotFound,
},
{
name: "failure: invalid commitment",
malleate: func() {
suite.chainA.App.GetIBCKeeper().ChannelKeeperV2.SetPacketCommitment(suite.chainA.GetContext(), recvPacket.SourceChannel, recvPacket.Sequence, []byte("foo"))
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() {
msgAckPacket.ProofHeight = clienttypes.ZeroHeight()
ack.AcknowledgementResults[0].RecvPacketResult.Acknowledgement = mock.MockFailPacketData
},
expError: errors.New("failed packet acknowledgement verification"),
},
Expand All @@ -417,28 +398,16 @@ func (suite *KeeperTestSuite) TestMsgAcknowledgement() {

timeoutTimestamp := suite.chainA.GetTimeoutTimestamp()

var err error
// Send packet from A to B
msgSendPacket := channeltypesv2.NewMsgSendPacket(path.EndpointA.ChannelID, timeoutTimestamp, suite.chainA.SenderAccount.GetAddress().String(), mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB))
res, err := path.EndpointA.Chain.SendMsgs(msgSendPacket)
packet, err = path.EndpointA.MsgSendPacket(timeoutTimestamp, mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB))
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().NoError(path.EndpointB.UpdateClient())

// Receive packet on B
recvPacket = channeltypesv2.NewPacket(1, path.EndpointA.ChannelID, path.EndpointB.ChannelID, timeoutTimestamp, mockv2.NewMockPacketData(mockv2.ModuleNameA, mockv2.ModuleNameB))
// get proof of packet commitment from chainA
packetKey := hostv2.PacketCommitmentKey(recvPacket.SourceChannel, recvPacket.Sequence)
proof, proofHeight := path.EndpointA.QueryProof(packetKey)

// Construct msgRecvPacket to be sent to B
msgRecvPacket := channeltypesv2.NewMsgRecvPacket(recvPacket, proof, proofHeight, suite.chainB.SenderAccount.GetAddress().String())
res, err = suite.chainB.SendMsgs(msgRecvPacket)
err = path.EndpointB.MsgRecvPacket(packet)
suite.Require().NoError(err)
suite.Require().NotNil(res)
suite.Require().NoError(path.EndpointA.UpdateClient())

// Construct expected acknowledgement
ack := channeltypesv2.Acknowledgement{
ack = channeltypesv2.Acknowledgement{
AcknowledgementResults: []channeltypesv2.AcknowledgementResult{
{
AppName: mockv2.ModuleNameB,
Expand All @@ -450,21 +419,14 @@ func (suite *KeeperTestSuite) TestMsgAcknowledgement() {
},
}

// Consttruct MsgAcknowledgement
packetKey = hostv2.PacketAcknowledgementKey(recvPacket.DestinationChannel, recvPacket.Sequence)
proof, proofHeight = path.EndpointB.QueryProof(packetKey)
msgAckPacket = channeltypesv2.NewMsgAcknowledgement(recvPacket, ack, proof, proofHeight, suite.chainA.SenderAccount.GetAddress().String())

tc.malleate()

// Finally, acknowledge the packet on A
res, err = suite.chainA.SendMsgs(msgAckPacket)
err = path.EndpointA.MsgAcknowledgePacket(packet, ack)

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)
}
Expand Down
56 changes: 56 additions & 0 deletions testing/endpoint_v2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package ibctesting

import (
"github.com/stretchr/testify/require"

channeltypesv2 "github.com/cosmos/ibc-go/v9/modules/core/04-channel/v2/types"
hostv2 "github.com/cosmos/ibc-go/v9/modules/core/24-host/v2"
)

// MsgSendPacket sends a packet on the associated endpoint. The constructed packet is returned.
func (endpoint *Endpoint) MsgSendPacket(timeoutTimestamp uint64, packetData channeltypesv2.PacketData) (channeltypesv2.Packet, error) {
msgSendPacket := channeltypesv2.NewMsgSendPacket(endpoint.ChannelID, timeoutTimestamp, endpoint.Chain.SenderAccount.GetAddress().String(), packetData)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how come you didn't allow chan id as arg? No strong opinions i think, mostly curious.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

figured we can just modify endpoint.ChannelID if we need to in a malleate fn


_, err := endpoint.Chain.SendMsgs(msgSendPacket)
if err != nil {
return channeltypesv2.Packet{}, err
}

if err := endpoint.Counterparty.UpdateClient(); err != nil {
return channeltypesv2.Packet{}, err
}

// TODO: parse the packet from events instead of manually constructing it. https://github.com/cosmos/ibc-go/issues/7459
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#7459 linkerino

nextSequenceSend, ok := endpoint.Chain.GetSimApp().IBCKeeper.ChannelKeeperV2.GetNextSequenceSend(endpoint.Chain.GetContext(), endpoint.ChannelID)
require.True(endpoint.Chain.TB, ok)
packet := channeltypesv2.NewPacket(nextSequenceSend-1, endpoint.ChannelID, endpoint.Counterparty.ChannelID, timeoutTimestamp, packetData)

return packet, nil
}

// MsgRecvPacket sends a MsgRecvPacket on the associated endpoint with the provided packet.
func (endpoint *Endpoint) MsgRecvPacket(packet channeltypesv2.Packet) error {
// get proof of packet commitment from chainA
packetKey := hostv2.PacketCommitmentKey(packet.SourceChannel, packet.Sequence)
proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey)

msg := channeltypesv2.NewMsgRecvPacket(packet, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String())

if err := endpoint.Chain.sendMsgs(msg); err != nil {
return err
}

return endpoint.Counterparty.UpdateClient()
}

// MsgAcknowledgePacket sends a MsgAcknowledgement on the associated endpoint with the provided packet and ack.
func (endpoint *Endpoint) MsgAcknowledgePacket(packet channeltypesv2.Packet, ack channeltypesv2.Acknowledgement) error {
packetKey := hostv2.PacketAcknowledgementKey(packet.DestinationChannel, packet.Sequence)
proof, proofHeight := endpoint.Counterparty.QueryProof(packetKey)
msg := channeltypesv2.NewMsgAcknowledgement(packet, ack, proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String())
if err := endpoint.Chain.sendMsgs(msg); err != nil {
return err
}
chatton marked this conversation as resolved.
Show resolved Hide resolved

return endpoint.Counterparty.UpdateClient()
}
Loading