diff --git a/x/delayedack/keeper/invariants.go b/x/delayedack/keeper/invariants.go index 1bd83bc13..085e76843 100644 --- a/x/delayedack/keeper/invariants.go +++ b/x/delayedack/keeper/invariants.go @@ -32,41 +32,33 @@ func AllInvariants(k Keeper) sdk.Invariant { // RollappFinalizedPackets checks that all rollapp packets stored for a rollapp finalized height are also finalized func RollappFinalizedPackets(k Keeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { - var ( - broken bool - msg string - ) + var msg string packets := k.GetAllRollappPackets(ctx) for _, packet := range packets { latestFinalizedStateIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, packet.RollappId) if !found { - msg += fmt.Sprintf("unable to find latest finalized state index for rollapp %s\n", packet.RollappId) - broken = true + continue } latestFinalizedStateInfo, found := k.rollappKeeper.GetStateInfo(ctx, packet.RollappId, latestFinalizedStateIndex.Index) if !found { - msg += fmt.Sprintf("unable to find latest finalized state info for rollapp %s\n", packet.RollappId) - broken = true + continue } latestFinalizedHeight := latestFinalizedStateInfo.StartHeight + latestFinalizedStateInfo.NumBlocks - 1 if packet.ProofHeight <= latestFinalizedHeight && packet.Status != commontypes.Status_FINALIZED { msg += fmt.Sprintf("rollapp packet for height %d from rollapp %s should be in finalized status, but is in %s status\n", packet.ProofHeight, packet.RollappId, packet.Status) - broken = true + return msg, true } } - return msg, broken + return msg, false } } // RollappRevertedPackets checks that all rollapp packets stored for a rollapp reverted height are also reverted func RollappRevertedPackets(k Keeper) sdk.Invariant { return func(ctx sdk.Context) (string, bool) { - var ( - broken bool - msg string - ) + var msg string rollapps := k.rollappKeeper.GetAllRollapps(ctx) @@ -87,7 +79,7 @@ func RollappRevertedPackets(k Keeper) sdk.Invariant { if packet.RollappId == rollapp.RollappId { if packet.ProofHeight >= stateInfoToCheck.StartHeight && packet.ProofHeight < stateInfoToCheck.StartHeight+stateInfoToCheck.NumBlocks && packet.Status != commontypes.Status_REVERTED { msg += fmt.Sprintf("rollapp packet for height %d from rollapp %s should be in reverted status, but is in %s status\n", packet.ProofHeight, packet.RollappId, packet.Status) - broken = true + return msg, true } } } @@ -99,6 +91,6 @@ func RollappRevertedPackets(k Keeper) sdk.Invariant { } } - return msg, broken + return msg, false } } diff --git a/x/delayedack/keeper/invariants_test.go b/x/delayedack/keeper/invariants_test.go index fcd70681a..8725069fd 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -6,6 +6,8 @@ import ( channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" + "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) func (suite *DelayedAckTestSuite) TestInvariants() { @@ -81,3 +83,198 @@ func (suite *DelayedAckTestSuite) TestInvariants() { msg, bool := keeper.AllInvariants(suite.App.DelayedAckKeeper)(suite.Ctx) suite.Require().False(bool, msg) } + +func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { + suite.SetupTest() + ctx := suite.Ctx + rollapp := "rollapp1" + cases := []struct { + name string + rollappId string + stateInfo *rollapptypes.StateInfo + stateInfo2 *rollapptypes.StateInfo + packet commontypes.RollappPacket + packet2 commontypes.RollappPacket + expectedIsBroken bool + }{ + { + "successful invariant check", + rollapp, + &rollapptypes.StateInfo{ + StateInfoIndex: rollapptypes.StateInfoIndex{ + RollappId: rollapp, + Index: 1, + }, + StartHeight: 1, + NumBlocks: 10, + Status: commontypes.Status_FINALIZED, + }, + &rollapptypes.StateInfo{ + StateInfoIndex: rollapptypes.StateInfoIndex{ + RollappId: rollapp, + Index: 2, + }, + StartHeight: 10, + NumBlocks: 10, + Status: commontypes.Status_PENDING, + }, + commontypes.RollappPacket{ + RollappId: rollapp, + Status: commontypes.Status_FINALIZED, + ProofHeight: 5, + Packet: &channeltypes.Packet{ + SourcePort: "testSourcePort", + SourceChannel: "testSourceChannel", + DestinationPort: "testDestinationPort", + DestinationChannel: "testDestinationChannel", + Data: []byte("testData"), + Sequence: uint64(1), + }, + }, + commontypes.RollappPacket{ + RollappId: rollapp, + Status: commontypes.Status_PENDING, + ProofHeight: 15, + Packet: &channeltypes.Packet{ + SourcePort: "testSourcePort", + SourceChannel: "testSourceChannel", + DestinationPort: "testDestinationPort", + DestinationChannel: "testDestinationChannel", + Data: []byte("testData"), + Sequence: uint64(2), + }, + }, + false, + }, + { + "error non-finalized packet", + rollapp, + &rollapptypes.StateInfo{ + StateInfoIndex: rollapptypes.StateInfoIndex{ + RollappId: rollapp, + Index: 1, + }, + StartHeight: 1, + NumBlocks: 10, + Status: commontypes.Status_FINALIZED, + }, + &rollapptypes.StateInfo{ + StateInfoIndex: rollapptypes.StateInfoIndex{ + RollappId: rollapp, + Index: 2, + }, + StartHeight: 10, + NumBlocks: 10, + Status: commontypes.Status_FINALIZED, + }, + commontypes.RollappPacket{ + RollappId: rollapp, + Status: commontypes.Status_FINALIZED, + ProofHeight: 5, + Packet: &channeltypes.Packet{ + SourcePort: "testSourcePort", + SourceChannel: "testSourceChannel", + DestinationPort: "testDestinationPort", + DestinationChannel: "testDestinationChannel", + Data: []byte("testData"), + Sequence: uint64(1), + }, + }, + commontypes.RollappPacket{ + RollappId: rollapp, + Status: commontypes.Status_PENDING, + ProofHeight: 15, + Packet: &channeltypes.Packet{ + SourcePort: "testSourcePort", + SourceChannel: "testSourceChannel", + DestinationPort: "testDestinationPort", + DestinationChannel: "testDestinationChannel", + Data: []byte("testData"), + Sequence: uint64(2), + }, + }, + true, + }, + { + "wrong invariant revert check", + rollapp, + &rollapptypes.StateInfo{ + StateInfoIndex: rollapptypes.StateInfoIndex{ + RollappId: rollapp, + Index: 1, + }, + StartHeight: 1, + NumBlocks: 10, + Status: commontypes.Status_FINALIZED, + }, + &rollapptypes.StateInfo{ + StateInfoIndex: rollapptypes.StateInfoIndex{ + RollappId: rollapp, + Index: 2, + }, + StartHeight: 10, + NumBlocks: 10, + Status: commontypes.Status_REVERTED, + }, + commontypes.RollappPacket{ + RollappId: rollapp, + Status: commontypes.Status_FINALIZED, + ProofHeight: 5, + Packet: &channeltypes.Packet{ + SourcePort: "testSourcePort", + SourceChannel: "testSourceChannel", + DestinationPort: "testDestinationPort", + DestinationChannel: "testDestinationChannel", + Data: []byte("testData"), + Sequence: uint64(1), + }, + }, + commontypes.RollappPacket{ + RollappId: rollapp, + Status: commontypes.Status_PENDING, + ProofHeight: 15, + Packet: &channeltypes.Packet{ + SourcePort: "testSourcePort", + SourceChannel: "testSourceChannel", + DestinationPort: "testDestinationPort", + DestinationChannel: "testDestinationChannel", + Data: []byte("testData"), + Sequence: uint64(2), + }, + }, + true, + }, + } + for _, tc := range cases { + suite.Run(tc.name, func() { + // create rollapp + suite.CreateRollappWithName(tc.rollappId) + // update state infos + suite.App.RollappKeeper.SetStateInfo(ctx, *tc.stateInfo) + if tc.stateInfo.Status == commontypes.Status_FINALIZED { + suite.App.RollappKeeper.SetLatestFinalizedStateIndex(ctx, types.StateInfoIndex{ + RollappId: tc.rollappId, + Index: tc.stateInfo.GetIndex().Index, + }) + } + suite.App.RollappKeeper.SetStateInfo(ctx, *tc.stateInfo2) + if tc.stateInfo2.Status == commontypes.Status_FINALIZED { + suite.App.RollappKeeper.SetLatestFinalizedStateIndex(ctx, types.StateInfoIndex{ + RollappId: tc.rollappId, + Index: tc.stateInfo2.GetIndex().Index, + }) + } + suite.App.RollappKeeper.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ + RollappId: tc.rollappId, + Index: tc.stateInfo2.GetIndex().Index, + }) + + suite.App.DelayedAckKeeper.SetRollappPacket(ctx, tc.packet) + suite.App.DelayedAckKeeper.SetRollappPacket(ctx, tc.packet2) + + // check invariant + _, isBroken := keeper.AllInvariants(suite.App.DelayedAckKeeper)(suite.Ctx) + suite.Require().Equal(tc.expectedIsBroken, isBroken) + }) + } +}