Skip to content

Commit cc6fe55

Browse files
authored
Merge commit from fork
rm test case
1 parent ff0a82e commit cc6fe55

File tree

2 files changed

+293
-0
lines changed

2 files changed

+293
-0
lines changed

modules/apps/transfer/ibc_module.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package transfer
22

33
import (
4+
"bytes"
45
"fmt"
56
"math"
67
"strings"
78

9+
errorsmod "cosmossdk.io/errors"
10+
811
sdk "github.com/cosmos/cosmos-sdk/types"
912
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
1013
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
@@ -14,6 +17,7 @@ import (
1417
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
1518
porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types"
1619
host "github.com/cosmos/ibc-go/v7/modules/core/24-host"
20+
ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors"
1721
ibcexported "github.com/cosmos/ibc-go/v7/modules/core/exported"
1822
)
1923

@@ -184,6 +188,12 @@ func (im IBCModule) OnRecvPacket(
184188
ackErr = sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "cannot unmarshal ICS-20 transfer packet data")
185189
ack = channeltypes.NewErrorAcknowledgement(ackErr)
186190
}
191+
bz := data.GetBytes()
192+
if !bytes.Equal(bz, packet.GetData()) {
193+
ackErr = errorsmod.Wrapf(ibcerrors.ErrInvalidType, "packet data did not marshal to expected bytes: %X ≠ %X", bz, packet.GetData())
194+
ack = channeltypes.NewErrorAcknowledgement(ackErr)
195+
im.keeper.Logger(ctx).Error(fmt.Sprintf("%s sequence %d", ackErr.Error(), packet.Sequence))
196+
}
187197

188198
// only attempt the application logic if the packet data
189199
// was successfully decoded
@@ -236,6 +246,11 @@ func (im IBCModule) OnAcknowledgementPacket(
236246
return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "cannot unmarshal ICS-20 transfer packet data: %s", err.Error())
237247
}
238248

249+
bz := types.ModuleCdc.MustMarshalJSON(&ack)
250+
if !bytes.Equal(bz, acknowledgement) {
251+
return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "acknowledgement did not marshal to expected bytes: %X ≠ %X", bz, acknowledgement)
252+
}
253+
239254
if err := im.keeper.OnAcknowledgementPacket(ctx, packet, data, ack); err != nil {
240255
return err
241256
}

modules/apps/transfer/ibc_module_test.go

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
package transfer_test
22

33
import (
4+
"errors"
45
"math"
56

67
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
78
sdk "github.com/cosmos/cosmos-sdk/types"
9+
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
810
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
911

1012
"github.com/cosmos/ibc-go/v7/modules/apps/transfer"
1113
"github.com/cosmos/ibc-go/v7/modules/apps/transfer/types"
1214
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
1315
host "github.com/cosmos/ibc-go/v7/modules/core/24-host"
16+
ibcerrors "github.com/cosmos/ibc-go/v7/modules/core/errors"
17+
"github.com/cosmos/ibc-go/v7/modules/core/exported"
1418
ibctesting "github.com/cosmos/ibc-go/v7/testing"
1519
)
1620

@@ -243,6 +247,280 @@ func (suite *TransferTestSuite) TestOnChanOpenAck() {
243247
}
244248
}
245249

