diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 5d494e6c5..dff448404 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -475,6 +475,7 @@ func (a *AppKeepers) InitKeepers( a.DelayedAckKeeper = *delayedackkeeper.NewKeeper( appCodec, a.keys[delayedacktypes.StoreKey], + a.keys[ibcexported.StoreKey], a.GetSubspace(delayedacktypes.ModuleName), a.RollappKeeper, a.IBCKeeper.ChannelKeeper, diff --git a/proto/dymensionxyz/dymension/common/status.proto b/proto/dymensionxyz/dymension/common/status.proto index 432a15a15..3cb04faa4 100644 --- a/proto/dymensionxyz/dymension/common/status.proto +++ b/proto/dymensionxyz/dymension/common/status.proto @@ -8,5 +8,4 @@ option go_package = "github.com/dymensionxyz/dymension/v3/x/common/types"; enum Status { PENDING = 0; FINALIZED = 1; - REVERTED = 3; } diff --git a/testutil/keeper/delayedack.go b/testutil/keeper/delayedack.go index 442336c73..019ec85a6 100644 --- a/testutil/keeper/delayedack.go +++ b/testutil/keeper/delayedack.go @@ -137,6 +137,7 @@ func DelayedackKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { k := keeper.NewKeeper(cdc, storeKey, + nil, paramsSubspace, RollappKeeperStub{}, ICS4WrapperStub{}, diff --git a/x/common/types/key_rollapp_packet.go b/x/common/types/key_rollapp_packet.go index 3f79ebb16..9566d4303 100644 --- a/x/common/types/key_rollapp_packet.go +++ b/x/common/types/key_rollapp_packet.go @@ -18,8 +18,6 @@ var ( PendingRollappPacketKeyPrefix = []byte{0x00, 0x01} // FinalizedRollappPacketKeyPrefix is the prefix for finalized rollapp packets FinalizedRollappPacketKeyPrefix = []byte{0x00, 0x02} - // RevertedRollappPacketKeyPrefix is the prefix for reverted rollapp packets - RevertedRollappPacketKeyPrefix = []byte{0x00, 0x03} // keySeparatorBytes is used to separate the rollapp packet key parts keySeparatorBytes = []byte("/") ) @@ -100,8 +98,6 @@ func MustGetStatusBytes(status Status) []byte { return PendingRollappPacketKeyPrefix case Status_FINALIZED: return FinalizedRollappPacketKeyPrefix - case Status_REVERTED: - return RevertedRollappPacketKeyPrefix default: panic(fmt.Sprintf("invalid packet status: %s", status)) } diff --git a/x/common/types/status.pb.go b/x/common/types/status.pb.go index dbf4fdfc2..a803d617f 100644 --- a/x/common/types/status.pb.go +++ b/x/common/types/status.pb.go @@ -26,19 +26,16 @@ type Status int32 const ( Status_PENDING Status = 0 Status_FINALIZED Status = 1 - Status_REVERTED Status = 3 ) var Status_name = map[int32]string{ 0: "PENDING", 1: "FINALIZED", - 3: "REVERTED", } var Status_value = map[string]int32{ "PENDING": 0, "FINALIZED": 1, - "REVERTED": 3, } func (x Status) String() string { @@ -58,17 +55,16 @@ func init() { } var fileDescriptor_acfb62db52f6fda8 = []byte{ - // 190 bytes of a gzipped FileDescriptorProto + // 176 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4a, 0xa9, 0xcc, 0x4d, 0xcd, 0x2b, 0xce, 0xcc, 0xcf, 0xab, 0xa8, 0xac, 0xd2, 0x87, 0x73, 0xf4, 0x93, 0xf3, 0x73, 0x73, 0xf3, 0xf3, 0xf4, 0x8b, 0x4b, 0x12, 0x4b, 0x4a, 0x8b, 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0x64, 0x91, 0xd5, 0xea, 0xc1, 0x39, 0x7a, 0x10, 0xb5, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, - 0x95, 0xfa, 0x20, 0x16, 0x44, 0x93, 0x96, 0x11, 0x17, 0x5b, 0x30, 0xd8, 0x10, 0x21, 0x6e, 0x2e, + 0x95, 0xfa, 0x20, 0x16, 0x44, 0x93, 0x96, 0x0a, 0x17, 0x5b, 0x30, 0xd8, 0x10, 0x21, 0x6e, 0x2e, 0xf6, 0x00, 0x57, 0x3f, 0x17, 0x4f, 0x3f, 0x77, 0x01, 0x06, 0x21, 0x5e, 0x2e, 0x4e, 0x37, 0x4f, - 0x3f, 0x47, 0x1f, 0xcf, 0x28, 0x57, 0x17, 0x01, 0x46, 0x21, 0x1e, 0x2e, 0x8e, 0x20, 0xd7, 0x30, - 0xd7, 0xa0, 0x10, 0x57, 0x17, 0x01, 0x66, 0x27, 0xdf, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, - 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, - 0x96, 0x63, 0x88, 0x32, 0x4e, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0x02, 0x59, 0xa9, 0x8f, 0xc3, 0xe5, - 0x65, 0xc6, 0xfa, 0x15, 0x30, 0xe7, 0x97, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x5d, 0x62, - 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x50, 0xdb, 0xd7, 0x0d, 0xec, 0x00, 0x00, 0x00, + 0x3f, 0x47, 0x1f, 0xcf, 0x28, 0x57, 0x17, 0x01, 0x46, 0x27, 0xdf, 0x13, 0x8f, 0xe4, 0x18, 0x2f, + 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, + 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x32, 0x4e, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0x02, 0x59, 0xa2, 0x8f, + 0xc3, 0xad, 0x65, 0xc6, 0xfa, 0x15, 0x30, 0x07, 0x97, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, + 0xed, 0x36, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x19, 0xa7, 0x17, 0xce, 0xde, 0x00, 0x00, 0x00, } diff --git a/x/delayedack/client/cli/query.go b/x/delayedack/client/cli/query.go index aac99e140..3779759d9 100644 --- a/x/delayedack/client/cli/query.go +++ b/x/delayedack/client/cli/query.go @@ -62,7 +62,7 @@ func CmdGetPacketsByRollapp() *cobra.Command { cmd := &cobra.Command{ Use: "packets-by-rollapp rollapp-id [status] [type]", Short: "Get packets by rollapp-id", - Long: `Get packets by rollapp-id. Can filter by status (pending/finalized/reverted) and by type (recv/ack/timeout) + Long: `Get packets by rollapp-id. Can filter by status (pending/finalized) and by type (recv/ack/timeout) Example: packets rollapp1 packets rollapp1 PENDING @@ -124,7 +124,7 @@ func CmdGetPacketsByStatus() *cobra.Command { cmd := &cobra.Command{ Use: "packets-by-status status [type]", Short: "Get packets by status", - Long: `Get packets by status (pending/finalized/reverted). Can filter by type (recv/ack/timeout) + Long: `Get packets by status (pending/finalized). Can filter by type (recv/ack/timeout) Example: packets-by-status pending packets-by-status finalized recv`, diff --git a/x/delayedack/keeper/finalize.go b/x/delayedack/keeper/finalize.go index 3026f28d3..0323ff6f9 100644 --- a/x/delayedack/keeper/finalize.go +++ b/x/delayedack/keeper/finalize.go @@ -11,7 +11,6 @@ import ( "github.com/osmosis-labs/osmosis/v15/osmoutils" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" - "github.com/dymensionxyz/dymension/v3/x/delayedack/types" ) // FinalizeRollappPacket finalizes a singe packet by its rollapp packet key. @@ -25,7 +24,7 @@ func (k Keeper) FinalizeRollappPacket(ctx sdk.Context, ibc porttypes.IBCModule, // Verify the height is finalized err = k.VerifyHeightFinalized(ctx, packet.RollappId, packet.ProofHeight) if err != nil { - return packet, fmt.Errorf("verify height is finalized: rollapp '%s': %w", packet.RollappId, err) + return packet, fmt.Errorf("verify height: rollapp '%s': %w", packet.RollappId, err) } // Finalize the packet @@ -137,41 +136,14 @@ func (k Keeper) onTimeoutPacket(rollappPacket commontypes.RollappPacket, ibc por } func (k Keeper) VerifyHeightFinalized(ctx sdk.Context, rollappID string, height uint64) error { - // Get the latest state info of the rollapp - latestIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, rollappID) - if !found { - return gerrc.ErrNotFound.Wrapf("latest finalized state index is not found") - } - stateInfo, found := k.rollappKeeper.GetStateInfo(ctx, rollappID, latestIndex.Index) - if !found { - return gerrc.ErrNotFound.Wrapf("state info is not found") + latestFinalizedHeight, err := k.getRollappLatestFinalizedHeight(ctx, rollappID) + if err != nil { + return err } + // Check the latest finalized height of the rollapp is higher than the height specified - if height > stateInfo.GetLatestHeight() { - return gerrc.ErrInvalidArgument.Wrapf("packet height is not finalized yet: height '%d', latest height '%d'", height, stateInfo.GetLatestHeight()) + if height > latestFinalizedHeight { + return gerrc.ErrInvalidArgument.Wrapf("packet height is not finalized yet: height '%d', latest finalized height '%d'", height, latestFinalizedHeight) } return nil } - -func (k Keeper) GetRollappLatestFinalizedHeight(ctx sdk.Context, rollappID string) (uint64, error) { - latestIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, rollappID) - if !found { - return 0, gerrc.ErrNotFound.Wrapf("latest finalized state index is not found") - } - stateInfo, found := k.rollappKeeper.GetStateInfo(ctx, rollappID, latestIndex.Index) - if !found { - return 0, gerrc.ErrNotFound.Wrapf("state info is not found") - } - return stateInfo.GetLatestHeight(), nil -} - -func (k Keeper) GetPendingPacketsUntilLatestHeight(ctx sdk.Context, rollappID string) ([]commontypes.RollappPacket, uint64, error) { - // Get rollapp's latest finalized height - latestFinalizedHeight, err := k.GetRollappLatestFinalizedHeight(ctx, rollappID) - if err != nil { - return nil, 0, fmt.Errorf("get latest finalized height: rollapp '%s': %w", rollappID, err) - } - - // Get all pending rollapp packets until the latest finalized height - return k.ListRollappPackets(ctx, types.PendingByRollappIDByMaxHeight(rollappID, latestFinalizedHeight)), latestFinalizedHeight, nil -} diff --git a/x/delayedack/keeper/finalize_test.go b/x/delayedack/keeper/finalize_test.go index 9fa890597..6dce23e84 100644 --- a/x/delayedack/keeper/finalize_test.go +++ b/x/delayedack/keeper/finalize_test.go @@ -51,7 +51,7 @@ func (s *DelayedAckTestSuite) TestFinalizePacket() { }, rollappHeight: 10, expectErr: true, - errContains: "packet height is not finalized yet: height '15', latest height '10'", + errContains: "verify height", }, } diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 74b26938c..790fcb54e 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -5,18 +5,16 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" ) -func (k Keeper) HandleFraud(ctx sdk.Context, rollappID string, ibc porttypes.IBCModule) error { - // Get all the pending packets - rollappPendingPackets := k.ListRollappPackets(ctx, types.ByRollappIDByStatus(rollappID, commontypes.Status_PENDING)) - if len(rollappPendingPackets) == 0 { - return nil - } +func (k Keeper) HandleHardFork(ctx sdk.Context, rollappID string, height uint64, ibc porttypes.IBCModule) error { logger := ctx.Logger().With("module", "DelayedAckMiddleware") - logger.Info("reverting IBC rollapp packets", "rollappID", rollappID) + + // Get all the pending packets from fork height inclusive + rollappPendingPackets := k.ListRollappPackets(ctx, types.PendingByRollappIDFromHeight(rollappID, height)) // Iterate over all the pending packets and revert them for _, rollappPacket := range rollappPendingPackets { @@ -28,22 +26,31 @@ func (k Keeper) HandleFraud(ctx sdk.Context, rollappID string, ibc porttypes.IBC "sequence", rollappPacket.Packet.Sequence, } + // refund all pending outgoing packets 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 refund reverted packet", append(logContext, "error", err.Error())...) } - } - // Update status to reverted - _, err := k.UpdateRollappPacketWithStatus(ctx, rollappPacket, commontypes.Status_REVERTED) - if err != nil { - logger.Error("error reverting IBC rollapp packet", append(logContext, "error", err.Error())...) - return err + } else { + // for incoming packets, we need to reset the packet receipt + ibcPacket := rollappPacket.Packet + k.deletePacketReceipt(ctx, ibcPacket.GetDestPort(), ibcPacket.GetDestChannel(), ibcPacket.GetSequence()) } + // delete the packet + k.DeleteRollappPacket(ctx, &rollappPacket) logger.Debug("reverted IBC rollapp packet", logContext...) } + + logger.Info("reverting IBC rollapp packets", "rollappID", rollappID, "numPackets", len(rollappPendingPackets)) + return nil } + +// DeleteRollappPacket deletes a packet receipt from the store +func (k Keeper) deletePacketReceipt(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := ctx.KVStore(k.channelKeeperStoreKey) + store.Delete(host.PacketReceiptKey(portID, channelID, sequence)) +} diff --git a/x/delayedack/keeper/fraud_test.go b/x/delayedack/keeper/fraud_test.go index ae3555a28..7d3f5ec99 100644 --- a/x/delayedack/keeper/fraud_test.go +++ b/x/delayedack/keeper/fraud_test.go @@ -18,66 +18,45 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { ) rollappId := "testRollappId" - pkts := generatePackets(rollappId, 5) + pkts := generatePackets(rollappId, 10) rollappId2 := "testRollappId2" - pkts2 := generatePackets(rollappId2, 5) + pkts2 := generatePackets(rollappId2, 10) prefixPending1 := types.ByRollappIDByStatus(rollappId, commontypes.Status_PENDING) prefixPending2 := types.ByRollappIDByStatus(rollappId2, commontypes.Status_PENDING) - prefixReverted := types.ByRollappIDByStatus(rollappId, commontypes.Status_REVERTED) - prefixFinalized := types.ByRollappIDByStatus(rollappId, commontypes.Status_FINALIZED) + prefixFinalized1 := types.ByRollappIDByStatus(rollappId, commontypes.Status_FINALIZED) prefixFinalized2 := types.ByRollappIDByStatus(rollappId, commontypes.Status_FINALIZED) for _, pkt := range append(pkts, pkts2...) { keeper.SetRollappPacket(ctx, pkt) } - suite.Require().Equal(5, len(keeper.ListRollappPackets(ctx, prefixPending1))) - suite.Require().Equal(5, len(keeper.ListRollappPackets(ctx, prefixPending2))) + suite.Require().Equal(10, len(keeper.ListRollappPackets(ctx, prefixPending1))) + suite.Require().Equal(10, len(keeper.ListRollappPackets(ctx, prefixPending2))) - // finalize some packets + // finalize one packet _, err := keeper.UpdateRollappPacketWithStatus(ctx, pkts[0], commontypes.Status_FINALIZED) suite.Require().Nil(err) _, err = keeper.UpdateRollappPacketWithStatus(ctx, pkts2[0], commontypes.Status_FINALIZED) suite.Require().Nil(err) - err = keeper.HandleFraud(ctx, rollappId, transferStack) + // call fraud on the 4 packet + err = keeper.HandleHardFork(ctx, rollappId, 4, transferStack) suite.Require().Nil(err) - suite.Require().Equal(0, len(keeper.ListRollappPackets(ctx, prefixPending1))) - suite.Require().Equal(4, len(keeper.ListRollappPackets(ctx, prefixPending2))) - suite.Require().Equal(4, len(keeper.ListRollappPackets(ctx, prefixReverted))) - suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized))) - suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized2))) -} - -func (suite *DelayedAckTestSuite) TestDeletionOfRevertedPackets() { - keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx - transferStack := damodule.NewIBCMiddleware( - damodule.WithIBCModule(ibctransfer.NewIBCModule(suite.App.TransferKeeper)), - damodule.WithKeeper(keeper), - damodule.WithRollappKeeper(suite.App.RollappKeeper), - ) - - rollappId := "testRollappId" - pkts := generatePackets(rollappId, 5) - rollappId2 := "testRollappId2" - pkts2 := generatePackets(rollappId2, 5) - - for _, pkt := range append(pkts, pkts2...) { - keeper.SetRollappPacket(ctx, pkt) - } - - err := keeper.HandleFraud(ctx, rollappId, transferStack) - suite.Require().Nil(err) + // expected result: + // rollappId: + // - packet 1 are finalized + // - packet 2-3 are still pending + // - packets 4-10 are deleted + // rollappId2: + // - packet 1 are finalized + // - packets 2-10 are still pending - suite.Require().Equal(10, len(keeper.GetAllRollappPackets(ctx))) + suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized1))) + suite.Require().Equal(2, len(keeper.ListRollappPackets(ctx, prefixPending1))) - keeper.SetParams(ctx, types.Params{EpochIdentifier: "minute", BridgingFee: keeper.BridgingFee(ctx)}) - epochHooks := keeper.GetEpochHooks() - err = epochHooks.AfterEpochEnd(ctx, "minute", 1) - suite.Require().NoError(err) - - suite.Require().Equal(5, len(keeper.GetAllRollappPackets(ctx))) + suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized2))) + suite.Require().Equal(9, len(keeper.ListRollappPackets(ctx, prefixPending2))) } // TODO: test refunds of pending packets @@ -86,7 +65,7 @@ func (suite *DelayedAckTestSuite) TestDeletionOfRevertedPackets() { func generatePackets(rollappId string, num uint64) []commontypes.RollappPacket { var packets []commontypes.RollappPacket - for i := uint64(0); i < num; i++ { + for i := uint64(1); i <= num; i++ { packets = append(packets, commontypes.RollappPacket{ RollappId: rollappId, Packet: &channeltypes.Packet{ diff --git a/x/delayedack/keeper/grpc_query.go b/x/delayedack/keeper/grpc_query.go index 70d558627..151b7fb18 100644 --- a/x/delayedack/keeper/grpc_query.go +++ b/x/delayedack/keeper/grpc_query.go @@ -63,7 +63,7 @@ func (q Querier) GetPendingPacketsByReceiver(goCtx context.Context, req *types.Q ctx := sdk.UnwrapSDKContext(goCtx) // Get all pending rollapp packets until the latest finalized height - rollappPendingPackets, _, err := q.GetPendingPacketsUntilLatestHeight(ctx, req.RollappId) + rollappPendingPackets, _, err := q.GetPendingPacketsUntilFinalizedHeight(ctx, req.RollappId) if err != nil { return nil, fmt.Errorf("get pending rollapp packets until the latest finalized height: rollapp '%s': %w", req.RollappId, err) } diff --git a/x/delayedack/keeper/hooks.go b/x/delayedack/keeper/hooks.go index 401b43d97..5d777b0b3 100644 --- a/x/delayedack/keeper/hooks.go +++ b/x/delayedack/keeper/hooks.go @@ -72,7 +72,7 @@ func (e epochHooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epoch return nil } - listFilter := types.ByStatus(commontypes.Status_FINALIZED, commontypes.Status_REVERTED).Take(int(deletePacketsBatchSize)) + listFilter := types.ByStatus(commontypes.Status_FINALIZED).Take(int(deletePacketsBatchSize)) count := 0 // Get batch of rollapp packets with status != PENDING and delete them @@ -83,7 +83,7 @@ func (e epochHooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epoch for _, packet := range toDeletePackets { err := osmoutils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error { - return e.deleteRollappPacket(ctx, &packet) + return e.DeleteRollappPacket(ctx, &packet) }) if err != nil { e.Logger(ctx).Error("Failed to delete rollapp packet", diff --git a/x/delayedack/keeper/invariants.go b/x/delayedack/keeper/invariants.go index 382744407..66e615249 100644 --- a/x/delayedack/keeper/invariants.go +++ b/x/delayedack/keeper/invariants.go @@ -12,73 +12,48 @@ import ( const ( routeFinalizedPacket = "rollapp-finalized-packet" - routeRevertedPacket = "rollapp-reverted-packet" ) // RegisterInvariants registers the delayedack module invariants func (k Keeper) RegisterInvariants(ir sdk.InvariantRegistry) { - ir.RegisterRoute(types.ModuleName, routeFinalizedPacket, k.PacketsFinalizationCorrespondsToFinalizationHeight) - // ir.RegisterRoute(types.ModuleName, routeRevertedPacket, k.PacketsFromRevertedHeightsAreReverted) + // INVARIANTS DISABLED SINCE LAZY FINALIZATION FEATURE } // PacketsFinalizationCorrespondsToFinalizationHeight checks that all rollapp packets stored are set to // finalized status for all heights up to the latest height. -func (k Keeper) PacketsFinalizationCorrespondsToFinalizationHeight(ctx sdk.Context) (string, bool) { - return k.packetsCorrespondsToStatusHeight(checkFinalizedPackets)(ctx) -} - -// PacketsFromRevertedHeightsAreReverted checks that all rollapp packets stored are set to -// reverted status for all heights up to the latest height -func (k Keeper) PacketsFromRevertedHeightsAreReverted(ctx sdk.Context) (string, bool) { - return k.packetsCorrespondsToStatusHeight(checkRevertedPackets)(ctx) -} +func PacketsFinalizationCorrespondsToFinalizationHeight(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + var ( + broken bool + msg string + ) -type checkPacketsFn func(packets []commontypes.RollappPacket, latestFinalizedHeight uint64) string - -// packetsCorrespondsToStatusHeight checks that all rollapp packets stored are set to adequate status for all heights up to the latest height -func (k Keeper) packetsCorrespondsToStatusHeight(checkPackets checkPacketsFn) sdk.Invariant { - return func(ctx sdk.Context) (msg string, stop bool) { for _, rollapp := range k.rollappKeeper.GetAllRollapps(ctx) { - msg = k.checkRollapp(ctx, rollapp, checkPackets) - if stop = msg != ""; stop { - break + msg = k.checkRollapp(ctx, rollapp) + if msg != "" { + msg += fmt.Sprintf("rollapp: %s, msg: %s\n", rollapp.RollappId, msg) + broken = true } } - return + return sdk.FormatInvariant(types.ModuleName, routeFinalizedPacket, msg), broken } } -func (k Keeper) checkRollapp(ctx sdk.Context, rollapp rtypes.Rollapp, checkPackets checkPacketsFn) (msg string) { +func (k Keeper) checkRollapp(ctx sdk.Context, rollapp rtypes.Rollapp) (msg string) { // will stay 0 if no state is found // but will still check packets var latestFinalizedHeight uint64 - defer func() { - if msg == "" { - packets := k.ListRollappPackets(ctx, types.ByRollappID(rollapp.RollappId)) - msg = checkPackets(packets, latestFinalizedHeight) - } - }() - latestFinalizedStateIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, rollapp.RollappId) if !found { return } - latestFinalizedStateInfo, found := k.rollappKeeper.GetStateInfo(ctx, rollapp.RollappId, latestFinalizedStateIndex.Index) - if !found { - msg = fmt.Sprintf("latest finalized state info not found for rollapp: %s", rollapp.RollappId) - return - } - + latestFinalizedStateInfo := k.rollappKeeper.MustGetStateInfo(ctx, rollapp.RollappId, latestFinalizedStateIndex.Index) latestFinalizedHeight = latestFinalizedStateInfo.GetLatestHeight() - return -} - -// checkFinalizedPackets checks that all rollapp packets stored are set to finalized status for all heights up to the latest height -func checkFinalizedPackets(packets []commontypes.RollappPacket, latestFinalizedHeight uint64) (_ string) { + packets := k.ListRollappPackets(ctx, types.ByRollappID(rollapp.RollappId)) for _, packet := range packets { if packet.ProofHeight > latestFinalizedHeight && packet.Status == commontypes.Status_FINALIZED { return fmt.Sprintf("rollapp packet for the height should not be in finalized status. height=%d, rollapp=%s, status=%s\n", @@ -87,15 +62,3 @@ func checkFinalizedPackets(packets []commontypes.RollappPacket, latestFinalizedH } return } - -// checkRevertedPackets checks that all rollapp packets stored are set to reverted status for all heights up to the latest height -func checkRevertedPackets(packets []commontypes.RollappPacket, latestFinalizedHeight uint64) (_ string) { - for _, packet := range packets { - if packet.ProofHeight > latestFinalizedHeight && packet.Status != commontypes.Status_REVERTED { - return fmt.Sprintf("packet should be reverted: rollapp: %s: height: %d: status: %s", - packet.RollappId, packet.ProofHeight, packet.Status) - } - } - - return -} diff --git a/x/delayedack/keeper/invariants_test.go b/x/delayedack/keeper/invariants_test.go index dae550a6e..f128e0c94 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -8,12 +8,12 @@ import ( 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" + dakeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) func (suite *DelayedAckTestSuite) TestInvariants() { - suite.SetupTest() + suite.T().Skip("skipping TestInvariants as it's not supported with lazy finalization feature") transferStack := damodule.NewIBCMiddleware( damodule.WithIBCModule(ibctransfer.NewIBCModule(suite.App.TransferKeeper)), @@ -82,35 +82,35 @@ func (suite *DelayedAckTestSuite) TestInvariants() { // test fraud for rollapp := range seqPerRollapp { - err := suite.App.DelayedAckKeeper.HandleFraud(suite.Ctx, rollapp, transferStack) + err := suite.App.DelayedAckKeeper.HandleHardFork(suite.Ctx, rollapp, uint64(suite.Ctx.BlockHeight()), transferStack) suite.Require().NoError(err) break } // check invariant - msg, fails := suite.App.DelayedAckKeeper.PacketsFinalizationCorrespondsToFinalizationHeight(suite.Ctx) - suite.Require().False(fails, msg) - msg, fails = suite.App.DelayedAckKeeper.PacketsFromRevertedHeightsAreReverted(suite.Ctx) + msg, fails := dakeeper.PacketsFinalizationCorrespondsToFinalizationHeight(suite.App.DelayedAckKeeper)(suite.Ctx) suite.Require().False(fails, msg) } +// TestRollappPacketsCasesInvariant tests the invariant that checks if the packets are finalized only for finalized heights +// by default, we have: +// - state1 with blocks 1-10 which is finalized +// - state2 with blocks 11-20 which is pending func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { - rollapp := "rollapp_1234-1" + suite.T().Skip("skipping TestRollappPacketsCasesInvariant as it's not supported with lazy finalization feature") + rollapp := "rollapp_1234-1" cases := []struct { name string - frozenRollapp bool - allFinalized bool nothingFinalized bool packet commontypes.RollappPacket packet2 commontypes.RollappPacket expectedIsBroken bool }{ + // successful checks { "successful invariant check - packets are finalized only for finalized heights", false, - false, - false, commontypes.RollappPacket{ RollappId: rollapp, Status: commontypes.Status_FINALIZED, @@ -126,19 +126,17 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { false, }, { - "successful revert check - packets are reverted for non-finalized states", - true, - false, + "successful invariant check - packets are not yet finalized for finalized heights", false, commontypes.RollappPacket{ RollappId: rollapp, - Status: commontypes.Status_FINALIZED, + Status: commontypes.Status_PENDING, ProofHeight: 5, Packet: suite.getNewTestPacket(1), }, commontypes.RollappPacket{ RollappId: rollapp, - Status: commontypes.Status_REVERTED, + Status: commontypes.Status_PENDING, ProofHeight: 15, Packet: suite.getNewTestPacket(2), }, @@ -146,8 +144,6 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { }, { "successful non-finalized state invariant check - packets without finalization state are not finalized", - false, - false, true, commontypes.RollappPacket{ RollappId: rollapp, @@ -163,29 +159,9 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { }, false, }, - { - "wrong invariant revert check - packets for frozen rollapps in non-finalized heights are not reverted", - true, - false, - false, - commontypes.RollappPacket{ - RollappId: rollapp, - Status: commontypes.Status_FINALIZED, - ProofHeight: 5, - Packet: suite.getNewTestPacket(1), - }, - commontypes.RollappPacket{ - RollappId: rollapp, - Status: commontypes.Status_PENDING, - ProofHeight: 15, - Packet: suite.getNewTestPacket(2), - }, - true, - }, + // failed checks { "wrong finalized packet check - packets are finalized in non-finalized heights", - false, - false, true, commontypes.RollappPacket{ RollappId: rollapp, @@ -204,8 +180,6 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { { "wrong finalized packet check - packets for non-finalized heights are finalized", false, - false, - false, commontypes.RollappPacket{ RollappId: rollapp, Status: commontypes.Status_FINALIZED, @@ -240,6 +214,11 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { Status: commontypes.Status_FINALIZED, Sequencer: proposer, } + if tc.nothingFinalized { + stateInfo.Status = commontypes.Status_PENDING + } + suite.App.RollappKeeper.SetStateInfo(ctx, stateInfo) + stateInfo2 := rollapptypes.StateInfo{ StateInfoIndex: rollapptypes.StateInfoIndex{ RollappId: rollapp, @@ -250,40 +229,10 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { Status: commontypes.Status_PENDING, Sequencer: proposer, } - - // if nothingFinalized true, all the state infos submitted should be pending - if tc.nothingFinalized { - stateInfo.Status = commontypes.Status_PENDING - } else { - suite.App.RollappKeeper.SetLatestFinalizedStateIndex(ctx, types.StateInfoIndex{ - RollappId: rollapp, - Index: stateInfo.GetIndex().Index, - }) - } - - suite.App.RollappKeeper.SetStateInfo(ctx, stateInfo) - - // if allFinalized true, all the state infos submitted should be finalized - if tc.allFinalized { - stateInfo2.Status = commontypes.Status_FINALIZED - } - suite.App.RollappKeeper.SetStateInfo(ctx, stateInfo2) - if stateInfo2.Status == commontypes.Status_FINALIZED { - suite.App.RollappKeeper.SetLatestFinalizedStateIndex(ctx, types.StateInfoIndex{ - RollappId: rollapp, - Index: stateInfo2.GetIndex().Index, - }) - } - suite.App.RollappKeeper.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ - RollappId: rollapp, - Index: stateInfo2.GetIndex().Index, - }) - - // if frozenRollapp true, we should freeze the rollapp and revert pending states - if tc.frozenRollapp { - err := suite.App.RollappKeeper.HardFork(ctx, rollapp, 11) - suite.Require().NoError(err) + suite.App.RollappKeeper.SetLatestStateInfoIndex(ctx, stateInfo2.StateInfoIndex) + if !tc.nothingFinalized { + suite.App.RollappKeeper.SetLatestFinalizedStateIndex(ctx, stateInfo.StateInfoIndex) } // add rollapp packets @@ -291,10 +240,7 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { suite.App.DelayedAckKeeper.SetRollappPacket(ctx, tc.packet2) // check invariant - _, failsFinalize := suite.App.DelayedAckKeeper.PacketsFinalizationCorrespondsToFinalizationHeight(suite.Ctx) - _, failsRevert := suite.App.DelayedAckKeeper.PacketsFromRevertedHeightsAreReverted(suite.Ctx) - - isBroken := failsFinalize || failsRevert + _, isBroken := dakeeper.PacketsFinalizationCorrespondsToFinalizationHeight(suite.App.DelayedAckKeeper)(suite.Ctx) suite.Require().Equal(tc.expectedIsBroken, isBroken) }) } diff --git a/x/delayedack/keeper/keeper.go b/x/delayedack/keeper/keeper.go index 2d656b630..5288adb12 100644 --- a/x/delayedack/keeper/keeper.go +++ b/x/delayedack/keeper/keeper.go @@ -12,14 +12,14 @@ import ( porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) type Keeper struct { - cdc codec.BinaryCodec - storeKey storetypes.StoreKey - hooks types.MultiDelayedAckHooks - paramstore paramtypes.Subspace + cdc codec.BinaryCodec + storeKey storetypes.StoreKey + channelKeeperStoreKey storetypes.StoreKey // we need direct access to the IBC channel store + hooks types.MultiDelayedAckHooks + paramstore paramtypes.Subspace rollappKeeper types.RollappKeeper porttypes.ICS4Wrapper @@ -30,6 +30,7 @@ type Keeper struct { func NewKeeper( cdc codec.BinaryCodec, storeKey storetypes.StoreKey, + channelKeeperStoreKey storetypes.StoreKey, ps paramtypes.Subspace, rollappKeeper types.RollappKeeper, ics4Wrapper porttypes.ICS4Wrapper, @@ -41,13 +42,14 @@ func NewKeeper( ps = ps.WithKeyTable(types.ParamKeyTable()) } return &Keeper{ - cdc: cdc, - storeKey: storeKey, - paramstore: ps, - rollappKeeper: rollappKeeper, - ICS4Wrapper: ics4Wrapper, - channelKeeper: channelKeeper, - EIBCKeeper: eibcKeeper, + cdc: cdc, + storeKey: storeKey, + channelKeeperStoreKey: channelKeeperStoreKey, + paramstore: ps, + rollappKeeper: rollappKeeper, + ICS4Wrapper: ics4Wrapper, + channelKeeper: channelKeeper, + EIBCKeeper: eibcKeeper, } } @@ -55,17 +57,6 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -func (k Keeper) getRollappFinalizedHeight(ctx sdk.Context, chainID string) (uint64, error) { - // GetLatestFinalizedStateIndex - latestFinalizedStateIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, chainID) - if !found { - return 0, rollapptypes.ErrNoFinalizedStateYetForRollapp - } - - stateInfo := k.rollappKeeper.MustGetStateInfo(ctx, chainID, latestFinalizedStateIndex.Index) - return stateInfo.StartHeight + stateInfo.NumBlocks - 1, nil -} - /* -------------------------------------------------------------------------- */ /* Hooks handling */ /* -------------------------------------------------------------------------- */ diff --git a/x/delayedack/keeper/rollapp_packet.go b/x/delayedack/keeper/rollapp_packet.go index 385cc16f1..4e56e7ace 100644 --- a/x/delayedack/keeper/rollapp_packet.go +++ b/x/delayedack/keeper/rollapp_packet.go @@ -1,11 +1,14 @@ package keeper import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" ) // SetRollappPacket stores a rollapp packet in the KVStore. @@ -165,7 +168,7 @@ func (k Keeper) GetAllRollappPackets(ctx sdk.Context) (list []commontypes.Rollap return list } -func (k Keeper) deleteRollappPacket(ctx sdk.Context, rollappPacket *commontypes.RollappPacket) error { +func (k Keeper) DeleteRollappPacket(ctx sdk.Context, rollappPacket *commontypes.RollappPacket) error { store := ctx.KVStore(k.storeKey) rollappPacketKey := rollappPacket.RollappPacketKey() store.Delete(rollappPacketKey) @@ -178,3 +181,25 @@ func (k Keeper) deleteRollappPacket(ctx sdk.Context, rollappPacket *commontypes. return nil } + +// GetPendingPacketsUntilFinalizedHeight returns all pending rollapp packets until the latest finalized height. +func (k Keeper) GetPendingPacketsUntilFinalizedHeight(ctx sdk.Context, rollappID string) ([]commontypes.RollappPacket, uint64, error) { + // Get rollapp's latest finalized height + latestFinalizedHeight, err := k.getRollappLatestFinalizedHeight(ctx, rollappID) + if err != nil { + return nil, 0, fmt.Errorf("get latest finalized height: rollapp '%s': %w", rollappID, err) + } + + // Get all pending rollapp packets until the latest finalized height + return k.ListRollappPackets(ctx, types.PendingByRollappIDByMaxHeight(rollappID, latestFinalizedHeight)), latestFinalizedHeight, nil +} + +func (k Keeper) getRollappLatestFinalizedHeight(ctx sdk.Context, rollappID string) (uint64, error) { + latestIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, rollappID) + if !found { + return 0, gerrc.ErrNotFound.Wrapf("latest finalized state index is not found") + } + + stateInfo := k.rollappKeeper.MustGetStateInfo(ctx, rollappID, latestIndex.Index) + return stateInfo.GetLatestHeight(), nil +} diff --git a/x/delayedack/keeper/rollapp_packet_test.go b/x/delayedack/keeper/rollapp_packet_test.go index e62354b8e..72a86ce0d 100644 --- a/x/delayedack/keeper/rollapp_packet_test.go +++ b/x/delayedack/keeper/rollapp_packet_test.go @@ -82,6 +82,10 @@ func (suite *DelayedAckTestSuite) TestRollappPacketEvents() { } } +// TestListRollappPackets tests the ListRollappPackets function +// we have 3 rollapps +// 2 pending packets, 3 finalized packets +// 2 onRecv packets, 2 onAck packets, 1 onTimeout packets func (suite *DelayedAckTestSuite) TestListRollappPackets() { keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx rollappIDs := []string{"testRollappID1", "testRollappID2", "testRollappID3"} @@ -89,7 +93,6 @@ func (suite *DelayedAckTestSuite) TestListRollappPackets() { sm := map[int]commontypes.Status{ 0: commontypes.Status_PENDING, 1: commontypes.Status_FINALIZED, - 2: commontypes.Status_REVERTED, } var packetsToSet []commontypes.RollappPacket @@ -106,7 +109,7 @@ func (suite *DelayedAckTestSuite) TestListRollappPackets() { Data: []byte("testData"), Sequence: uint64(i), }, - Status: sm[i%3], + Status: sm[i%2], Type: commontypes.RollappPacket_Type(i % 3), ProofHeight: uint64(6 - i), } @@ -123,50 +126,52 @@ func (suite *DelayedAckTestSuite) TestListRollappPackets() { packets := keeper.ListRollappPackets(ctx, types.ByRollappID(rollappIDs[0])) suite.Require().Equal(5, len(packets)) - expectPendingLength := 3 + expectPendingLength := 6 pendingPackets := keeper.ListRollappPackets(ctx, types.ByStatus(commontypes.Status_PENDING)) suite.Require().Equal(expectPendingLength, len(pendingPackets)) - expectFinalizedLength := 6 + expectFinalizedLength := 9 finalizedPackets := keeper.ListRollappPackets(ctx, types.ByStatus(commontypes.Status_FINALIZED)) suite.Require().Equal(expectFinalizedLength, len(finalizedPackets)) - expectRevertedLength := 6 - revertedPackets := keeper.ListRollappPackets(ctx, types.ByStatus(commontypes.Status_REVERTED)) - suite.Require().Equal(expectRevertedLength, len(revertedPackets)) + expectFinalizedLengthLimit := 4 + finalizedPacketsLimit := keeper.ListRollappPackets(ctx, types.ByStatus(commontypes.Status_FINALIZED).Take(4)) + suite.Require().Equal(expectFinalizedLengthLimit, len(finalizedPacketsLimit)) - expectRevertedLengthLimit := 4 - revertedPacketsLimit := keeper.ListRollappPackets(ctx, types.ByStatus(commontypes.Status_REVERTED).Take(4)) - suite.Require().Equal(expectRevertedLengthLimit, len(revertedPacketsLimit)) - - suite.Require().Equal(totalLength, len(pendingPackets)+len(finalizedPackets)+len(revertedPackets)) + suite.Require().Equal(totalLength, len(pendingPackets)+len(finalizedPackets)) rollappPacket1Finalized := keeper.ListRollappPackets(ctx, types.ByRollappIDByStatus(rollappIDs[0], commontypes.Status_FINALIZED)) rollappPacket2Pending := keeper.ListRollappPackets(ctx, types.ByRollappIDByStatus(rollappIDs[1], commontypes.Status_PENDING)) - rollappPacket3Reverted := keeper.ListRollappPackets(ctx, types.ByRollappIDByStatus(rollappIDs[2], commontypes.Status_REVERTED)) - suite.Require().Equal(2, len(rollappPacket1Finalized)) - suite.Require().Equal(1, len(rollappPacket2Pending)) - suite.Require().Equal(2, len(rollappPacket3Reverted)) + suite.Require().Equal(3, len(rollappPacket1Finalized)) + suite.Require().Equal(2, len(rollappPacket2Pending)) rollappPacket1MaxHeight4 := keeper.ListRollappPackets(ctx, types.PendingByRollappIDByMaxHeight(rollappIDs[0], 4)) - suite.Require().Equal(1, len(rollappPacket1MaxHeight4)) + suite.Require().Equal(2, len(rollappPacket1MaxHeight4)) rollappPacket2MaxHeight3 := keeper.ListRollappPackets(ctx, types.PendingByRollappIDByMaxHeight(rollappIDs[1], 3)) suite.Require().Equal(1, len(rollappPacket2MaxHeight3)) - expectOnRecvLength := 3 + expectOnRecvLength := 0 // i % 2 == 0 AND i % 3 == 0 onRecvPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_RECV, commontypes.Status_PENDING)) suite.Equal(expectOnRecvLength, len(onRecvPackets)) - expectOnAckLength := 6 + expectOnAckLength := 3 // i % 2 == 1 AND i % 3 == 1 (per rollapp) onAckPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_ACK, commontypes.Status_FINALIZED)) suite.Equal(expectOnAckLength, len(onAckPackets)) - expectOnTimeoutLength := 6 - onTimeoutPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_TIMEOUT, commontypes.Status_REVERTED)) + expectOnTimeoutLength := 3 // i % 2 == 1 AND i % 3 == 2 (per rollapp) + onTimeoutPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_TIMEOUT, commontypes.Status_FINALIZED)) suite.Equal(expectOnTimeoutLength, len(onTimeoutPackets)) - suite.Require().Equal(totalLength, len(onRecvPackets)+len(onAckPackets)+len(onTimeoutPackets)) + var totalCount int + for _, status := range sm { + onRecvPackets = keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_RECV, status)) + onAckPackets = keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_ACK, status)) + onTimeoutPackets = keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_TIMEOUT, status)) + totalCount += len(onRecvPackets) + len(onAckPackets) + len(onTimeoutPackets) + } + + suite.Require().Equal(totalLength, totalCount) } func (suite *DelayedAckTestSuite) TestUpdateRollappPacketWithStatus() { diff --git a/x/delayedack/keeper/transfer.go b/x/delayedack/keeper/transfer.go index 4e4db0b4d..fbb8cc6b8 100644 --- a/x/delayedack/keeper/transfer.go +++ b/x/delayedack/keeper/transfer.go @@ -6,7 +6,6 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" "github.com/dymensionxyz/gerr-cosmos/gerrc" ) @@ -46,8 +45,8 @@ func (k Keeper) GetValidTransferWithFinalizationInfo( return } - finalizedHeight, err := k.getRollappFinalizedHeight(ctx, data.Rollapp.RollappId) - if errorsmod.IsOf(err, rollapptypes.ErrNoFinalizedStateYetForRollapp) { + finalizedHeight, err := k.getRollappLatestFinalizedHeight(ctx, data.Rollapp.RollappId) + if errorsmod.IsOf(err, gerrc.ErrNotFound) { err = nil } else if err != nil { err = errorsmod.Wrap(err, "get rollapp finalized height") diff --git a/x/delayedack/rollapp_hooks.go b/x/delayedack/rollapp_hooks.go index 7a4a12a7a..ab9b01e5c 100644 --- a/x/delayedack/rollapp_hooks.go +++ b/x/delayedack/rollapp_hooks.go @@ -9,5 +9,5 @@ import ( var _ rollapptypes.RollappHooks = &IBCMiddleware{} func (w IBCMiddleware) OnHardFork(ctx sdk.Context, rollappID string, height uint64) error { - return w.HandleFraud(ctx, rollappID, w.IBCModule) + return w.HandleHardFork(ctx, rollappID, height, w.IBCModule) } diff --git a/x/delayedack/types/rollapp_packets_list_filter.go b/x/delayedack/types/rollapp_packets_list_filter.go index 034cff45f..b921b71e9 100644 --- a/x/delayedack/types/rollapp_packets_list_filter.go +++ b/x/delayedack/types/rollapp_packets_list_filter.go @@ -1,6 +1,8 @@ package types import ( + math "math" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" ) @@ -33,6 +35,18 @@ func PendingByRollappIDByMaxHeight( } } +func PendingByRollappIDFromHeight(rollappID string, fromHeight uint64) RollappPacketListFilter { + return RollappPacketListFilter{ + Prefixes: []Prefix{ + { + Start: commontypes.RollappPacketByStatusByRollappIDByProofHeightPrefix(rollappID, commontypes.Status_PENDING, fromHeight), + End: commontypes.RollappPacketByStatusByRollappIDByProofHeightPrefix(rollappID, commontypes.Status_PENDING, math.MaxUint64), + }, + }, + FilterFunc: bypassFilter, + } +} + func ByRollappIDByStatus(rollappID string, status ...commontypes.Status) RollappPacketListFilter { prefixes := make([]Prefix, len(status)) for i, s := range status { @@ -58,7 +72,6 @@ func ByRollappID(rollappID string) RollappPacketListFilter { return ByRollappIDByStatus(rollappID, commontypes.Status_PENDING, commontypes.Status_FINALIZED, - commontypes.Status_REVERTED, ) } diff --git a/x/delayedack/types/rollapp_packets_list_filter_test.go b/x/delayedack/types/rollapp_packets_list_filter_test.go index 4e7b9ce5b..2bbe33b21 100644 --- a/x/delayedack/types/rollapp_packets_list_filter_test.go +++ b/x/delayedack/types/rollapp_packets_list_filter_test.go @@ -29,8 +29,6 @@ func TestByRollappID(t *testing.T) { Start: []uint8{0x00, 0x01, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f}, }, { Start: []uint8{0x00, 0x02, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f}, - }, { - Start: []uint8{0x00, 0x03, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f}, }, }, }, { @@ -43,8 +41,6 @@ func TestByRollappID(t *testing.T) { Start: []uint8{0x00, 0x01, 0x2f, 0x2f}, }, { Start: []uint8{0x00, 0x02, 0x2f, 0x2f}, - }, { - Start: []uint8{0x00, 0x03, 0x2f, 0x2f}, }, }, }, @@ -89,17 +85,6 @@ func TestByRollappIDByStatus(t *testing.T) { Start: []uint8{0x00, 0x02, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f}, }, }, - }, { - name: "Test with rollappID 1 and status REVERTED", - args: args{ - rollappID: "testRollappID1", - status: []commontypes.Status{commontypes.Status_REVERTED}, - }, - want: []types.Prefix{ - { - Start: []uint8{0x00, 0x03, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f}, - }, - }, }, { name: "Test with rollappID 1 and status PENDING, FINALIZED", args: args{ @@ -163,16 +148,6 @@ func TestByStatus(t *testing.T) { Start: []uint8{0x00, 0x02, 0x2f}, }, }, - }, { - name: "Test with status REVERTED", - args: args{ - status: []commontypes.Status{commontypes.Status_REVERTED}, - }, - want: []types.Prefix{ - { - Start: []uint8{0x00, 0x03, 0x2f}, - }, - }, }, } for _, tt := range tests { @@ -282,6 +257,64 @@ func TestByType(t *testing.T) { } } +func TestPendingByRollappIDFromHeight(t *testing.T) { + type args struct { + rollappID string + fromHeight uint64 + } + tests := []struct { + name string + args args + want []types.Prefix + }{ + { + name: "Test with rollappID 1 and fromHeight 100", + args: args{ + rollappID: "testRollappID1", + fromHeight: 100, + }, + want: []types.Prefix{ + { + Start: []uint8{0x00, 0x01, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64}, + End: []uint8{0x00, 0x01, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, + }, + }, + { + name: "Test with empty rollappID and fromHeight 50", + args: args{ + rollappID: "", + fromHeight: 50, + }, + want: []types.Prefix{ + { + Start: []uint8{0x0, 0x1, 0x2f, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32}, + End: []uint8{0x0, 0x1, 0x2f, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, + }, + }, + { + name: "Test with rollappID 2 and fromHeight 0", + args: args{ + rollappID: "testRollappID2", + fromHeight: 0, + }, + want: []types.Prefix{ + { + Start: []uint8{0x0, 0x1, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x32, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + End: []uint8{0x0, 0x1, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x32, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + filter := types.PendingByRollappIDFromHeight(tt.args.rollappID, tt.args.fromHeight) + require.Equal(t, tt.want, filter.Prefixes) + }) + } +} + var testRollappPackets = []commontypes.RollappPacket{ { RollappId: "rollapp-id-1", diff --git a/x/eibc/client/cli/query_command_orders.go b/x/eibc/client/cli/query_command_orders.go index 18622c574..8e320a222 100644 --- a/x/eibc/client/cli/query_command_orders.go +++ b/x/eibc/client/cli/query_command_orders.go @@ -18,7 +18,7 @@ func CmdListDemandOrdersByStatus() *cobra.Command { cmd := &cobra.Command{ Use: "list-demand-orders status [rollapp] [recipient] [type] [denom] [fulfilled] [fulfiller] [limit]", Short: "List all demand orders with a specific status", - Long: `Query demand orders filtered by status. Examples of status include "pending", "finalized", and "reverted". + Long: `Query demand orders filtered by status. Status can "pending" or "finalized". Optional arguments include rollapp_id, type (recv, timeout, ack), and limit.`, Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/x/eibc/genesis_test.go b/x/eibc/genesis_test.go index 5b2ac0545..0f1b1ac7f 100644 --- a/x/eibc/genesis_test.go +++ b/x/eibc/genesis_test.go @@ -33,7 +33,7 @@ func TestInitGenesis(t *testing.T) { Fee: sdk.Coins{sdk.Coin{Denom: "adym", Amount: math.NewInt(150)}}, Recipient: "dym15saxgqw6kvhv6k5sg6r45kmdf4sf88kfw2adcw", FulfillerAddress: "dym19pas0pqwje540u5ptwnffjxeamdxc9tajmdrfa", - TrackingPacketStatus: commontypes.Status_REVERTED, + TrackingPacketStatus: commontypes.Status_FINALIZED, }, }, } diff --git a/x/eibc/keeper/grpc_query.go b/x/eibc/keeper/grpc_query.go index f48758bd1..cd5ffe691 100644 --- a/x/eibc/keeper/grpc_query.go +++ b/x/eibc/keeper/grpc_query.go @@ -41,7 +41,7 @@ func (q Querier) DemandOrderById(goCtx context.Context, req *types.QueryGetDeman // Get the demand order by its ID and search for it in all statuses var demandOrder *types.DemandOrder var err error - statuses := []commontypes.Status{commontypes.Status_PENDING, commontypes.Status_FINALIZED, commontypes.Status_REVERTED} + statuses := []commontypes.Status{commontypes.Status_PENDING, commontypes.Status_FINALIZED} for _, status := range statuses { demandOrder, err = q.GetDemandOrder(ctx, status, req.Id) if err == nil && demandOrder != nil { diff --git a/x/eibc/keeper/grpc_query_test.go b/x/eibc/keeper/grpc_query_test.go index a54925e9b..4d340a9cd 100644 --- a/x/eibc/keeper/grpc_query_test.go +++ b/x/eibc/keeper/grpc_query_test.go @@ -51,7 +51,7 @@ func (suite *KeeperTestSuite) TestQueryDemandOrdersByStatus() { demandOrderAddresses := apptesting.AddTestAddrs(suite.App, suite.Ctx, demandOrdersNum, math.NewInt(1000)) // Define statuses to test - statuses := []commontypes.Status{commontypes.Status_PENDING, commontypes.Status_REVERTED, commontypes.Status_FINALIZED} + statuses := []commontypes.Status{commontypes.Status_PENDING, commontypes.Status_FINALIZED} // Create and set demand orders for each status for i, status := range statuses { diff --git a/x/eibc/keeper/hooks.go b/x/eibc/keeper/hooks.go index 67e67bc39..9b75215be 100644 --- a/x/eibc/keeper/hooks.go +++ b/x/eibc/keeper/hooks.go @@ -65,8 +65,7 @@ func (d delayedAckHooks) AfterPacketDeleted(ctx sdk.Context, rollappPacket *comm packetKey := rollappPacket.RollappPacketKey() demandOrderID := types.BuildDemandIDFromPacketKey(string(packetKey)) - // Check for demand order in both FINALIZED and REVERTED statuses - statuses := []commontypes.Status{commontypes.Status_FINALIZED, commontypes.Status_REVERTED} + statuses := []commontypes.Status{commontypes.Status_PENDING, commontypes.Status_FINALIZED} for _, status := range statuses { demandOrder, err := d.GetDemandOrder(ctx, status, demandOrderID) if err != nil { diff --git a/x/eibc/keeper/hooks_test.go b/x/eibc/keeper/hooks_test.go index 029676c16..54aded6f8 100644 --- a/x/eibc/keeper/hooks_test.go +++ b/x/eibc/keeper/hooks_test.go @@ -38,13 +38,13 @@ func (suite *KeeperTestSuite) TestAfterRollappPacketDeleted() { expectedError error }{ { - name: "Finalized packet", - packetStatus: commontypes.Status_FINALIZED, + name: "Pending packet", + packetStatus: commontypes.Status_PENDING, expectedError: types.ErrDemandOrderDoesNotExist, }, { - name: "Reverted packet", - packetStatus: commontypes.Status_REVERTED, + name: "Finalized packet", + packetStatus: commontypes.Status_FINALIZED, expectedError: types.ErrDemandOrderDoesNotExist, }, } @@ -64,13 +64,8 @@ func (suite *KeeperTestSuite) TestAfterRollappPacketDeleted() { _, err = suite.App.DelayedAckKeeper.UpdateRollappPacketWithStatus(suite.Ctx, *rollappPacket, tc.packetStatus) suite.Require().NoError(err) - // Trigger the delayed ack hook which should delete the rollapp packet and the demand order - epochIdentifier := "minute" - defParams := delayedacktypes.DefaultParams() - defParams.EpochIdentifier = epochIdentifier - suite.App.DelayedAckKeeper.SetParams(suite.Ctx, defParams) - hooks := suite.App.DelayedAckKeeper.GetEpochHooks() - err = hooks.AfterEpochEnd(suite.Ctx, epochIdentifier, 1) + // delete the rollapp packet + err = suite.App.DelayedAckKeeper.DeleteRollappPacket(suite.Ctx, rollappPacket) suite.Require().NoError(err) // Verify that the rollapp packet and demand order are deleted diff --git a/x/eibc/keeper/invariants.go b/x/eibc/keeper/invariants.go index 437c70a82..82e62edef 100644 --- a/x/eibc/keeper/invariants.go +++ b/x/eibc/keeper/invariants.go @@ -35,20 +35,15 @@ func DemandOrderCountInvariant(k Keeper) sdk.Invariant { msg += fmt.Sprintf("list pending demand orders failed: %v\n", err) broken = true } - revertedDemandOrders, err := k.ListDemandOrdersByStatus(ctx, commontypes.Status_REVERTED, 0) - if err != nil { - msg += fmt.Sprintf("list reverted demand orders failed: %v\n", err) - broken = true - } finalizedDemandOrders, err := k.ListDemandOrdersByStatus(ctx, commontypes.Status_FINALIZED, 0) if err != nil { msg += fmt.Sprintf("list finalized demand orders failed: %v\n", err) broken = true } // Validate the count of demand orders is equal to the sum of demand orders in all statuses - if len(allDemandOrders) != len(pendingDemandOrders)+len(revertedDemandOrders)+len(finalizedDemandOrders) { - msg += fmt.Sprintf("demand orders count mismatch: all(%d) != pending(%d) + reverted(%d) + finalized(%d)\n", - len(allDemandOrders), len(pendingDemandOrders), len(revertedDemandOrders), len(finalizedDemandOrders)) + if len(allDemandOrders) != len(pendingDemandOrders)+len(finalizedDemandOrders) { + msg += fmt.Sprintf("demand orders count mismatch: all(%d) != pending(%d) + finalized(%d)\n", + len(allDemandOrders), len(pendingDemandOrders), len(finalizedDemandOrders)) broken = true } return sdk.FormatInvariant(types.ModuleName, demandOrderCountInvariantName, msg), broken diff --git a/x/eibc/keeper/invariants_test.go b/x/eibc/keeper/invariants_test.go index f220c872a..a02df8c44 100644 --- a/x/eibc/keeper/invariants_test.go +++ b/x/eibc/keeper/invariants_test.go @@ -18,12 +18,10 @@ func (suite *KeeperTestSuite) TestInvariants() { // Create and set some demand orders with status pending for i := 0; i < demandOrdersNum; i++ { var status commontypes.Status - switch i % 3 { + switch i % 2 { case 0: status = commontypes.Status_PENDING case 1: - status = commontypes.Status_REVERTED - case 2: status = commontypes.Status_FINALIZED } rollappPacket := &commontypes.RollappPacket{ diff --git a/x/eibc/keeper/keeper.go b/x/eibc/keeper/keeper.go index eb0c74f2c..4e248697f 100644 --- a/x/eibc/keeper/keeper.go +++ b/x/eibc/keeper/keeper.go @@ -178,8 +178,6 @@ func (k Keeper) ListDemandOrdersByStatus(ctx sdk.Context, status commontypes.Sta statusPrefix = types.PendingDemandOrderKeyPrefix case commontypes.Status_FINALIZED: statusPrefix = types.FinalizedDemandOrderKeyPrefix - case commontypes.Status_REVERTED: - statusPrefix = types.RevertedDemandOrderKeyPrefix default: return nil, fmt.Errorf("invalid packet status: %s", status) } diff --git a/x/eibc/types/keys.go b/x/eibc/types/keys.go index 0fe1b4380..e44e789b7 100644 --- a/x/eibc/types/keys.go +++ b/x/eibc/types/keys.go @@ -34,8 +34,6 @@ var ( PendingDemandOrderKeyPrefix = []byte{0x00, 0x01} // FinalizedDemandOrderKeyPrefix is the prefix for finalized demand orders FinalizedDemandOrderKeyPrefix = []byte{0x00, 0x02} - // RevertedDemandOrderKeyPrefix is the prefix for reverted demand orders - RevertedDemandOrderKeyPrefix = []byte{0x00, 0x03} ) // GetDemandOrderKey constructs a key for a specific DemandOrder. @@ -47,8 +45,6 @@ func GetDemandOrderKey(packetStatus commontypes.Status, orderId string) ([]byte, prefix = PendingDemandOrderKeyPrefix case commontypes.Status_FINALIZED: prefix = FinalizedDemandOrderKeyPrefix - case commontypes.Status_REVERTED: - prefix = RevertedDemandOrderKeyPrefix default: return nil, fmt.Errorf("invalid packet status: %s", packetStatus) }