Skip to content

Commit

Permalink
fix(fraud): refunding pending outgoing packets (#816)
Browse files Browse the repository at this point in the history
Co-authored-by: Omri <[email protected]>
  • Loading branch information
mtsitrin and omritoptix authored Apr 8, 2024
1 parent 8007da9 commit 456e6aa
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 59 deletions.
1 change: 0 additions & 1 deletion x/delayedack/ibc_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,6 @@ func (im IBCMiddleware) OnAcknowledgementPacket(
Relayer: relayer,
ProofHeight: proofHeight,
Type: commontypes.RollappPacket_ON_ACK,
// TODO: do I need to set the error field here?
}
err = im.keeper.SetRollappPacket(ctx, rollappPacket)
if err != nil {
Expand Down
49 changes: 20 additions & 29 deletions x/delayedack/keeper/fraud.go
Original file line number Diff line number Diff line change
@@ -1,56 +1,47 @@
package keeper

import (
"fmt"

sdk "github.com/cosmos/cosmos-sdk/types"
channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types"
commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
)

func (k Keeper) HandleFraud(ctx sdk.Context, rollappID string) error {
func (k Keeper) HandleFraud(ctx sdk.Context, rollappID string, ibc porttypes.IBCModule) error {
// Get all the pending packets
rollappPendingPackets := k.ListRollappPackets(ctx, ByRollappIDByStatus(rollappID, commontypes.Status_PENDING))
if len(rollappPendingPackets) == 0 {
return nil
}
logger := ctx.Logger().With("module", "DelayedAckMiddleware")
logger.Debug("Reverting IBC rollapp packets", "rollappID", rollappID)

// Iterate over all the pending packets and revert them
for _, rollappPacket := range rollappPendingPackets {
errString := "fraudulent packet"
packetId := channeltypes.NewPacketID(rollappPacket.Packet.GetDestPort(), rollappPacket.Packet.GetDestChannel(), rollappPacket.Packet.GetSequence())
logger.Debug("Reverting IBC rollapp packet", "rollappID", rollappID, "packetId", packetId, "type", rollappPacket.Type)
logContext := []interface{}{
"rollappID", rollappID,
"sourceChannel", rollappPacket.Packet.SourceChannel,
"destChannel", rollappPacket.Packet.DestinationChannel,
"type", rollappPacket.Type,
"sequence", rollappPacket.Packet.Sequence,
}

if rollappPacket.Type == commontypes.RollappPacket_ON_RECV {
err := k.writeFailedAck(ctx, rollappPacket, errString)
logger.Debug("Reverting IBC rollapp packet", logContext...)

if rollappPacket.Type == commontypes.RollappPacket_ON_ACK || rollappPacket.Type == commontypes.RollappPacket_ON_TIMEOUT {
// refund all pending outgoing packets
// we don't have access directly to `refundPacketToken` function, so we'll use the `OnTimeoutPacket` function
err := ibc.OnTimeoutPacket(ctx, *rollappPacket.Packet, rollappPacket.Relayer)
if err != nil {
logger.Error("failed to write failed ack", "rollappID", rollappID, "packetId", packetId, "error", errString)
// don't return here as it's nice to have
logger.Error("failed to refund reverted packet", append(logContext, "error", err.Error())...)
}
}

// Update status to reverted
rollappPacket.Error = errString
rollappPacket, err := k.UpdateRollappPacketWithStatus(ctx, rollappPacket, commontypes.Status_REVERTED)
_, err := k.UpdateRollappPacketWithStatus(ctx, rollappPacket, commontypes.Status_REVERTED)
if err != nil {
logger.Error("Error reverting IBC rollapp packet", "rollappID", rollappID, "packetId", packetId, "type", rollappPacket.Type, "error", err.Error())
logger.Error("Error reverting IBC rollapp packet", append(logContext, "error", err.Error())...)
return err
}
}
return nil
}

func (k Keeper) writeFailedAck(ctx sdk.Context, rollappPacket commontypes.RollappPacket, msg string) error {
failedAck := channeltypes.NewErrorAcknowledgement(fmt.Errorf(msg))
// Write the acknowledgement to the chain
_, chanCap, err := k.LookupModuleByChannel(ctx, rollappPacket.Packet.DestinationPort, rollappPacket.Packet.DestinationChannel)
if err != nil {
return err
}
err = k.WriteAcknowledgement(ctx, chanCap, rollappPacket.Packet, failedAck)
if err != nil {
return err
}

return nil
}
36 changes: 35 additions & 1 deletion x/delayedack/keeper/fraud_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
package keeper_test

import (
ibctransfer "github.com/cosmos/ibc-go/v6/modules/apps/transfer"
channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
damodule "github.com/dymensionxyz/dymension/v3/x/delayedack"
dkeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper"
"github.com/dymensionxyz/dymension/v3/x/delayedack/types"
)

func (suite *DelayedAckTestSuite) TestHandleFraud() {
keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx
transferStack := damodule.NewIBCMiddleware(ibctransfer.NewIBCModule(suite.App.TransferKeeper), keeper)

rollappId := "testRollappId"
pkts := generatePackets(rollappId, 5)
rollappId2 := "testRollappId2"
Expand All @@ -32,7 +37,7 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() {
_, err = keeper.UpdateRollappPacketWithStatus(ctx, pkts2[0], commontypes.Status_FINALIZED)
suite.Require().Nil(err)

err = keeper.HandleFraud(ctx, rollappId)
err = keeper.HandleFraud(ctx, rollappId, transferStack)
suite.Require().Nil(err)

suite.Require().Equal(0, len(keeper.ListRollappPackets(ctx, prefixPending1)))
Expand All @@ -42,6 +47,35 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() {
suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized2)))
}

func (suite *DelayedAckTestSuite) TestDeletionOfRevertedPackets() {
keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx
transferStack := damodule.NewIBCMiddleware(ibctransfer.NewIBCModule(suite.App.TransferKeeper), keeper)

rollappId := "testRollappId"
pkts := generatePackets(rollappId, 5)
rollappId2 := "testRollappId2"
pkts2 := generatePackets(rollappId2, 5)

for _, pkt := range append(pkts, pkts2...) {
err := keeper.SetRollappPacket(ctx, pkt)
suite.Require().NoError(err)
}

err := keeper.HandleFraud(ctx, rollappId, transferStack)
suite.Require().Nil(err)

suite.Require().Equal(10, len(keeper.GetAllRollappPackets(ctx)))

keeper.SetParams(ctx, types.Params{EpochIdentifier: "minute"})
epochHooks := keeper.GetEpochHooks()
err = epochHooks.AfterEpochEnd(ctx, "minute", 1)
suite.Require().NoError(err)

suite.Require().Equal(5, len(keeper.GetAllRollappPackets(ctx)))
}

// TODO: test refunds of pending packets

/* ---------------------------------- utils --------------------------------- */

func generatePackets(rollappId string, num uint64) []commontypes.RollappPacket {
Expand Down
26 changes: 0 additions & 26 deletions x/delayedack/keeper/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,29 +86,3 @@ func (suite *DelayedAckTestSuite) TestAfterEpochEnd() {
})
}
}

func (suite *DelayedAckTestSuite) TestDeletionOfRevertedPackets() {
keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx

rollappId := "testRollappId"
pkts := generatePackets(rollappId, 5)
rollappId2 := "testRollappId2"
pkts2 := generatePackets(rollappId2, 5)

for _, pkt := range append(pkts, pkts2...) {
err := keeper.SetRollappPacket(ctx, pkt)
suite.Require().NoError(err)
}

err := keeper.HandleFraud(ctx, rollappId)
suite.Require().Nil(err)

suite.Require().Equal(10, len(keeper.GetAllRollappPackets(ctx)))

keeper.SetParams(ctx, types.Params{EpochIdentifier: "minute"})
epochHooks := keeper.GetEpochHooks()
err = epochHooks.AfterEpochEnd(ctx, "minute", 1)
suite.Require().NoError(err)

suite.Require().Equal(5, len(keeper.GetAllRollappPackets(ctx)))
}
8 changes: 7 additions & 1 deletion x/delayedack/keeper/invariants_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ package keeper_test
import (
"github.com/tendermint/tendermint/libs/rand"

ibctransfer "github.com/cosmos/ibc-go/v6/modules/apps/transfer"
channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
commontypes "github.com/dymensionxyz/dymension/v3/x/common/types"
damodule "github.com/dymensionxyz/dymension/v3/x/delayedack"
"github.com/dymensionxyz/dymension/v3/x/rollapp/types"
rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types"
)

func (suite *DelayedAckTestSuite) TestInvariants() {
suite.SetupTest()

keeper := suite.App.DelayedAckKeeper
transferStack := damodule.NewIBCMiddleware(ibctransfer.NewIBCModule(suite.App.TransferKeeper), keeper)

initialHeight := int64(10)
suite.Ctx = suite.Ctx.WithBlockHeight(initialHeight)

Expand Down Expand Up @@ -67,7 +73,7 @@ func (suite *DelayedAckTestSuite) TestInvariants() {

// test fraud
for rollapp := range seqPerRollapp {
err := suite.App.DelayedAckKeeper.HandleFraud(suite.Ctx, rollapp)
err := suite.App.DelayedAckKeeper.HandleFraud(suite.Ctx, rollapp, transferStack)
suite.Require().NoError(err)
break
}
Expand Down
2 changes: 1 addition & 1 deletion x/delayedack/rollapp_hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (im IBCMiddleware) AfterStateFinalized(ctx sdk.Context, rollappID string, s
}

func (im IBCMiddleware) FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error {
return im.keeper.HandleFraud(ctx, rollappID)
return im.keeper.HandleFraud(ctx, rollappID, im.IBCModule)
}

// FinalizeRollappPackets finalizes the packets for the given rollapp until the given height which is
Expand Down

0 comments on commit 456e6aa

Please sign in to comment.