250+
func (suite *TransferTestSuite) TestOnRecvPacket() {
251+
// This test suite mostly covers the top-level logic of the ibc module OnRecvPacket function
252+
// The core logic is covered in keeper OnRecvPacket
253+
var (
254+
packet channeltypes.Packet
255+
path *ibctesting.Path
256+
)
257+
testCases := []struct {
258+
name string
259+
malleate func()
260+
expAck exported.Acknowledgement
261+
}{
262+
{
263+
"success", func() {}, channeltypes.NewResultAcknowledgement([]byte{byte(1)}),
264+
},
265+
{
266+
"failure: invalid packet data bytes",
267+
func() {
268+
packet.Data = []byte("invalid data")
269+
270+
},
271+
channeltypes.NewErrorAcknowledgement(ibcerrors.ErrInvalidType),
272+
},
273+
{
274+
"failure: receive disabled",
275+
func() {
276+
suite.chainB.GetSimApp().TransferKeeper.SetParams(suite.chainB.GetContext(), types.Params{ReceiveEnabled: false})
277+
},
278+
channeltypes.NewErrorAcknowledgement(types.ErrReceiveDisabled),
279+
},
280+
}
281+
282+
for _, tc := range testCases {
283+
suite.Run(tc.name, func() {
284+
suite.SetupTest() // reset
285+
286+
path = NewTransferPath(suite.chainA, suite.chainB)
287+
suite.coordinator.Setup(path)
288+
289+
coin := sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))
290+
291+
packetData := types.NewFungibleTokenPacketData(
292+
coin.Denom,
293+
coin.Amount.String(),
294+
suite.chainA.SenderAccount.GetAddress().String(),
295+
suite.chainB.SenderAccount.GetAddress().String(),
296+
"",
297+
)
298+
299+
seq := uint64(1)
300+
packet = channeltypes.NewPacket(packetData.GetBytes(), seq, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, suite.chainA.GetTimeoutHeight(), 0)
301+
302+
ctx := suite.chainB.GetContext()
303+
cbs, ok := suite.chainB.App.GetIBCKeeper().PortKeeper.Router.GetRoute(ibctesting.TransferPort)
304+
suite.Require().True(ok)
305+
306+
tc.malleate() // change fields in packet
307+
308+
ack := cbs.OnRecvPacket(ctx, packet, suite.chainB.SenderAccount.GetAddress())
309+
310+
suite.Require().Equal(tc.expAck, ack)
311+
})
312+
}
313+
}
314+
315+
func (suite *TransferTestSuite) TestOnAcknowledgePacket() {
316+
var (
317+
path *ibctesting.Path
318+
packet channeltypes.Packet
319+
ack []byte
320+
)
321+
322+
testCases := []struct {
323+
name string
324+
malleate func()
325+
expError error
326+
expRefund bool
327+
}{
328+
{
329+
"success",
330+
func() {},
331+
nil,
332+
false,
333+
},
334+
{
335+
"success: refund coins",
336+
func() {
337+
ack = channeltypes.NewErrorAcknowledgement(ibcerrors.ErrInsufficientFunds).Acknowledgement()
338+
},
339+
nil,
340+
true,
341+
},
342+
{
343+
"cannot refund ack on non-existent channel",
344+
func() {
345+
ack = channeltypes.NewErrorAcknowledgement(ibcerrors.ErrInsufficientFunds).Acknowledgement()
346+
347+
packet.SourceChannel = "channel-100"
348+
},
349+
errors.New("unable to unescrow tokens"),
350+
false,
351+
},
352+
{
353+
"invalid packet data",
354+
func() {
355+
packet.Data = []byte("invalid data")
356+
},
357+
sdkerrors.ErrUnknownRequest,
358+
false,
359+
},
360+
{
361+
"invalid acknowledgement",
362+
func() {
363+
ack = []byte("invalid ack")
364+
},
365+
ibcerrors.ErrUnknownRequest,
366+
false,
367+
},
368+
{
369+
"cannot refund already acknowledged packet",
370+
func() {
371+
ack = channeltypes.NewErrorAcknowledgement(ibcerrors.ErrInsufficientFunds).Acknowledgement()
372+
373+
cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Router.GetRoute(ibctesting.TransferPort)
374+
suite.Require().True(ok)
375+
376+
suite.Require().NoError(cbs.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, ack, suite.chainA.SenderAccount.GetAddress()))
377+
},
378+
errors.New("unable to unescrow tokens"),
379+
false,
380+
},
381+
}
382+
383+
for _, tc := range testCases {
384+
tc := tc
385+
suite.Run(tc.name, func() {
386+
suite.SetupTest() // reset
387+
388+
path = NewTransferPath(suite.chainA, suite.chainB)
389+
suite.coordinator.Setup(path)
390+
391+
timeoutHeight := suite.chainA.GetTimeoutHeight()
392+
msg := types.NewMsgTransfer(
393+
path.EndpointA.ChannelConfig.PortID,
394+
path.EndpointA.ChannelID,
395+
ibctesting.TestCoin,
396+
suite.chainA.SenderAccount.GetAddress().String(),
397+
suite.chainB.SenderAccount.GetAddress().String(),
398+
timeoutHeight,
399+
0,
400+
"",
401+
)
402+
res, err := suite.chainA.SendMsgs(msg)
403+
suite.Require().NoError(err) // message committed
404+
405+
packet, err = ibctesting.ParsePacketFromEvents(res.GetEvents())
406+
suite.Require().NoError(err)
407+
408+
cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Router.GetRoute(ibctesting.TransferPort)
409+
suite.Require().True(ok)
410+
411+
ack = channeltypes.NewResultAcknowledgement([]byte{byte(1)}).Acknowledgement()
412+
413+
tc.malleate() // change fields in packet
414+
415+
err = cbs.OnAcknowledgementPacket(suite.chainA.GetContext(), packet, ack, suite.chainA.SenderAccount.GetAddress())
416+
417+
if tc.expError == nil {
418+
suite.Require().NoError(err)
419+
420+
if tc.expRefund {
421+
escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel())
422+
escrowBalanceAfter := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom)
423+
suite.Require().Equal(sdk.NewInt(0), escrowBalanceAfter.Amount)
424+
}
425+
} else {
426+
suite.Require().Error(err)
427+
suite.Require().Contains(err.Error(), tc.expError.Error())
428+
}
429+
})
430+
}
431+
}
432+
433+
func (suite *TransferTestSuite) TestOnTimeoutPacket() {
434+
var path *ibctesting.Path
435+
var packet channeltypes.Packet
436+
437+
testCases := []struct {
438+
name string
439+
coinsToSendToB sdk.Coin
440+
malleate func()
441+
expError error
442+
}{
443+
{
444+
"success",
445+
ibctesting.TestCoin,
446+
func() {},
447+
nil,
448+
},
449+
{
450+
"non-existent channel",
451+
ibctesting.TestCoin,
452+
func() {
453+
packet.SourceChannel = "channel-100"
454+
},
455+
errors.New("unable to unescrow tokens"),
456+
},
457+
{
458+
"invalid packet data",
459+
ibctesting.TestCoin,
460+
func() {
461+
packet.Data = []byte("invalid data")
462+
},
463+
sdkerrors.ErrUnknownRequest,
464+
},
465+
{
466+
"already timed-out packet",
467+
ibctesting.TestCoin,
468+
func() {
469+
cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Router.GetRoute(ibctesting.TransferPort)
470+
suite.Require().True(ok)
471+
472+
suite.Require().NoError(cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress()))
473+
},
474+
errors.New("unable to unescrow tokens"),
475+
},
476+
}
477+
478+
for _, tc := range testCases {
479+
tc := tc
480+
suite.Run(tc.name, func() {
481+
suite.SetupTest() // reset
482+
483+
path = NewTransferPath(suite.chainA, suite.chainB)
484+
suite.coordinator.Setup(path)
485+
486+
timeoutHeight := suite.chainA.GetTimeoutHeight()
487+
msg := types.NewMsgTransfer(
488+
path.EndpointA.ChannelConfig.PortID,
489+
path.EndpointA.ChannelID,
490+
tc.coinsToSendToB,
491+
suite.chainA.SenderAccount.GetAddress().String(),
492+
suite.chainB.SenderAccount.GetAddress().String(),
493+
timeoutHeight,
494+
0,
495+
"",
496+
)
497+
res, err := suite.chainA.SendMsgs(msg)
498+
suite.Require().NoError(err) // message committed
499+
500+
packet, err = ibctesting.ParsePacketFromEvents(res.GetEvents())
501+
suite.Require().NoError(err)
502+
503+
cbs, ok := suite.chainA.App.GetIBCKeeper().PortKeeper.Router.GetRoute(ibctesting.TransferPort)
504+
suite.Require().True(ok)
505+
506+
tc.malleate() // change fields in packet
507+
508+
err = cbs.OnTimeoutPacket(suite.chainA.GetContext(), packet, suite.chainA.SenderAccount.GetAddress())
509+
510+
if tc.expError == nil {
511+
suite.Require().NoError(err)
512+
513+
escrowAddress := types.GetEscrowAddress(packet.GetSourcePort(), packet.GetSourceChannel())
514+
escrowBalanceAfter := suite.chainA.GetSimApp().BankKeeper.GetBalance(suite.chainA.GetContext(), escrowAddress, sdk.DefaultBondDenom)
515+
suite.Require().Equal(sdk.NewInt(0), escrowBalanceAfter.Amount)
516+
} else {
517+
suite.Require().Error(err)
518+
suite.Require().Contains(err.Error(), tc.expError.Error())
519+
}
520+
})
521+
}
522+
}
523+
246524
func (suite *TransferTestSuite) TestPacketDataUnmarshalerInterface() {
247525
var (
248526
sender = sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address()).String()

0 commit comments

Comments
 (0)