From 7f1c54e4699f9e7c243b1cef8ae8308489fb5ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Thu, 10 Feb 2022 14:08:06 +0100 Subject: [PATCH 1/2] begin writing transfer test for ics29 --- modules/apps/29-fee/transfer_test.go | 51 +++++++++++++++++++++++ testing/events.go | 60 ++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 modules/apps/29-fee/transfer_test.go diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go new file mode 100644 index 00000000000..3498a537e30 --- /dev/null +++ b/modules/apps/29-fee/transfer_test.go @@ -0,0 +1,51 @@ +package fee_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/v3/modules/apps/29-fee/types" + transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" + ibctesting "github.com/cosmos/ibc-go/v3/testing" +) + +// Integration test to ensure ics29 works with ics20 +func (suite *FeeTestSuite) TestFeeTransfer() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + feeTransferVersion := string(types.ModuleCdc.MustMarshalJSON(&types.Metadata{FeeVersion: types.Version, AppVersion: transfertypes.Version})) + path.EndpointA.ChannelConfig.Version = feeTransferVersion + path.EndpointB.ChannelConfig.Version = feeTransferVersion + path.EndpointA.ChannelConfig.PortID = transfertypes.PortID + path.EndpointB.ChannelConfig.PortID = transfertypes.PortID + + suite.coordinator.Setup(path) + + // set up coin & ics20 packet + coin := ibctesting.TestCoin + fee := types.Fee{ + RecvFee: validCoins, + AckFee: validCoins2, + TimeoutFee: validCoins3, + } + + msgs := []sdk.Msg{ + types.NewMsgPayPacketFee(fee, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, suite.chainA.SenderAccount.GetAddress().String(), nil), + transfertypes.NewMsgTransfer(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, coin, suite.chainA.SenderAccount.GetAddress().String(), suite.chainB.SenderAccount.GetAddress().String(), clienttypes.NewHeight(0, 100), 0), + } + res, err := suite.chainA.SendMsgs(msgs...) + suite.Require().NoError(err) // message committed + + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) + suite.Require().NoError(err) + + // register counterparty address on chainB + // msgRegister := types.NewMsgRegisterCounterpartyAddress(addr, counterpartyAddr) + // _, err = suite.chainA.SendMsgs(msgRegister) + // suite.Require().NoError(err) // message committed + + // relay packet + err = path.RelayPacket(packet) + suite.Require().NoError(err) // relay committed + + // ensure relayers got paid +} diff --git a/testing/events.go b/testing/events.go index 037a4c342e3..7828b42619f 100644 --- a/testing/events.go +++ b/testing/events.go @@ -2,6 +2,7 @@ package ibctesting import ( "fmt" + "strconv" sdk "github.com/cosmos/cosmos-sdk/types" @@ -56,6 +57,65 @@ func ParseChannelIDFromEvents(events sdk.Events) (string, error) { return "", fmt.Errorf("channel identifier event attribute not found") } +// ParsePacketFromEvents parses events emitted from a MsgRecvPacket and returns the +// acknowledgement. +func ParsePacketFromEvents(events sdk.Events) (channeltypes.Packet, error) { + for _, ev := range events { + if ev.Type == channeltypes.EventTypeSendPacket { + packet := channeltypes.Packet{} + for _, attr := range ev.Attributes { + + switch string(attr.Key) { + case channeltypes.AttributeKeyData: + packet.Data = attr.Value + + case channeltypes.AttributeKeySequence: + seq, err := strconv.ParseUint(string(attr.Value), 10, 64) + if err != nil { + return channeltypes.Packet{}, err + } + + packet.Sequence = seq + + case channeltypes.AttributeKeySrcPort: + packet.SourcePort = string(attr.Value) + + case channeltypes.AttributeKeySrcChannel: + packet.SourceChannel = string(attr.Value) + + case channeltypes.AttributeKeyDstPort: + packet.DestinationPort = string(attr.Value) + + case channeltypes.AttributeKeyDstChannel: + packet.DestinationChannel = string(attr.Value) + + case channeltypes.AttributeKeyTimeoutHeight: + height, err := clienttypes.ParseHeight(string(attr.Value)) + if err != nil { + return channeltypes.Packet{}, err + } + + packet.TimeoutHeight = height + + case channeltypes.AttributeKeyTimeoutTimestamp: + timestamp, err := strconv.ParseUint(string(attr.Value), 10, 64) + if err != nil { + return channeltypes.Packet{}, err + } + + packet.TimeoutTimestamp = timestamp + + default: + continue + } + } + + return packet, nil + } + } + return channeltypes.Packet{}, fmt.Errorf("acknowledgement event attribute not found") +} + // ParseAckFromEvents parses events emitted from a MsgRecvPacket and returns the // acknowledgement. func ParseAckFromEvents(events sdk.Events) ([]byte, error) { From 54bdca52eb61e3949ed6c54206222ed8a5844830 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 15 Feb 2022 13:19:06 +0100 Subject: [PATCH 2/2] finish writing transfer test --- modules/apps/29-fee/transfer_test.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/modules/apps/29-fee/transfer_test.go b/modules/apps/29-fee/transfer_test.go index 3498a537e30..863b728d45f 100644 --- a/modules/apps/29-fee/transfer_test.go +++ b/modules/apps/29-fee/transfer_test.go @@ -35,17 +35,38 @@ func (suite *FeeTestSuite) TestFeeTransfer() { res, err := suite.chainA.SendMsgs(msgs...) suite.Require().NoError(err) // message committed + // after incentivizing the packets + originalChainASenderAccountBalance := sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)) + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) suite.Require().NoError(err) // register counterparty address on chainB - // msgRegister := types.NewMsgRegisterCounterpartyAddress(addr, counterpartyAddr) - // _, err = suite.chainA.SendMsgs(msgRegister) - // suite.Require().NoError(err) // message committed + // relayerAddress is address of sender account on chainB, but we will use it on chainA + // to differentiate from the chainA.SenderAccount for checking successful relay payouts + relayerAddress := suite.chainB.SenderAccount.GetAddress() + + msgRegister := types.NewMsgRegisterCounterpartyAddress(suite.chainB.SenderAccount.GetAddress().String(), relayerAddress.String()) + _, err = suite.chainB.SendMsgs(msgRegister) + suite.Require().NoError(err) // message committed // relay packet err = path.RelayPacket(packet) suite.Require().NoError(err) // relay committed // ensure relayers got paid + // relayer for forward relay: chainB.SenderAccount + // relayer for reverse relay: chainA.SenderAccount + + // check forward relay balance + suite.Require().Equal( + fee.RecvFee, + sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainB.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)), + ) + + suite.Require().Equal( + fee.AckFee.Add(fee.TimeoutFee...), // ack fee paid, timeout fee refunded + sdk.NewCoins(suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), suite.chainA.SenderAccount.GetAddress(), ibctesting.TestCoin.Denom)).Sub(originalChainASenderAccountBalance), + ) + }