diff --git a/app/ante/reject_msgs.go b/app/ante/reject_msgs.go index 688d851e9..dfafe543f 100644 --- a/app/ante/reject_msgs.go +++ b/app/ante/reject_msgs.go @@ -1,6 +1,7 @@ package ante import ( + "errors" "fmt" errorsmod "cosmossdk.io/errors" @@ -59,7 +60,7 @@ func (rmd RejectMessagesDecorator) AnteHandle( next sdk.AnteHandler, ) (sdk.Context, error) { if err := rmd.checkMsgs(ctx, tx.GetMsgs(), 0); err != nil { - return ctx, errorsmod.Wrapf(sdkerrors.ErrUnauthorized, err.Error()) + return ctx, errors.Join(sdkerrors.ErrUnauthorized, err) } return next(ctx, tx, simulate) } diff --git a/app/apptesting/delayedack.go b/app/apptesting/delayedack.go index 943728a23..4722b2db5 100644 --- a/app/apptesting/delayedack.go +++ b/app/apptesting/delayedack.go @@ -41,7 +41,7 @@ func GenerateTestPacket(t *testing.T, sequence uint64) *channeltypes.Packet { func GenerateRollappPackets(t *testing.T, rollappId string, num uint64) []commontypes.RollappPacket { t.Helper() 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: GenerateTestPacket(t, i), diff --git a/app/apptesting/test_suite.go b/app/apptesting/test_suite.go index cb30fee66..04af4e1c5 100644 --- a/app/apptesting/test_suite.go +++ b/app/apptesting/test_suite.go @@ -78,7 +78,7 @@ func (s *KeeperTestHelper) CreateRollappByName(name string) { s.FundForAliasRegistration(msgCreateRollapp) - msgServer := rollappkeeper.NewMsgServerImpl(*s.App.RollappKeeper) + msgServer := rollappkeeper.NewMsgServerImpl(s.App.RollappKeeper) _, err := msgServer.CreateRollapp(s.Ctx, &msgCreateRollapp) s.Require().NoError(err) } @@ -135,7 +135,7 @@ func (s *KeeperTestHelper) PostStateUpdateWithDRSVersion(ctx sdk.Context, rollap BDs: bds, Last: false, } - msgServer := rollappkeeper.NewMsgServerImpl(*s.App.RollappKeeper) + msgServer := rollappkeeper.NewMsgServerImpl(s.App.RollappKeeper) _, err = msgServer.UpdateState(ctx, &updateState) return startHeight + numOfBlocks, err } diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 26bf98cfe..a3f5be78b 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -89,7 +89,6 @@ import ( lightclientmoduletypes "github.com/dymensionxyz/dymension/v3/x/lightclient/types" lockupkeeper "github.com/dymensionxyz/dymension/v3/x/lockup/keeper" lockuptypes "github.com/dymensionxyz/dymension/v3/x/lockup/types" - rollappmodule "github.com/dymensionxyz/dymension/v3/x/rollapp" "github.com/dymensionxyz/dymension/v3/x/rollapp/genesisbridge" rollappmodulekeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" rollappmoduletypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" @@ -348,17 +347,11 @@ func (a *AppKeepers) InitKeepers( a.ScopedIBCKeeper, ) - a.DenomMetadataKeeper = denommetadatamodulekeeper.NewKeeper( - a.BankKeeper, - ) - a.RollappKeeper = rollappmodulekeeper.NewKeeper( appCodec, a.keys[rollappmoduletypes.StoreKey], a.GetSubspace(rollappmoduletypes.ModuleName), - a.AccountKeeper, a.IBCKeeper.ChannelKeeper, - a.IBCKeeper.ClientKeeper, nil, a.BankKeeper, a.TransferKeeper, @@ -403,6 +396,11 @@ func (a *AppKeepers) InitKeepers( a.RollappKeeper.SetSequencerKeeper(a.SequencerKeeper) a.RollappKeeper.SetCanonicalClientKeeper(a.LightClientKeeper) + a.DenomMetadataKeeper = denommetadatamodulekeeper.NewKeeper( + a.BankKeeper, + a.RollappKeeper, + ) + a.IncentivesKeeper = incentiveskeeper.NewKeeper( a.keys[incentivestypes.StoreKey], a.GetSubspace(incentivestypes.ModuleName), @@ -484,6 +482,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, @@ -503,7 +502,6 @@ func (a *AppKeepers) InitKeepers( AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(a.UpgradeKeeper)). AddRoute(ibcclienttypes.RouterKey, ibcclient.NewClientProposalHandler(a.IBCKeeper.ClientKeeper)). AddRoute(streamermoduletypes.RouterKey, streamermodule.NewStreamerProposalHandler(a.StreamerKeeper)). - AddRoute(rollappmoduletypes.RouterKey, rollappmodule.NewRollappProposalHandler(a.RollappKeeper)). AddRoute(denommetadatamoduletypes.RouterKey, denommetadatamodule.NewDenomMetadataProposalHandler(a.DenomMetadataKeeper)). AddRoute(dymnstypes.RouterKey, dymnsmodule.NewDymNsProposalHandler(a.DymNSKeeper)). AddRoute(evmtypes.RouterKey, evm.NewEvmProposalHandler(a.EvmKeeper)) @@ -628,11 +626,12 @@ func (a *AppKeepers) SetupHooks() { a.RollappKeeper.SetHooks(rollappmoduletypes.NewMultiRollappHooks( // insert rollapp hooks receivers here a.SequencerKeeper.RollappHooks(), - a.delayedAckMiddleware, + a.DelayedAckKeeper, a.StreamerKeeper.Hooks(), a.DymNSKeeper.GetRollAppHooks(), a.LightClientKeeper.RollappHooks(), a.IROKeeper, + a.DenomMetadataKeeper.RollappHooks(), )) } diff --git a/app/keepers/modules.go b/app/keepers/modules.go index be3cd11b3..6e4aa0f15 100644 --- a/app/keepers/modules.go +++ b/app/keepers/modules.go @@ -98,7 +98,6 @@ import ( lightclientmodule "github.com/dymensionxyz/dymension/v3/x/lightclient" lightclientmoduletypes "github.com/dymensionxyz/dymension/v3/x/lightclient/types" "github.com/dymensionxyz/dymension/v3/x/rollapp" - rollappmoduleclient "github.com/dymensionxyz/dymension/v3/x/rollapp/client" rollappmoduletypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" "github.com/dymensionxyz/dymension/v3/x/sequencer" sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" @@ -130,7 +129,6 @@ var ModuleBasics = module.NewBasicManager( streamermoduleclient.TerminateStreamHandler, streamermoduleclient.ReplaceStreamHandler, streamermoduleclient.UpdateStreamHandler, - rollappmoduleclient.SubmitFraudHandler, denommetadatamoduleclient.CreateDenomMetadataHandler, denommetadatamoduleclient.UpdateDenomMetadataHandler, dymnsmoduleclient.MigrateChainIdsProposalHandler, diff --git a/app/upgrades/v4/upgrade.go b/app/upgrades/v4/upgrade.go index 8b6f08942..677ff49ae 100644 --- a/app/upgrades/v4/upgrade.go +++ b/app/upgrades/v4/upgrade.go @@ -317,7 +317,6 @@ func ConvertOldRollappToNew(oldRollapp rollapptypes.Rollapp) rollapptypes.Rollap Owner: oldRollapp.Owner, GenesisState: oldRollapp.GenesisState, ChannelId: oldRollapp.ChannelId, - Frozen: oldRollapp.Frozen, Metadata: &rollapptypes.RollappMetadata{ // Can be updated in runtime Website: "", Description: "", @@ -336,6 +335,8 @@ func ConvertOldRollappToNew(oldRollapp rollapptypes.Rollapp) rollapptypes.Rollap PreLaunchTime: nil, // We can just let it be zero. Existing rollapps are already launched. LivenessEventHeight: 0, // Filled lazily in runtime LastStateUpdateHeight: 0, // Filled lazily in runtime + RevisionNumber: 0, + RevisionStartHeight: 0, } } diff --git a/ibctesting/bridging_fee_test.go b/ibctesting/bridging_fee_test.go index a149c02c7..aba3dbf78 100644 --- a/ibctesting/bridging_fee_test.go +++ b/ibctesting/bridging_fee_test.go @@ -19,6 +19,11 @@ func TestBridgingFeeTestSuite(t *testing.T) { suite.Run(t, new(bridgingFeeSuite)) } +func (s *bridgingFeeSuite) SetupTest() { + s.utilSuite.SetupTest() + s.hubApp().LightClientKeeper.SetEnabled(false) +} + func (s *bridgingFeeSuite) TestNotRollappNoBridgingFee() { // setup between cosmosChain and hubChain path := s.newTransferPath(s.hubChain(), s.cosmosChain()) diff --git a/ibctesting/delayed_ack_test.go b/ibctesting/delayed_ack_test.go index 90116a539..95e7d9969 100644 --- a/ibctesting/delayed_ack_test.go +++ b/ibctesting/delayed_ack_test.go @@ -7,7 +7,12 @@ import ( banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + ibcmerkle "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" ibctesting "github.com/cosmos/ibc-go/v7/testing" + "github.com/cosmos/ibc-go/v7/testing/simapp" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" ) @@ -25,6 +30,8 @@ func TestDelayedAckTestSuite(t *testing.T) { func (s *delayedAckSuite) SetupTest() { s.utilSuite.SetupTest() + s.hubApp().LightClientKeeper.SetEnabled(false) + s.hubApp().BankKeeper.SetDenomMetaData(s.hubCtx(), banktypes.Metadata{ Base: sdk.DefaultBondDenom, }) @@ -235,3 +242,110 @@ func (s *delayedAckSuite) TestHubToRollappTimeout() { postFinalizeBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) s.Require().Equal(preSendBalance.Amount, postFinalizeBalance.Amount) } + +// TestHardFork tests the hard fork handling for outgoing packets from the hub to the rollapp. +// we assert the packets commitments are restored and the pending packets are ackable after the hard fork. +func (s *delayedAckSuite) TestHardFork_HubToRollapp() { + path := s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.Setup(path) + + // Setup endpoints + var ( + hubEndpoint = path.EndpointA + hubIBCKeeper = s.hubChain().App.GetIBCKeeper() + senderAccount = s.hubChain().SenderAccount.GetAddress() + receiverAccount = s.rollappChain().SenderAccount.GetAddress() + + amount, _ = sdk.NewIntFromString("1000000000000000000") // 1DYM + coinToSendToB = sdk.NewCoin(sdk.DefaultBondDenom, amount) + timeoutHeight = clienttypes.Height{RevisionNumber: 1, RevisionHeight: 50} + ) + + // Create rollapp and update its initial state + s.createRollappWithFinishedGenesis(path.EndpointA.ChannelID) + s.setRollappLightClientID(s.rollappCtx().ChainID(), path.EndpointA.ClientID) + s.registerSequencer() + s.updateRollappState(uint64(s.rollappCtx().BlockHeight())) + + // send from hubChain to rollappChain + balanceBefore := s.hubApp().BankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) + msg := types.NewMsgTransfer(hubEndpoint.ChannelConfig.PortID, hubEndpoint.ChannelID, coinToSendToB, senderAccount.String(), receiverAccount.String(), timeoutHeight, disabledTimeoutTimestamp, "") + res, err := s.hubChain().SendMsgs(msg) + s.Require().NoError(err) + packet, err := ibctesting.ParsePacketFromEvents(res.GetEvents()) + s.Require().NoError(err) + + // assert commitments are created + found := hubIBCKeeper.ChannelKeeper.HasPacketCommitment(s.hubCtx(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + s.Require().True(found) + + // Update the client + err = hubEndpoint.UpdateClient() + s.Require().NoError(err) + + err = path.RelayPacket(packet) + s.Require().NoError(err) // expecting error as no AcknowledgePacket expected to return + + // progress the rollapp chain + s.coordinator.CommitNBlocks(s.rollappChain(), 110) + + // Update the client + err = hubEndpoint.UpdateClient() + s.Require().NoError(err) + + // write ack optimistically + err = path.EndpointA.AcknowledgePacket(packet, []byte{0x1}) + s.Require().NoError(err) + + // assert commitments are no longer available + found = hubIBCKeeper.ChannelKeeper.HasPacketCommitment(s.hubCtx(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + s.Require().False(found) + + // timeout the packet, can't check for error (ErrNoOp). we assert the balance refund + err = path.EndpointA.TimeoutPacket(packet) + s.Require().NoError(err) + balanceAfter := s.hubApp().BankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) + s.Require().NotEqual(balanceBefore.String(), balanceAfter.String()) + + // hard fork + err = s.hubApp().DelayedAckKeeper.OnHardFork(s.hubCtx(), s.rollappCtx().ChainID(), 5) + s.Require().NoError(err) + + // assert commitments are created again + found = hubIBCKeeper.ChannelKeeper.HasPacketCommitment(s.hubCtx(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) + s.Require().True(found) + + // Update the client + err = hubEndpoint.UpdateClient() + s.Require().NoError(err) + + // timeout the packet. we expect for verification error + timeoutMsg := getTimeOutPacket(hubEndpoint, packet) + _, _, err = simapp.SignAndDeliver( + path.EndpointA.Chain.T, + path.EndpointA.Chain.TxConfig, + path.EndpointA.Chain.App.GetBaseApp(), + path.EndpointA.Chain.GetContext().BlockHeader(), + []sdk.Msg{timeoutMsg}, + path.EndpointA.Chain.ChainID, + []uint64{path.EndpointA.Chain.SenderAccount.GetAccountNumber()}, + []uint64{path.EndpointA.Chain.SenderAccount.GetSequence()}, + true, false, path.EndpointA.Chain.SenderPrivKey, + ) + s.Require().ErrorIs(err, ibcmerkle.ErrInvalidProof) +} + +func getTimeOutPacket(endpoint *ibctesting.Endpoint, packet channeltypes.Packet) *channeltypes.MsgTimeout { + packetKey := host.PacketReceiptKey(packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) + counterparty := endpoint.Counterparty + proof, proofHeight := counterparty.QueryProof(packetKey) + nextSeqRecv, found := counterparty.Chain.App.GetIBCKeeper().ChannelKeeper.GetNextSequenceRecv(counterparty.Chain.GetContext(), counterparty.ChannelConfig.PortID, counterparty.ChannelID) + require.True(endpoint.Chain.T, found) + + timeoutMsg := channeltypes.NewMsgTimeout( + packet, nextSeqRecv, + proof, proofHeight, endpoint.Chain.SenderAccount.GetAddress().String(), + ) + + return timeoutMsg +} diff --git a/ibctesting/eibc_test.go b/ibctesting/eibc_test.go index cd02d7caf..089899cb2 100644 --- a/ibctesting/eibc_test.go +++ b/ibctesting/eibc_test.go @@ -40,6 +40,8 @@ func TestEIBCTestSuite(t *testing.T) { func (s *eibcSuite) SetupTest() { s.utilSuite.SetupTest() + s.hubApp().LightClientKeeper.SetEnabled(false) + s.hubApp().BankKeeper.SetDenomMetaData(s.hubCtx(), banktypes.Metadata{ Base: sdk.DefaultBondDenom, }) diff --git a/ibctesting/genesis_bridge_test.go b/ibctesting/genesis_bridge_test.go index 552c19cda..f288c1d7d 100644 --- a/ibctesting/genesis_bridge_test.go +++ b/ibctesting/genesis_bridge_test.go @@ -37,6 +37,8 @@ func TestTransferGenesisTestSuite(t *testing.T) { func (s *transferGenesisSuite) SetupTest() { s.utilSuite.SetupTest() + s.hubApp().LightClientKeeper.SetEnabled(false) + path := s.newTransferPath(s.hubChain(), s.rollappChain()) s.coordinator.SetupConnections(path) s.createRollapp(false, nil) // genesis protocol is not finished yet @@ -45,11 +47,6 @@ func (s *transferGenesisSuite) SetupTest() { iroFee := sdk.NewCoin(appparams.BaseDenom, s.hubApp().IROKeeper.GetParams(s.hubCtx()).CreationFee) apptesting.FundAccount(s.hubApp(), s.hubCtx(), s.hubChain().SenderAccount.GetAddress(), sdk.NewCoins(iroFee)) - // FIXME: remove? - // fund the iro module account for pool creation fee - poolFee := s.hubApp().GAMMKeeper.GetParams(s.hubCtx()).PoolCreationFee - apptesting.FundAccount(s.hubApp(), s.hubCtx(), sdk.MustAccAddressFromBech32(s.hubApp().IROKeeper.GetModuleAccountAddress()), poolFee) - // set the canonical client before creating channels s.path = path s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), rollappChainID(), s.path.EndpointA.ClientID) diff --git a/ibctesting/light_client_test.go b/ibctesting/light_client_test.go new file mode 100644 index 000000000..1b129b3a1 --- /dev/null +++ b/ibctesting/light_client_test.go @@ -0,0 +1,488 @@ +package ibctesting_test + +import ( + "testing" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/cosmos/ibc-go/v7/testing/simapp" + + "github.com/dymensionxyz/dymension/v3/x/lightclient/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + + ibctesting "github.com/cosmos/ibc-go/v7/testing" + "github.com/stretchr/testify/suite" +) + +var canonicalClientConfig = ibctesting.TendermintConfig{ + TrustLevel: types.DefaultExpectedCanonicalClientParams().TrustLevel, + TrustingPeriod: types.DefaultExpectedCanonicalClientParams().TrustingPeriod, + UnbondingPeriod: types.DefaultExpectedCanonicalClientParams().UnbondingPeriod, + MaxClockDrift: types.DefaultExpectedCanonicalClientParams().MaxClockDrift, +} + +type lightClientSuite struct { + utilSuite + path *ibctesting.Path +} + +func TestLightClientSuite(t *testing.T) { + suite.Run(t, new(lightClientSuite)) +} + +func (s *lightClientSuite) TestSetCanonicalClient_FailsTrustRequirements() { + s.createRollapp(false, nil) + s.registerSequencer() + // The default tm client does not match the trust requirements of a canonical client. + // So it should not be set as one. + s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.SetupClients(s.path) + + // Update rollapp state - this will trigger the check for prospective canonical client + currentRollappBlockHeight := uint64(s.rollappChain().App.LastBlockHeight()) + s.updateRollappState(currentRollappBlockHeight) + + _, found := s.hubApp().LightClientKeeper.GetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID) + s.False(found) +} + +func (s *lightClientSuite) TestSetCanonicalClient_FailsIncompatibleState() { + s.createRollapp(false, nil) + s.registerSequencer() + // create a custom tm client which matches the trust requirements of a canonical client + endpointA := ibctesting.NewEndpoint(s.hubChain(), &canonicalClientConfig, ibctesting.NewConnectionConfig(), ibctesting.NewChannelConfig()) + endpointB := ibctesting.NewEndpoint(s.rollappChain(), ibctesting.NewTendermintConfig(), ibctesting.NewConnectionConfig(), ibctesting.NewChannelConfig()) + endpointA.Counterparty = endpointB + endpointB.Counterparty = endpointA + s.path = &ibctesting.Path{EndpointA: endpointA, EndpointB: endpointB} + + // Creating the tm client - this will take us to the next block + s.coordinator.SetupClients(s.path) + + // Update the rollapp state - this will trigger the check for prospective canonical client + // The block descriptor root has dummy values and will not match the IBC roots for the same height + currentRollappBlockHeight := uint64(s.rollappChain().App.LastBlockHeight()) + s.updateRollappState(currentRollappBlockHeight) + + _, found := s.hubApp().LightClientKeeper.GetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID) + s.False(found) +} + +func (s *lightClientSuite) TestSetCanonicalClient_Succeeds() { + s.createRollapp(false, nil) + s.registerSequencer() + // create a custom tm client which matches the trust requirements of a canonical client + endpointA := ibctesting.NewEndpoint(s.hubChain(), &canonicalClientConfig, ibctesting.NewConnectionConfig(), ibctesting.NewChannelConfig()) + endpointB := ibctesting.NewEndpoint(s.rollappChain(), ibctesting.NewTendermintConfig(), ibctesting.NewConnectionConfig(), ibctesting.NewChannelConfig()) + endpointA.Counterparty = endpointB + endpointB.Counterparty = endpointA + s.path = &ibctesting.Path{EndpointA: endpointA, EndpointB: endpointB} + + currentHeader := s.rollappChain().CurrentHeader + startHeight := uint64(currentHeader.Height) + bd := rollapptypes.BlockDescriptor{Height: startHeight, StateRoot: currentHeader.AppHash, Timestamp: currentHeader.Time} + + // Creating the tm client - this will take us to the next block + s.NoError(s.path.EndpointA.CreateClient()) + + currentHeader = s.rollappChain().CurrentHeader + bdNext := rollapptypes.BlockDescriptor{Height: uint64(currentHeader.Height), StateRoot: currentHeader.AppHash, Timestamp: currentHeader.Time} + + // Update the rollapp state - this will trigger the check for prospective canonical client + msgUpdateState := rollapptypes.NewMsgUpdateState( + s.hubChain().SenderAccount.GetAddress().String(), + rollappChainID(), + "mock-da-path", + startHeight, + 2, + &rollapptypes.BlockDescriptors{BD: []rollapptypes.BlockDescriptor{bd, bdNext}}, + ) + _, err := s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) + s.Require().NoError(err) + + canonClientID, found := s.hubApp().LightClientKeeper.GetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID) + s.Require().True(found) + s.Equal(endpointA.ClientID, canonClientID) +} + +func (s *lightClientSuite) TestMsgUpdateClient_StateUpdateDoesntExist() { + s.createRollapp(false, nil) + s.registerSequencer() + currentRollappBlockHeight := uint64(s.rollappChain().App.LastBlockHeight()) + s.updateRollappState(currentRollappBlockHeight) + s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.SetupClients(s.path) + s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) + + for i := 0; i < 10; i++ { + s.hubChain().NextBlock() + s.rollappChain().NextBlock() + } + + s.NoError(s.path.EndpointA.UpdateClient()) + // As there was no stateinfo found for the height, should have accepted the update optimistically. + seqAddr, err := s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, s.path.EndpointA.GetClientState().GetLatestHeight().GetRevisionHeight()) + s.NoError(err) + s.Equal(s.hubChain().SenderAccount.GetAddress().String(), seqAddr) +} + +func (s *lightClientSuite) TestMsgUpdateClient_StateUpdateExists_Compatible() { + s.createRollapp(false, nil) + s.registerSequencer() + s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.SetupClients(s.path) + s.NoError(s.path.EndpointA.UpdateClient()) + s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) + + bds := rollapptypes.BlockDescriptors{} + for i := 0; i < 2; i++ { + lastHeader := s.rollappChain().LastHeader + bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} + bds.BD = append(bds.BD, bd) + s.hubChain().NextBlock() + s.rollappChain().NextBlock() + } + header, err := s.path.EndpointA.Chain.ConstructUpdateTMClientHeader(s.path.EndpointA.Counterparty.Chain, s.path.EndpointA.ClientID) + s.NoError(err) + + for i := 0; i < 2; i++ { + lastHeader := s.rollappChain().LastHeader + bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} + bds.BD = append(bds.BD, bd) + s.hubChain().NextBlock() + s.rollappChain().NextBlock() + } + msgUpdateState := rollapptypes.NewMsgUpdateState( + s.hubChain().SenderAccount.GetAddress().String(), + rollappChainID(), + "mock-da-path", + bds.BD[0].Height, uint64(len(bds.BD)), &bds, + ) + _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) + s.NoError(err) + + msg, err := clienttypes.NewMsgUpdateClient( + s.path.EndpointA.ClientID, header, + s.path.EndpointA.Chain.SenderAccount.GetAddress().String(), + ) + s.NoError(err) + + // As there was compatible stateinfo found, should accept the ClientUpdate without any error. + _, err = s.path.EndpointA.Chain.SendMsgs(msg) + s.NoError(err) + s.Equal(uint64(header.Header.Height), s.path.EndpointA.GetClientState().GetLatestHeight().GetRevisionHeight()) + // There shouldnt be any optimistic updates as the roots were verified + _, err = s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) + s.Error(err) +} + +func (s *lightClientSuite) TestMsgUpdateClient_StateUpdateExists_NotCompatible() { + s.createRollapp(false, nil) + s.registerSequencer() + s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.SetupClients(s.path) + s.NoError(s.path.EndpointA.UpdateClient()) + s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) + + bds := rollapptypes.BlockDescriptors{} + for i := 0; i < 2; i++ { + lastHeader := s.rollappChain().LastHeader + bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} + bds.BD = append(bds.BD, bd) + s.hubChain().NextBlock() + s.rollappChain().NextBlock() + } + header, err := s.path.EndpointA.Chain.ConstructUpdateTMClientHeader(s.path.EndpointA.Counterparty.Chain, s.path.EndpointA.ClientID) + s.NoError(err) + + for i := 0; i < 2; i++ { + lastHeader := s.rollappChain().LastHeader + bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} + bd.Timestamp = bd.Timestamp.AddDate(0, 0, 1) // wrong timestamp to cause state mismatch + bds.BD = append(bds.BD, bd) + s.hubChain().NextBlock() + s.rollappChain().NextBlock() + } + msgUpdateState := rollapptypes.NewMsgUpdateState( + s.hubChain().SenderAccount.GetAddress().String(), + rollappChainID(), + "mock-da-path", + bds.BD[0].Height, uint64(len(bds.BD)), &bds, + ) + _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) + s.NoError(err) + + msg, err := clienttypes.NewMsgUpdateClient( + s.path.EndpointA.ClientID, header, + s.path.EndpointA.Chain.SenderAccount.GetAddress().String(), + ) + s.NoError(err) + + // As there was incompatible stateinfo found, should prevent light client update. + s.path.EndpointA.Chain.Coordinator.UpdateTimeForChain(s.path.EndpointA.Chain) + _, _, err = simapp.SignAndDeliver( // Explicitly submitting msg as we expect it to fail + s.path.EndpointA.Chain.T, + s.path.EndpointA.Chain.TxConfig, + s.path.EndpointA.Chain.App.GetBaseApp(), + s.path.EndpointA.Chain.GetContext().BlockHeader(), + []sdk.Msg{msg}, + s.path.EndpointA.Chain.ChainID, + []uint64{s.path.EndpointA.Chain.SenderAccount.GetAccountNumber()}, + []uint64{s.path.EndpointA.Chain.SenderAccount.GetSequence()}, + true, false, s.path.EndpointA.Chain.SenderPrivKey, + ) + s.Error(err) + s.True(errorsmod.IsOf(err, types.ErrTimestampMismatch)) +} + +func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_Compatible() { + s.createRollapp(false, nil) + s.registerSequencer() + s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.SetupClients(s.path) + s.NoError(s.path.EndpointA.UpdateClient()) + s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) + + bds := rollapptypes.BlockDescriptors{} + for i := 0; i < 2; i++ { + lastHeader := s.rollappChain().LastHeader + bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} + bds.BD = append(bds.BD, bd) + s.hubChain().NextBlock() + s.rollappChain().NextBlock() + } + header, err := s.path.EndpointA.Chain.ConstructUpdateTMClientHeader(s.path.EndpointA.Counterparty.Chain, s.path.EndpointA.ClientID) + s.NoError(err) + + for i := 0; i < 2; i++ { + lastHeader := s.rollappChain().LastHeader + bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} + bds.BD = append(bds.BD, bd) + s.hubChain().NextBlock() + s.rollappChain().NextBlock() + } + + msg, err := clienttypes.NewMsgUpdateClient( + s.path.EndpointA.ClientID, header, + s.path.EndpointA.Chain.SenderAccount.GetAddress().String(), + ) + s.NoError(err) + _, err = s.path.EndpointA.Chain.SendMsgs(msg) + s.NoError(err) + // There should be one optimistic update for the header height + _, err = s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) + s.NoError(err) + + msgUpdateState := rollapptypes.NewMsgUpdateState( + s.hubChain().SenderAccount.GetAddress().String(), + rollappChainID(), + "mock-da-path", + bds.BD[0].Height, uint64(len(bds.BD)), &bds, + ) + _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) + s.NoError(err) + // The optimistic update valhash should be removed as the state has been confirmed to be compatible + _, err = s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) + s.Error(err) + // Ensuring that the stateinfo is now upto date as well + state, found := s.hubApp().RollappKeeper.GetLatestStateInfo(s.hubCtx(), s.rollappChain().ChainID) + s.True(found) + s.True(state.ContainsHeight(uint64(header.Header.Height))) +} + +func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_NotCompatible() { + s.createRollapp(false, nil) + s.registerSequencer() + s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.SetupConnections(s.path) + s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) + s.coordinator.CreateChannels(s.path) + s.NoError(s.path.EndpointA.UpdateClient()) + + bds := rollapptypes.BlockDescriptors{} + for i := 0; i < 2; i++ { + lastHeader := s.rollappChain().LastHeader + bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} + bds.BD = append(bds.BD, bd) + s.hubChain().NextBlock() + s.rollappChain().NextBlock() + } + header, err := s.path.EndpointA.Chain.ConstructUpdateTMClientHeader(s.path.EndpointA.Counterparty.Chain, s.path.EndpointA.ClientID) + s.NoError(err) + + for i := 0; i < 2; i++ { + lastHeader := s.rollappChain().LastHeader + bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} + bd.Timestamp = bd.Timestamp.AddDate(0, 0, 1) // wrong timestamp to cause state mismatch + bds.BD = append(bds.BD, bd) + s.hubChain().NextBlock() + s.rollappChain().NextBlock() + } + + msg, err := clienttypes.NewMsgUpdateClient( + s.path.EndpointA.ClientID, header, + s.path.EndpointA.Chain.SenderAccount.GetAddress().String(), + ) + s.NoError(err) + _, err = s.path.EndpointA.Chain.SendMsgs(msg) + s.NoError(err) + // There should be one optimistic update for the header height + _, err = s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) + s.NoError(err) + + msgUpdateState := rollapptypes.NewMsgUpdateState( + s.hubChain().SenderAccount.GetAddress().String(), + rollappChainID(), + "mock-da-path", + bds.BD[0].Height, uint64(len(bds.BD)), &bds, + ) + _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) + s.Error(err) +} + +// Test the rollback flow for a light client +// - do some client updates +// - trigger rollback +// - validate rollback: +// - check if the client is frozen +// - validate IsHardForkingInProgress returns true +// - validate client updates are blocked +// - validate future consensus states are cleared +// +// - resolve hard fork +// - validate client is unfrozen and hard fork is resolved +// - validate the client is updated +// - validate the client is not in hard forking state +// +// - validate client updates are allowed +func (s *lightClientSuite) TestAfterUpdateState_Rollback() { + s.createRollapp(false, nil) + s.registerSequencer() + s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) + s.coordinator.SetupConnections(s.path) + s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) + s.coordinator.CreateChannels(s.path) + + bds := rollapptypes.BlockDescriptors{} + signerHeights := []int64{} + + for i := 0; i < 20; i++ { + s.coordinator.CommitBlock(s.hubChain(), s.rollappChain()) + + lastHeader := s.rollappChain().LastHeader + bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} + bds.BD = append(bds.BD, bd) + + if i%4 == 0 { + header, err := s.path.EndpointA.Chain.ConstructUpdateTMClientHeader(s.path.EndpointA.Counterparty.Chain, s.path.EndpointA.ClientID) + s.NoError(err) + msg, err := clienttypes.NewMsgUpdateClient( + s.path.EndpointA.ClientID, header, + s.path.EndpointA.Chain.SenderAccount.GetAddress().String(), + ) + s.NoError(err) + _, err = s.path.EndpointA.Chain.SendMsgs(msg) + s.NoError(err) + + // save signers + _, err = s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) + s.NoError(err) + signerHeights = append(signerHeights, header.Header.Height) + } + + } + + // get number of consensus states before rollback + csBeforeRollback := s.hubApp().IBCKeeper.ClientKeeper.GetAllConsensusStates(s.hubCtx())[0].ConsensusStates + + // Trigger rollback + rollbackHeight := uint64(s.rollappChain().LastHeader.Header.Height) - 5 + err := s.hubApp().LightClientKeeper.RollbackCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, rollbackHeight) + s.Require().NoError(err) + + clientState, found := s.hubApp().IBCKeeper.ClientKeeper.GetClientState(s.hubCtx(), s.path.EndpointA.ClientID) + s.True(found) + tmClientState, ok := clientState.(*ibctm.ClientState) + s.True(ok) + + // Check if the client is frozen + s.True(!tmClientState.FrozenHeight.IsZero(), "Client should be frozen after rollback") + + // Check if IsHardForkingInProgress returns true + s.True(s.hubApp().LightClientKeeper.IsHardForkingInProgress(s.hubCtx(), s.rollappChain().ChainID), "Rollapp should be in hard forking state") + + // Validate future consensus states are cleared + csAfterRollback := s.hubApp().IBCKeeper.ClientKeeper.GetAllConsensusStates(s.hubCtx())[0].ConsensusStates + s.Require().Less(len(csAfterRollback), len(csBeforeRollback), "Consensus states should be cleared after rollback") + for height := uint64(0); height <= uint64(s.rollappChain().LastHeader.Header.Height); height++ { + _, found := s.hubApp().IBCKeeper.ClientKeeper.GetClientConsensusState(s.hubCtx(), s.path.EndpointA.ClientID, clienttypes.NewHeight(1, height)) + if height > rollbackHeight { + s.False(found, "Consensus state should be cleared for height %d", height) + } + } + + // validate signers are removed + cnt := 0 + for _, height := range signerHeights { + _, err := s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, uint64(height)) + if height > int64(rollbackHeight) { + s.Error(err, "Signer should be removed for height %d", height) + } else { + s.NoError(err, "Signer should not be removed for height %d", height) + cnt++ + } + } + s.Require().Less(cnt, len(signerHeights), "Signers should be removed after rollback") + + // Validate client updates are blocked + header, err := s.path.EndpointA.Chain.ConstructUpdateTMClientHeader(s.path.EndpointA.Counterparty.Chain, s.path.EndpointA.ClientID) + s.NoError(err) + msg, err := clienttypes.NewMsgUpdateClient( + s.path.EndpointA.ClientID, header, + s.path.EndpointA.Chain.SenderAccount.GetAddress().String(), + ) + s.NoError(err) + _, _, err = simapp.SignAndDeliver( + s.path.EndpointA.Chain.T, + s.path.EndpointA.Chain.TxConfig, + s.path.EndpointA.Chain.App.GetBaseApp(), + s.path.EndpointA.Chain.GetContext().BlockHeader(), + []sdk.Msg{msg}, + s.path.EndpointA.Chain.ChainID, + []uint64{s.path.EndpointA.Chain.SenderAccount.GetAccountNumber()}, + []uint64{s.path.EndpointA.Chain.SenderAccount.GetSequence()}, + true, false, s.path.EndpointA.Chain.SenderPrivKey, + ) + s.ErrorIs(err, types.ErrorHardForkInProgress) + + // submit a state info update to resolve the hard fork + blockDescriptors := &rollapptypes.BlockDescriptors{BD: bds.BD} + msgUpdateState := rollapptypes.NewMsgUpdateState( + s.hubChain().SenderAccount.GetAddress().String(), + rollappChainID(), + "mock-da-path", + bds.BD[0].Height, + uint64(len(bds.BD)), + blockDescriptors, + ) + _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) + s.Require().NoError(err) + + // Test resolve hard fork + clientState, found = s.hubApp().IBCKeeper.ClientKeeper.GetClientState(s.hubCtx(), s.path.EndpointA.ClientID) + s.True(found) + // Verify that the client is unfrozen and hard fork is resolved + s.True(clientState.(*ibctm.ClientState).FrozenHeight.IsZero(), "Client should be unfrozen after hard fork resolution") + // Verify that the client is not in hard forking state + s.False(s.hubApp().LightClientKeeper.IsHardForkingInProgress(s.hubCtx(), s.rollappChain().ChainID), "Rollapp should not be in hard forking state") + // Verify that the client is updated with the height of the first block descriptor + s.Require().Equal(bds.BD[0].Height, clientState.GetLatestHeight().GetRevisionHeight()) + _, ok = s.hubApp().IBCKeeper.ClientKeeper.GetLatestClientConsensusState(s.hubCtx(), s.path.EndpointA.ClientID) + s.True(ok) + + // validate client updates are no longer blocked + s.coordinator.CommitBlock(s.rollappChain()) + s.NoError(s.path.EndpointA.UpdateClient()) +} diff --git a/ibctesting/utils_test.go b/ibctesting/utils_test.go index 1ea8e1f77..9037ca812 100644 --- a/ibctesting/utils_test.go +++ b/ibctesting/utils_test.go @@ -22,6 +22,7 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" "github.com/cosmos/ibc-go/v7/testing/mock" + "github.com/cosmos/ibc-go/v7/testing/simapp" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -104,14 +105,17 @@ func (s *utilSuite) rollappCtx() sdk.Context { } func (s *utilSuite) rollappMsgServer() rollapptypes.MsgServer { - return rollappkeeper.NewMsgServerImpl(*s.hubApp().RollappKeeper) + return rollappkeeper.NewMsgServerImpl(s.hubApp().RollappKeeper) } // SetupTest creates a coordinator with 2 test chains. func (s *utilSuite) SetupTest() { + // this is used as default when creating blocks. + // set in the block as the revision number + simapp.DefaultAppVersion = 0 + s.coordinator = ibctesting.NewCoordinator(s.T(), 2) // initializes test chains s.coordinator.Chains[rollappChainID()] = s.newTestChainWithSingleValidator(s.T(), s.coordinator, rollappChainID()) - s.hubApp().LightClientKeeper.SetEnabled(false) } func (s *utilSuite) fundSenderAccount() { 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/proto/dymensionxyz/dymension/lightclient/genesis.proto b/proto/dymensionxyz/dymension/lightclient/genesis.proto index fb0b9c3e2..98bc6c591 100644 --- a/proto/dymensionxyz/dymension/lightclient/genesis.proto +++ b/proto/dymensionxyz/dymension/lightclient/genesis.proto @@ -17,6 +17,7 @@ message HeaderSignerEntry { message GenesisState { repeated CanonicalClient canonical_clients = 1 [ (gogoproto.nullable) = false ]; repeated HeaderSignerEntry header_signers = 3 [ (gogoproto.nullable) = false ]; + repeated string hard_fork_keys = 4; } message CanonicalClient { diff --git a/proto/dymensionxyz/dymension/rollapp/events.proto b/proto/dymensionxyz/dymension/rollapp/events.proto index 76ed1f715..dd48df587 100644 --- a/proto/dymensionxyz/dymension/rollapp/events.proto +++ b/proto/dymensionxyz/dymension/rollapp/events.proto @@ -17,9 +17,9 @@ message EventAppRemoved { App app = 1; } -message EventMarkVulnerableRollapps { - // VulnerableRollappNum is a number of rollapps that were marked as vulnerable. - uint64 vulnerable_rollapp_num = 1; - // DrsVersions is a list of DRS versions that were marked as vulnerable. +message EventMarkObsoleteRollapps { + // ObsoleteRollappNum is a number of rollapps that were marked as obsolete. + uint64 obsolete_rollapp_num = 1; + // DrsVersions is a list of DRS versions that were marked as obsolete. repeated uint32 drs_versions = 2; } diff --git a/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto new file mode 100644 index 000000000..49d9001e5 --- /dev/null +++ b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto @@ -0,0 +1,39 @@ +syntax = "proto3"; +package dymensionxyz.dymension.rollapp; + + +import "gogoproto/gogo.proto"; +import "cosmos/msg/v1/msg.proto"; + +option go_package = "github.com/dymensionxyz/dymension/v3/x/rollapp/types"; + + +service ProposalMsg { + rpc SubmitRollappFraud(MsgRollappFraudProposal) returns (MsgRollappFraudProposalResponse); +} + +message MsgRollappFraudProposal { + option (cosmos.msg.v1.signer) = "authority"; + + // Authority is the authority address. + string authority = 1; + + // RollappID is the rollapp id. + string rollapp_id = 2; + // rollapp revision. used to verify the rollapp revision is the same as the one in the fraud proposal + uint64 rollapp_revision = 3; + + // The height of the fraudelent block + uint64 fraud_height = 4; + + // sequencer address to punish. optional + string punish_sequencer_address = 6; + + // rewardAddr is bech32 for sdk acc addr + string rewardee = 7; +} + +message MsgRollappFraudProposalResponse { +} + +// TODO: add slashing only proposal (e.g for double signing) \ No newline at end of file diff --git a/proto/dymensionxyz/dymension/rollapp/genesis.proto b/proto/dymensionxyz/dymension/rollapp/genesis.proto index 8b8abc9aa..943f7b36a 100644 --- a/proto/dymensionxyz/dymension/rollapp/genesis.proto +++ b/proto/dymensionxyz/dymension/rollapp/genesis.proto @@ -23,8 +23,8 @@ message GenesisState { repeated App appList = 8 [(gogoproto.nullable) = false]; repeated RollappRegisteredDenoms registeredDenoms = 9 [(gogoproto.nullable) = false]; repeated SequencerHeightPair sequencerHeightPairs = 10 [(gogoproto.nullable) = false]; - // VulnerableDrsVersions is a list of DRS versions that are marked vulnerable - repeated uint32 vulnerable_drs_versions = 11; + // ObsoleteDrsVersions is a list of DRS versions that are marked obsolete + repeated uint32 obsolete_drs_versions = 11; } message SequencerHeightPair { @@ -34,5 +34,5 @@ message SequencerHeightPair { message RollappRegisteredDenoms { string rollapp_id = 1; - repeated string denoms = 2 [(gogoproto.nullable) = false]; + repeated string denoms = 2; } diff --git a/proto/dymensionxyz/dymension/rollapp/proposal.proto b/proto/dymensionxyz/dymension/rollapp/proposal.proto deleted file mode 100644 index b11fcbd50..000000000 --- a/proto/dymensionxyz/dymension/rollapp/proposal.proto +++ /dev/null @@ -1,26 +0,0 @@ -syntax = "proto3"; -package dymensionxyz.dymension.rollapp; - - -import "gogoproto/gogo.proto"; - -option go_package = "github.com/dymensionxyz/dymension/v3/x/rollapp/types"; - - -message SubmitFraudProposal { - option (gogoproto.equal) = true; - option (gogoproto.goproto_getters) = false; - option (gogoproto.goproto_stringer) = false; - - string title = 1; - string description = 2; - - // The rollapp id - string rollapp_id = 3; - // The ibc client id of the rollapp - string ibc_client_id = 4; - // The height of the fraudelent block - uint64 fraudelent_height = 5; - // The address of the fraudelent sequencer - string fraudelent_sequencer_address = 6; -} diff --git a/proto/dymensionxyz/dymension/rollapp/rollapp.proto b/proto/dymensionxyz/dymension/rollapp/rollapp.proto index 38d3d45cf..37c245e84 100644 --- a/proto/dymensionxyz/dymension/rollapp/rollapp.proto +++ b/proto/dymensionxyz/dymension/rollapp/rollapp.proto @@ -41,10 +41,9 @@ message Rollapp { RollappGenesisState genesis_state = 7 [ (gogoproto.nullable) = false ]; // channel_id will be set to the canonical IBC channel of the rollapp. string channel_id = 8; - // frozen is a boolean that indicates if the rollapp is frozen. - bool frozen = 9; - reserved 10; + reserved 9,10; + // metadata is the rollapp metadata RollappMetadata metadata = 11; // genesis_info keeps immutable rollapp fields @@ -75,6 +74,11 @@ message Rollapp { // The LastStateUpdateHeight HUB height when the last state update was // received int64 last_state_update_height = 18; + + // The revision number of the rollapp. starts always with 0 revision + uint64 revision_number = 19; + // The first height of the rollapp when the revision started + uint64 revision_start_height = 20; } // Rollapp summary is a compact representation of Rollapp diff --git a/proto/dymensionxyz/dymension/rollapp/tx.proto b/proto/dymensionxyz/dymension/rollapp/tx.proto index cb4e831fa..763a7896c 100644 --- a/proto/dymensionxyz/dymension/rollapp/tx.proto +++ b/proto/dymensionxyz/dymension/rollapp/tx.proto @@ -19,7 +19,7 @@ service Msg { rpc AddApp(MsgAddApp) returns (MsgAddAppResponse); rpc UpdateApp(MsgUpdateApp) returns (MsgUpdateAppResponse); rpc RemoveApp(MsgRemoveApp) returns (MsgRemoveAppResponse); - rpc MarkVulnerableRollapps(MsgMarkVulnerableRollapps) returns (MsgMarkVulnerableRollappsResponse); + rpc MarkObsoleteRollapps(MsgMarkObsoleteRollapps) returns (MsgMarkObsoleteRollappsResponse); } // MsgCreateRollapp creates a new rollapp chain on the hub. @@ -89,6 +89,8 @@ message MsgUpdateState { BlockDescriptors BDs = 7 [(gogoproto.nullable) = false]; // last is true if this is the last batch of the sequencer bool last = 8; + // rollapp_revision is the revision of the rollapp chain. increases after hard fork + uint64 rollapp_revision = 9; } message MsgUpdateStateResponse { @@ -168,15 +170,15 @@ message MsgRemoveApp { message MsgRemoveAppResponse { } -// MsgMarkVulnerableRollapps marks specified versions as vulnerable as well as +// MsgMarkObsoleteRollapps marks specified versions as obsolete as well as // all corresponding rollapps. Must be called by the governance. -message MsgMarkVulnerableRollapps { +message MsgMarkObsoleteRollapps { option (cosmos.msg.v1.signer) = "authority"; // Authority is the authority address. string authority = 1; - // DrsVersions is a list of DRS versions that will be marked vulnerable. + // DrsVersions is a list of DRS versions that will be marked obsolete. repeated uint32 drs_versions = 2; } -message MsgMarkVulnerableRollappsResponse {} +message MsgMarkObsoleteRollappsResponse {} diff --git a/testutil/keeper/delayedack.go b/testutil/keeper/delayedack.go index 442336c73..4046647a7 100644 --- a/testutil/keeper/delayedack.go +++ b/testutil/keeper/delayedack.go @@ -28,6 +28,12 @@ import ( type ChannelKeeperStub struct{} +func (c ChannelKeeperStub) SetPacketCommitment(ctx sdk.Context, portID string, channelID string, sequence uint64, commitmentHash []byte) { +} + +func (c ChannelKeeperStub) SetPacketReceipt(ctx sdk.Context, portID string, channelID string, sequence uint64) { +} + func (ChannelKeeperStub) LookupModuleByChannel(ctx sdk.Context, portID, channelID string) (string, *capabilitytypes.Capability, error) { return "", nil, nil } @@ -137,6 +143,7 @@ func DelayedackKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { k := keeper.NewKeeper(cdc, storeKey, + nil, paramsSubspace, RollappKeeperStub{}, ICS4WrapperStub{}, diff --git a/testutil/keeper/dymns.go b/testutil/keeper/dymns.go index f3ebd8d00..9a33b71e5 100644 --- a/testutil/keeper/dymns.go +++ b/testutil/keeper/dymns.go @@ -93,7 +93,7 @@ func DymNSKeeper(t testing.TB) (dymnskeeper.Keeper, dymnstypes.BankKeeper, rolla cdc, rollappStoreKey, rollappParamsSubspace, - nil, nil, nil, nil, + nil, nil, bankKeeper, nil, authtypes.NewModuleAddress(govtypes.ModuleName).String(), diff --git a/testutil/keeper/lightclient.go b/testutil/keeper/lightclient.go index 157db71e0..8a686ca12 100644 --- a/testutil/keeper/lightclient.go +++ b/testutil/keeper/lightclient.go @@ -97,6 +97,11 @@ type MockIBCCLientKeeper struct { clientStates map[string]exported.ClientState } +// ClientStore implements types.IBCClientKeeperExpected. +func (m *MockIBCCLientKeeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { + panic("unimplemented") +} + func NewMockIBCClientKeeper( clientCS map[string]map[uint64]exported.ConsensusState, genesisClients map[string]exported.ClientState, @@ -164,8 +169,9 @@ func (m *MockSequencerKeeper) RollappSequencers(ctx sdk.Context, rollappId strin return seqs } -func (m *MockSequencerKeeper) UnbondingTime(ctx sdk.Context) (res time.Duration) { - return types.DefaultExpectedCanonicalClientParams().UnbondingPeriod +// GetProposer implements types.SequencerKeeperExpected. +func (m *MockSequencerKeeper) GetProposer(ctx sdk.Context, rollappId string) (val sequencertypes.Sequencer) { + panic("unimplemented") } func NewMockSequencerKeeper(sequencers map[string]*sequencertypes.Sequencer) *MockSequencerKeeper { @@ -176,6 +182,11 @@ func NewMockSequencerKeeper(sequencers map[string]*sequencertypes.Sequencer) *Mo type MockRollappKeeper struct{} +// GetLatestStateInfo implements types.RollappKeeperExpected. +func (m *MockRollappKeeper) GetLatestStateInfo(ctx sdk.Context, rollappId string) (rollapptypes.StateInfo, bool) { + panic("unimplemented") +} + func NewMockRollappKeeper() *MockRollappKeeper { return &MockRollappKeeper{} } @@ -195,6 +206,6 @@ func (m *MockRollappKeeper) GetStateInfo(ctx sdk.Context, rollappId string, inde func (m *MockRollappKeeper) SetRollapp(ctx sdk.Context, rollapp rollapptypes.Rollapp) { } -func (m *MockRollappKeeper) HandleFraud(ctx sdk.Context, rollappID, clientId string, fraudHeight uint64, seqAddr string) error { +func (m *MockRollappKeeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error { return nil } diff --git a/testutil/keeper/rollapp.go b/testutil/keeper/rollapp.go index a5887650b..6609fc0d8 100644 --- a/testutil/keeper/rollapp.go +++ b/testutil/keeper/rollapp.go @@ -40,7 +40,7 @@ func RollappKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { memStoreKey, "RollappParams", ) - k := keeper.NewKeeper(cdc, storeKey, paramsSubspace, nil, nil, nil, nil, nil, nil, authtypes.NewModuleAddress(govtypes.ModuleName).String(), nil) + k := keeper.NewKeeper(cdc, storeKey, paramsSubspace, nil, nil, nil, nil, authtypes.NewModuleAddress(govtypes.ModuleName).String(), nil) ctx := sdk.NewContext(stateStore, cometbftproto.Header{}, false, log.NewNopLogger()) diff --git a/x/common/types/key_rollapp_packet.go b/x/common/types/key_rollapp_packet.go index 3f79ebb16..9de033283 100644 --- a/x/common/types/key_rollapp_packet.go +++ b/x/common/types/key_rollapp_packet.go @@ -18,8 +18,9 @@ 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} + + _ = []byte{0x00, 0x03} // deprecated key + // keySeparatorBytes is used to separate the rollapp packet key parts keySeparatorBytes = []byte("/") ) @@ -100,8 +101,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/rollapp_packet.go b/x/common/types/rollapp_packet.go index 832ccbe2e..83ddf80ee 100644 --- a/x/common/types/rollapp_packet.go +++ b/x/common/types/rollapp_packet.go @@ -107,11 +107,8 @@ func (r RollappPacket) GetAck() (channeltypes.Acknowledgement, error) { return ack, nil } -func (r RollappPacket) RestoreOriginalTransferTarget() (RollappPacket, error) { - transferPacketData, err := r.GetTransferPacketData() - if err != nil { - return r, fmt.Errorf("get transfer packet data: %w", err) - } +func (r RollappPacket) RestoreOriginalTransferTarget() RollappPacket { + transferPacketData := r.MustGetTransferPacketData() if r.OriginalTransferTarget != "" { // It can be empty if the eibc order was never fulfilled switch r.Type { case RollappPacket_ON_RECV: @@ -121,5 +118,5 @@ func (r RollappPacket) RestoreOriginalTransferTarget() (RollappPacket, error) { } r.Packet.Data = transferPacketData.GetBytes() } - return r, nil + return r } 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 fbda768bd..d60165873 100644 --- a/x/delayedack/client/cli/query.go +++ b/x/delayedack/client/cli/query.go @@ -64,7 +64,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 @@ -126,7 +126,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 689cd7b05..06abc050c 100644 --- a/x/delayedack/keeper/finalize.go +++ b/x/delayedack/keeper/finalize.go @@ -24,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 @@ -84,7 +84,7 @@ func (k Keeper) finalizeRollappPacket( } // Update status to finalized - _, err := k.UpdateRollappPacketWithStatus(ctx, rollappPacket, commontypes.Status_FINALIZED) + _, err := k.UpdateRollappPacketAfterFinalization(ctx, rollappPacket) if err != nil { return fmt.Errorf("update rollapp packet: %w", err) } @@ -109,10 +109,7 @@ func (k Keeper) writeRecvAck(rollappPacket commontypes.RollappPacket, ack export Here, we do the inverse of what we did when we updated the packet transfer address, when we fulfilled the order to ensure the ack matches what the rollapp expects. */ - rollappPacket, err = rollappPacket.RestoreOriginalTransferTarget() - if err != nil { - return fmt.Errorf("restore original transfer target: %w", err) - } + rollappPacket = rollappPacket.RestoreOriginalTransferTarget() err = k.WriteAcknowledgement(ctx, chanCap, rollappPacket.Packet, ack) return } @@ -136,19 +133,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 - latestHeight := stateInfo.GetLatestHeight() - if height > latestHeight { - return gerrc.ErrInvalidArgument.Wrapf("packet height is not finalized yet: height '%d', latest height '%d'", height, latestHeight) + if height > latestFinalizedHeight { + return gerrc.ErrInvalidArgument.Wrapf("packet height is not finalized yet: height '%d', latest finalized height '%d'", height, latestFinalizedHeight) } return nil } diff --git a/x/delayedack/keeper/finalize_test.go b/x/delayedack/keeper/finalize_test.go index a2f134fbd..02e290914 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..45ded3ef1 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -1,22 +1,24 @@ package keeper import ( + errorsmod "cosmossdk.io/errors" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" sdk "github.com/cosmos/cosmos-sdk/types" - porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/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 - } +var _ rollapptypes.RollappHooks = &Keeper{} + +func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, newRevisionHeight uint64) 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, newRevisionHeight)) // Iterate over all the pending packets and revert them for _, rollappPacket := range rollappPendingPackets { @@ -29,21 +31,33 @@ func (k Keeper) HandleFraud(ctx sdk.Context, rollappID string, ibc porttypes.IBC } 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())...) - } + // for sent packets, we restore the packet commitment + // the packet will be handled over the new rollapp revision + // we update the packet to the original transfer target and restore the packet commitment + commitment := channeltypes.CommitPacket(k.cdc, rollappPacket.RestoreOriginalTransferTarget().Packet) + k.channelKeeper.SetPacketCommitment(ctx, rollappPacket.Packet.SourcePort, rollappPacket.Packet.SourceChannel, rollappPacket.Packet.Sequence, commitment) + } else { + // for incoming packets, we need to reset the packet receipt + ibcPacket := rollappPacket.Packet + k.deletePacketReceipt(ctx, ibcPacket.GetDestPort(), ibcPacket.GetDestChannel(), ibcPacket.GetSequence()) } - // Update status to reverted - _, err := k.UpdateRollappPacketWithStatus(ctx, rollappPacket, commontypes.Status_REVERTED) + + // delete the packet + err := k.DeleteRollappPacket(ctx, &rollappPacket) if err != nil { - logger.Error("error reverting IBC rollapp packet", append(logContext, "error", err.Error())...) - return err + return errorsmod.Wrap(err, "delete rollapp packet") } 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 dd844c0f4..2495f41b1 100644 --- a/x/delayedack/keeper/fraud_test.go +++ b/x/delayedack/keeper/fraud_test.go @@ -1,83 +1,59 @@ package keeper_test import ( - ibctransfer "github.com/cosmos/ibc-go/v7/modules/apps/transfer" - "github.com/dymensionxyz/dymension/v3/app/apptesting" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" - damodule "github.com/dymensionxyz/dymension/v3/x/delayedack" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" ) func (suite *DelayedAckTestSuite) TestHandleFraud() { 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 := apptesting.GenerateRollappPackets(suite.T(), rollappId, 5) + pkts := apptesting.GenerateRollappPackets(suite.T(), rollappId, 10) rollappId2 := "testRollappId2" - pkts2 := apptesting.GenerateRollappPackets(suite.T(), rollappId2, 5) + pkts2 := apptesting.GenerateRollappPackets(suite.T(), 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) + keeper.MustSetPendingPacketByAddress(ctx, apptesting.TestPacketReceiver, pkt.RollappPacketKey()) } - 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))) + pktsByAddr, err := keeper.GetPendingPacketsByAddress(ctx, apptesting.TestPacketReceiver) + suite.Require().NoError(err) + suite.Require().Equal(20, len(pktsByAddr)) - // finalize some packets - _, err := keeper.UpdateRollappPacketWithStatus(ctx, pkts[0], commontypes.Status_FINALIZED) + // finalize one packet + _, err = keeper.UpdateRollappPacketAfterFinalization(ctx, pkts[0]) suite.Require().Nil(err) - _, err = keeper.UpdateRollappPacketWithStatus(ctx, pkts2[0], commontypes.Status_FINALIZED) - suite.Require().Nil(err) - - err = keeper.HandleFraud(ctx, rollappId, transferStack) + _, err = keeper.UpdateRollappPacketAfterFinalization(ctx, pkts2[0]) 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 := apptesting.GenerateRollappPackets(suite.T(), rollappId, 5) - rollappId2 := "testRollappId2" - pkts2 := apptesting.GenerateRollappPackets(suite.T(), rollappId2, 5) - - for _, pkt := range append(pkts, pkts2...) { - keeper.SetRollappPacket(ctx, pkt) - } + // call fraud on the 4 packet + err = keeper.OnHardFork(ctx, rollappId, 4) + suite.Require().NoError(err) - 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) + pktsByAddr, err = keeper.GetPendingPacketsByAddress(ctx, apptesting.TestPacketReceiver) suite.Require().NoError(err) + suite.Require().Equal(11, len(pktsByAddr)) // 2 from rollappId, 9 from rollappId2 - 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 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/hooks_test.go b/x/delayedack/keeper/hooks_test.go index 552ab1d52..972c91271 100644 --- a/x/delayedack/keeper/hooks_test.go +++ b/x/delayedack/keeper/hooks_test.go @@ -66,7 +66,7 @@ func (suite *DelayedAckTestSuite) TestAfterEpochEnd() { suite.Require().Equal(tc.pendingPacketsNum, len(rollappPackets)) for _, rollappPacket := range rollappPackets[:tc.finalizePacketsNum] { - _, err := keeper.UpdateRollappPacketWithStatus(ctx, rollappPacket, commontypes.Status_FINALIZED) + _, err := keeper.UpdateRollappPacketAfterFinalization(ctx, rollappPacket) suite.Require().NoError(err) } finalizedRollappPackets := keeper.ListRollappPackets(ctx, types.ByRollappIDByStatus(rollappID, commontypes.Status_FINALIZED)) diff --git a/x/delayedack/keeper/invariants.go b/x/delayedack/keeper/invariants.go index f68cc2ffa..66e615249 100644 --- a/x/delayedack/keeper/invariants.go +++ b/x/delayedack/keeper/invariants.go @@ -12,79 +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. -// Skip the check if the rollapp is frozen -func (k Keeper) PacketsFinalizationCorrespondsToFinalizationHeight(ctx sdk.Context) (string, bool) { - return k.packetsCorrespondsToStatusHeight(checkFinalizedPackets, false)(ctx) -} - -// PacketsFromRevertedHeightsAreReverted checks that all rollapp packets stored are set to -// reverted status for all heights up to the latest height -// Check if the rollapp is frozen -func (k Keeper) PacketsFromRevertedHeightsAreReverted(ctx sdk.Context) (string, bool) { - return k.packetsCorrespondsToStatusHeight(checkRevertedPackets, true)(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, checkRollappFrozen bool) sdk.Invariant { - return func(ctx sdk.Context) (msg string, stop bool) { for _, rollapp := range k.rollappKeeper.GetAllRollapps(ctx) { - msg = k.checkRollapp(ctx, rollapp, checkPackets, checkRollappFrozen) - 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, checkFrozen bool) (msg string) { - if checkFrozen && !rollapp.Frozen { - return - } - +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", @@ -93,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 83a2de635..81f0cb129 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -2,23 +2,15 @@ package keeper_test import ( "github.com/cometbft/cometbft/libs/rand" - ibctransfer "github.com/cosmos/ibc-go/v7/modules/apps/transfer" "github.com/dymensionxyz/dymension/v3/app/apptesting" 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() - - transferStack := damodule.NewIBCMiddleware( - damodule.WithIBCModule(ibctransfer.NewIBCModule(suite.App.TransferKeeper)), - damodule.WithKeeper(suite.App.DelayedAckKeeper), - damodule.WithRollappKeeper(suite.App.RollappKeeper), - ) + suite.T().Skip("skipping TestInvariants as it's not supported with lazy finalization feature") initialHeight := int64(10) suite.Ctx = suite.Ctx.WithBlockHeight(initialHeight) @@ -86,35 +78,34 @@ func (suite *DelayedAckTestSuite) TestInvariants() { // test fraud for rollapp := range seqPerRollapp { - err := suite.App.DelayedAckKeeper.HandleFraud(suite.Ctx, rollapp, transferStack) + err := suite.App.DelayedAckKeeper.OnHardFork(suite.Ctx, rollapp, uint64(suite.Ctx.BlockHeight())) 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, @@ -130,19 +121,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: apptesting.GenerateTestPacket(suite.T(), 1), }, commontypes.RollappPacket{ RollappId: rollapp, - Status: commontypes.Status_REVERTED, + Status: commontypes.Status_PENDING, ProofHeight: 15, Packet: apptesting.GenerateTestPacket(suite.T(), 2), }, @@ -150,8 +139,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, @@ -167,29 +154,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: apptesting.GenerateTestPacket(suite.T(), 1), - }, - commontypes.RollappPacket{ - RollappId: rollapp, - Status: commontypes.Status_PENDING, - ProofHeight: 15, - Packet: apptesting.GenerateTestPacket(suite.T(), 2), - }, - true, - }, + // failed checks { "wrong finalized packet check - packets are finalized in non-finalized heights", - false, - false, true, commontypes.RollappPacket{ RollappId: rollapp, @@ -208,8 +175,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, @@ -244,6 +209,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, @@ -254,40 +224,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.HandleFraud(ctx, rollapp, "", 11, proposer) - suite.Require().NoError(err) + suite.App.RollappKeeper.SetLatestStateInfoIndex(ctx, stateInfo2.StateInfoIndex) + if !tc.nothingFinalized { + suite.App.RollappKeeper.SetLatestFinalizedStateIndex(ctx, stateInfo.StateInfoIndex) } // add rollapp packets @@ -295,10 +235,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 3439f4088..7534a98a8 100644 --- a/x/delayedack/keeper/keeper.go +++ b/x/delayedack/keeper/keeper.go @@ -19,10 +19,13 @@ import ( ) type Keeper struct { - cdc codec.Codec - storeKey storetypes.StoreKey - hooks types.MultiDelayedAckHooks - paramstore paramtypes.Subspace + rollapptypes.StubRollappCreatedHooks + + cdc codec.Codec + storeKey storetypes.StoreKey + channelKeeperStoreKey storetypes.StoreKey // we need direct access to the IBC channel store + hooks types.MultiDelayedAckHooks + paramstore paramtypes.Subspace // pendingPacketsByAddress is an index of all pending packets associated with a Hub address. // In case of ON_RECV packet (Rollapp -> Hub), the address is the packet receiver. @@ -39,6 +42,7 @@ type Keeper struct { func NewKeeper( cdc codec.Codec, storeKey storetypes.StoreKey, + channelKeeperStoreKey storetypes.StoreKey, ps paramtypes.Subspace, rollappKeeper types.RollappKeeper, ics4Wrapper porttypes.ICS4Wrapper, @@ -50,9 +54,10 @@ func NewKeeper( ps = ps.WithKeyTable(types.ParamKeyTable()) } return &Keeper{ - cdc: cdc, - storeKey: storeKey, - paramstore: ps, + cdc: cdc, + storeKey: storeKey, + channelKeeperStoreKey: channelKeeperStoreKey, + paramstore: ps, pendingPacketsByAddress: collections.NewKeySet( collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey)), collections.NewPrefix(types.PendingPacketsByAddressKeyPrefix), @@ -75,17 +80,6 @@ func (k Keeper) Cdc() codec.Codec { return k.cdc } -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 c0441a17a..6071229a4 100644 --- a/x/delayedack/keeper/rollapp_packet.go +++ b/x/delayedack/keeper/rollapp_packet.go @@ -1,7 +1,7 @@ package keeper import ( - "errors" + "fmt" "cosmossdk.io/collections" sdk "github.com/cosmos/cosmos-sdk/types" @@ -9,6 +9,7 @@ import ( 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. @@ -151,16 +152,13 @@ func (k Keeper) UpdateRollappPacketTransferAddress( return nil } -// UpdateRollappPacketWithStatus deletes the current rollapp packet and creates a new one with and updated status under a new key. +// UpdateRollappPacketAfterFinalization deletes the current rollapp packet and creates a new one with and updated status under a new key. // Updating the status should be called only with this method as it effects the key of the packet. // The assumption is that the passed rollapp packet status field is not updated directly. -func (k *Keeper) UpdateRollappPacketWithStatus(ctx sdk.Context, rollappPacket commontypes.RollappPacket, newStatus commontypes.Status) (commontypes.RollappPacket, error) { +func (k *Keeper) UpdateRollappPacketAfterFinalization(ctx sdk.Context, rollappPacket commontypes.RollappPacket) (commontypes.RollappPacket, error) { if rollappPacket.Status != commontypes.Status_PENDING { return commontypes.RollappPacket{}, types.ErrCanOnlyUpdatePendingPacket } - if newStatus == commontypes.Status_PENDING { - return commontypes.RollappPacket{}, errors.New("cannot update packet to pending status") - } transferPacketData, err := rollappPacket.GetTransferPacketData() if err != nil { @@ -182,7 +180,7 @@ func (k *Keeper) UpdateRollappPacketWithStatus(ctx sdk.Context, rollappPacket co store.Delete(oldKey) // Update the packet - rollappPacket.Status = newStatus + rollappPacket.Status = commontypes.Status_FINALIZED // Create a new rollapp packet with the updated status k.SetRollappPacket(ctx, rollappPacket) @@ -248,12 +246,24 @@ 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) + // delete the PacketByAddress index + pendingAddr := "" + transfer := rollappPacket.MustGetTransferPacketData() + switch rollappPacket.Type { + case commontypes.RollappPacket_ON_RECV: + pendingAddr = transfer.Receiver + case commontypes.RollappPacket_ON_ACK, commontypes.RollappPacket_ON_TIMEOUT: + pendingAddr = transfer.Sender + } + k.MustDeletePendingPacketByAddress(ctx, pendingAddr, rollappPacket.RollappPacketKey()) + keeperHooks := k.GetHooks() + // TODO: can call eIBC directly. shouldn't return error anyway err := keeperHooks.AfterPacketDeleted(ctx, rollappPacket) if err != nil { return err @@ -261,3 +271,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 1fca74b66..853867a9c 100644 --- a/x/delayedack/keeper/rollapp_packet_test.go +++ b/x/delayedack/keeper/rollapp_packet_test.go @@ -14,7 +14,6 @@ func (suite *DelayedAckTestSuite) TestRollappPacketEvents() { tests := []struct { name string rollappPacket commontypes.RollappPacket - rollappUpdatedStatus commontypes.Status rollappUpdateError error expectedEventType string expectedEventsCountPreUpdate int @@ -30,7 +29,6 @@ func (suite *DelayedAckTestSuite) TestRollappPacketEvents() { Status: commontypes.Status_PENDING, ProofHeight: 1, }, - rollappUpdatedStatus: commontypes.Status_FINALIZED, rollappUpdateError: types.ErrRollappPacketDoesNotExist, expectedEventType: delayedAckEventType, expectedEventsCountPreUpdate: 1, @@ -65,7 +63,7 @@ func (suite *DelayedAckTestSuite) TestRollappPacketEvents() { suite.AssertAttributes(lastEvent, tc.expectedEventsAttributesPreUpdate) // Update the rollapp packet tc.rollappPacket.Error = tc.rollappUpdateError.Error() - _, err := keeper.UpdateRollappPacketWithStatus(ctx, tc.rollappPacket, tc.rollappUpdatedStatus) + _, err := keeper.UpdateRollappPacketAfterFinalization(ctx, tc.rollappPacket) suite.Require().NoError(err) // Check the events suite.AssertEventEmitted(ctx, tc.expectedEventType, tc.expectedEventsCountPostUpdate) @@ -76,6 +74,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"} @@ -83,7 +85,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 @@ -100,7 +101,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), } @@ -117,50 +118,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_PendingToFinalized() { @@ -177,7 +180,7 @@ func (suite *DelayedAckTestSuite) TestUpdateRollappPacketWithStatus_PendingToFin suite.Require().NoError(err) // Update the packet status - packet, err := keeper.UpdateRollappPacketWithStatus(ctx, oldPacket, commontypes.Status_FINALIZED) + packet, err := keeper.UpdateRollappPacketAfterFinalization(ctx, oldPacket) suite.Require().NoError(err) suite.Require().Equal(commontypes.Status_FINALIZED, packet.Status) 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 deleted file mode 100644 index a56360edb..000000000 --- a/x/delayedack/rollapp_hooks.go +++ /dev/null @@ -1,13 +0,0 @@ -package delayedack - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" -) - -var _ rollapptypes.RollappHooks = &IBCMiddleware{} - -func (w IBCMiddleware) FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { - return w.HandleFraud(ctx, rollappID, w.IBCModule) -} diff --git a/x/delayedack/types/expected_keepers.go b/x/delayedack/types/expected_keepers.go index 7d886bd3f..327d08cd3 100644 --- a/x/delayedack/types/expected_keepers.go +++ b/x/delayedack/types/expected_keepers.go @@ -13,13 +13,11 @@ import ( // ChannelKeeper defines the expected IBC channel keeper type ChannelKeeper interface { LookupModuleByChannel(ctx sdk.Context, portID, channelID string) (string, *capabilitytypes.Capability, error) + SetPacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64, commitmentHash []byte) } type RollappKeeper interface { - GetParams(ctx sdk.Context) rollapptypes.Params - GetStateInfo(ctx sdk.Context, rollappId string, index uint64) (val rollapptypes.StateInfo, found bool) MustGetStateInfo(ctx sdk.Context, rollappId string, index uint64) rollapptypes.StateInfo - GetLatestStateInfo(ctx sdk.Context, rollappId string) (types.StateInfo, bool) GetLatestFinalizedStateIndex(ctx sdk.Context, rollappId string) (val types.StateInfoIndex, found bool) GetAllRollapps(ctx sdk.Context) (list []types.Rollapp) GetValidTransfer( 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/denommetadata/ibc_middleware.go b/x/denommetadata/ibc_middleware.go index 9406058f2..d4d2e2498 100644 --- a/x/denommetadata/ibc_middleware.go +++ b/x/denommetadata/ibc_middleware.go @@ -106,6 +106,7 @@ func (im IBCModule) OnRecvPacket( } // OnAcknowledgementPacket adds the token metadata to the rollapp if it doesn't exist +// It marks the completion of the denom metadata registration process on the rollapp func (im IBCModule) OnAcknowledgementPacket( ctx sdk.Context, packet channeltypes.Packet, diff --git a/x/denommetadata/ibc_middleware_test.go b/x/denommetadata/ibc_middleware_test.go index c708dd999..c61f6bf78 100644 --- a/x/denommetadata/ibc_middleware_test.go +++ b/x/denommetadata/ibc_middleware_test.go @@ -696,6 +696,12 @@ type mockRollappKeeper struct { err error } +// ClearRegisteredDenoms implements types.RollappKeeper. +func (m *mockRollappKeeper) ClearRegisteredDenoms(ctx sdk.Context, rollappID string) error { + m.registeredDenoms = make(map[string]struct{}) + return nil +} + func (m *mockRollappKeeper) SetRollapp(_ sdk.Context, rollapp rollapptypes.Rollapp) { m.returnRollapp = &rollapp } diff --git a/x/denommetadata/keeper/keeper.go b/x/denommetadata/keeper/keeper.go index 8d825be2b..5c12dbe13 100644 --- a/x/denommetadata/keeper/keeper.go +++ b/x/denommetadata/keeper/keeper.go @@ -15,13 +15,15 @@ import ( // Keeper of the denommetadata store type Keeper struct { bankKeeper types.BankKeeper + rk types.RollappKeeper hooks types.MultiDenomMetadataHooks } // NewKeeper returns a new instance of the denommetadata keeper -func NewKeeper(bankKeeper types.BankKeeper) *Keeper { +func NewKeeper(bankKeeper types.BankKeeper, rk types.RollappKeeper) *Keeper { return &Keeper{ bankKeeper: bankKeeper, + rk: rk, hooks: nil, } } diff --git a/x/denommetadata/keeper/rollback.go b/x/denommetadata/keeper/rollback.go new file mode 100644 index 000000000..5ce7c829b --- /dev/null +++ b/x/denommetadata/keeper/rollback.go @@ -0,0 +1,22 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +var _ rollapptypes.RollappHooks = rollappHook{} + +type rollappHook struct { + rollapptypes.StubRollappCreatedHooks + k Keeper +} + +func (k Keeper) RollappHooks() rollapptypes.RollappHooks { + return rollappHook{k: k} +} + +// OnHardFork implements the RollappHooks interface +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappID string, _ uint64) error { + return hook.k.rk.ClearRegisteredDenoms(ctx, rollappID) +} diff --git a/x/denommetadata/types/expected_keepers.go b/x/denommetadata/types/expected_keepers.go index b57ff19c9..d8bb59f8d 100644 --- a/x/denommetadata/types/expected_keepers.go +++ b/x/denommetadata/types/expected_keepers.go @@ -27,4 +27,5 @@ type RollappKeeper interface { ) (data rollapptypes.TransferData, err error) SetRegisteredDenom(ctx sdk.Context, rollappID, denom string) error HasRegisteredDenom(ctx sdk.Context, rollappID, denom string) (bool, error) + ClearRegisteredDenoms(ctx sdk.Context, rollappID string) error } diff --git a/x/dymns/keeper/hooks.go b/x/dymns/keeper/hooks.go index cfb1db8e7..1f23ef165 100644 --- a/x/dymns/keeper/hooks.go +++ b/x/dymns/keeper/hooks.go @@ -73,9 +73,7 @@ func (h rollappHooks) AfterStateFinalized(_ sdk.Context, _ string, _ *rollapptyp return nil } -func (h rollappHooks) FraudSubmitted(_ sdk.Context, _ string, _ uint64, _ string) error { - return nil -} +func (h rollappHooks) OnHardFork(_ sdk.Context, _ string, _ uint64) error { return nil } func (h rollappHooks) AfterTransfersEnabled(_ sdk.Context, _, _ string) error { return nil diff --git a/x/dymns/keeper/keeper_suite_test.go b/x/dymns/keeper/keeper_suite_test.go index 8229fcbc0..0a6dc34cc 100644 --- a/x/dymns/keeper/keeper_suite_test.go +++ b/x/dymns/keeper/keeper_suite_test.go @@ -142,7 +142,8 @@ func (s *KeeperTestSuite) SetupTest() { cdc, rollappStoreKey, rollappParamsSubspace, - nil, nil, nil, nil, + nil, + nil, bk, nil, authtypes.NewModuleAddress(govtypes.ModuleName).String(), 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 c119522d7..33d12edca 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 729e16d48..e627e6a17 100644 --- a/x/eibc/keeper/hooks_test.go +++ b/x/eibc/keeper/hooks_test.go @@ -20,7 +20,7 @@ func (suite *KeeperTestSuite) TestAfterRollappPacketUpdated() { err := suite.App.EIBCKeeper.SetDemandOrder(suite.Ctx, demandOrder) suite.Require().NoError(err) // Update rollapp packet status to finalized - updatedRollappPacket, err := suite.App.DelayedAckKeeper.UpdateRollappPacketWithStatus(suite.Ctx, *rollappPacket, commontypes.Status_FINALIZED) + updatedRollappPacket, err := suite.App.DelayedAckKeeper.UpdateRollappPacketAfterFinalization(suite.Ctx, *rollappPacket) suite.Require().NoError(err) // Veirfy that the demand order is updated updatedDemandOrder, err := suite.App.EIBCKeeper.GetDemandOrder(suite.Ctx, commontypes.Status_FINALIZED, demandOrder.Id) @@ -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, }, } @@ -59,18 +59,17 @@ func (suite *KeeperTestSuite) TestAfterRollappPacketDeleted() { demandOrder := types.NewDemandOrder(*rollappPacket, math.NewIntFromUint64(100), math.NewIntFromUint64(50), sdk.DefaultBondDenom, demandOrderFulfillerAddr, 1) err := suite.App.EIBCKeeper.SetDemandOrder(suite.Ctx, demandOrder) suite.Require().NoError(err) + _, err = suite.App.EIBCKeeper.GetDemandOrder(suite.Ctx, commontypes.Status_PENDING, demandOrder.Id) + suite.Require().NoError(err) // Update rollapp packet status - _, err = suite.App.DelayedAckKeeper.UpdateRollappPacketWithStatus(suite.Ctx, *rollappPacket, tc.packetStatus) - suite.Require().NoError(err) + if tc.packetStatus == commontypes.Status_FINALIZED { + _, err = suite.App.DelayedAckKeeper.UpdateRollappPacketAfterFinalization(suite.Ctx, *rollappPacket) + 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 718d2d3e1..36fecff71 100644 --- a/x/eibc/keeper/invariants_test.go +++ b/x/eibc/keeper/invariants_test.go @@ -19,12 +19,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/keeper/msg_server_test.go b/x/eibc/keeper/msg_server_test.go index d44900bf3..09712e059 100644 --- a/x/eibc/keeper/msg_server_test.go +++ b/x/eibc/keeper/msg_server_test.go @@ -158,7 +158,7 @@ func (suite *KeeperTestSuite) TestMsgFulfillOrder() { suite.Require().NoError(err) // Update rollapp status if needed if rollappPacket.Status != tc.demandOrderUnderlyingPacketStatus { - _, err = suite.App.DelayedAckKeeper.UpdateRollappPacketWithStatus(suite.Ctx, rPacket, tc.demandOrderUnderlyingPacketStatus) + _, err = suite.App.DelayedAckKeeper.UpdateRollappPacketAfterFinalization(suite.Ctx, rPacket) suite.Require().NoError(err, tc.name) } diff --git a/x/eibc/types/expected_keepers.go b/x/eibc/types/expected_keepers.go index fc0b48eaa..61d832d0b 100644 --- a/x/eibc/types/expected_keepers.go +++ b/x/eibc/types/expected_keepers.go @@ -22,7 +22,6 @@ type BankKeeper interface { type DelayedAckKeeper interface { GetRollappPacket(ctx sdk.Context, rollappPacketKey string) (*commontypes.RollappPacket, error) - BridgingFeeFromAmt(ctx sdk.Context, amt sdk.Int) (res sdk.Int) BridgingFee(ctx sdk.Context) (res sdk.Dec) VerifyHeightFinalized(ctx sdk.Context, rollappID string, height uint64) error } diff --git a/x/eibc/types/keys.go b/x/eibc/types/keys.go index 0fe1b4380..84a29422f 100644 --- a/x/eibc/types/keys.go +++ b/x/eibc/types/keys.go @@ -34,8 +34,8 @@ 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} + + _ = []byte{0x00, 0x03} // deprecated key ) // GetDemandOrderKey constructs a key for a specific DemandOrder. @@ -47,8 +47,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) } diff --git a/x/incentives/client/cli/query_test.go b/x/incentives/client/cli/query_test.go index 1f6e907ef..bca49cab6 100644 --- a/x/incentives/client/cli/query_test.go +++ b/x/incentives/client/cli/query_test.go @@ -41,7 +41,7 @@ func (suite *QueryTestSuite) CreateDefaultRollapp() string { suite.FundForAliasRegistration(msgCreateRollapp) - msgServer := rollapp.NewMsgServerImpl(*suite.App.RollappKeeper) + msgServer := rollapp.NewMsgServerImpl(suite.App.RollappKeeper) _, err := msgServer.CreateRollapp(suite.Ctx, &msgCreateRollapp) suite.Require().NoError(err) return msgCreateRollapp.RollappId diff --git a/x/incentives/keeper/suite_test.go b/x/incentives/keeper/suite_test.go index db1785cbb..464601e0c 100644 --- a/x/incentives/keeper/suite_test.go +++ b/x/incentives/keeper/suite_test.go @@ -228,14 +228,14 @@ func (suite *KeeperTestSuite) CreateDefaultRollapp(addr sdk.AccAddress) string { suite.FundForAliasRegistration(msgCreateRollapp) - msgServer := rollapp.NewMsgServerImpl(*suite.App.RollappKeeper) + msgServer := rollapp.NewMsgServerImpl(suite.App.RollappKeeper) _, err := msgServer.CreateRollapp(suite.Ctx, &msgCreateRollapp) suite.Require().NoError(err) return msgCreateRollapp.RollappId } func (suite *KeeperTestSuite) TransferRollappOwnership(currentOwner, newOwner sdk.AccAddress, rollappID string) { - rollappMsgServer := rollapp.NewMsgServerImpl(*suite.App.RollappKeeper) + rollappMsgServer := rollapp.NewMsgServerImpl(suite.App.RollappKeeper) resp, err := rollappMsgServer.TransferOwnership(suite.Ctx, &rollapptypes.MsgTransferOwnership{ CurrentOwner: currentOwner.String(), NewOwner: newOwner.String(), diff --git a/x/lightclient/ante/ibc_msg_update_client.go b/x/lightclient/ante/ibc_msg_update_client.go index 2451a1c7b..719151279 100644 --- a/x/lightclient/ante/ibc_msg_update_client.go +++ b/x/lightclient/ante/ibc_msg_update_client.go @@ -62,7 +62,17 @@ func (i IBCMessagesDecorator) HandleMsgUpdateClient(ctx sdk.Context, msg *ibccli return gerrc.ErrInternal.Wrapf("get rollapp from sequencer: rollapp: %s", seq.RollappId) } - // TODO: in hard fork will need to also use revision to make sure not from old revision + // cannot update the LC unless fork is resolved (after receiving state post fork state update) + if i.k.IsHardForkingInProgress(ctx, rollapp.RollappId) { + return types.ErrorHardForkInProgress + } + + // this disallows LC updates from previous revisions but should be fine since new state roots can be used to prove + // state older than the one in the current state root. + if header.Header.Version.App != rollapp.RevisionNumber { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "client update revision mismatch") + } + h := header.GetHeight().GetRevisionHeight() stateInfos, err := i.getStateInfos(ctx, rollapp.RollappId, h) if err != nil { diff --git a/x/lightclient/ante/ibc_msgs_test.go b/x/lightclient/ante/ibc_msgs_test.go index eb8ae92e7..6eeed99d6 100644 --- a/x/lightclient/ante/ibc_msgs_test.go +++ b/x/lightclient/ante/ibc_msgs_test.go @@ -3,6 +3,7 @@ package ante_test import ( "context" + "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" @@ -16,6 +17,11 @@ type MockRollappKeeper struct { stateInfos map[string]map[uint64]rollapptypes.StateInfo } +// GetLatestStateInfo implements types.RollappKeeperExpected. +func (m *MockRollappKeeper) GetLatestStateInfo(ctx sdk.Context, rollappId string) (rollapptypes.StateInfo, bool) { + return rollapptypes.StateInfo{}, false +} + func NewMockRollappKeeper(rollapps map[string]rollapptypes.Rollapp, stateInfos map[string]map[uint64]rollapptypes.StateInfo) *MockRollappKeeper { return &MockRollappKeeper{ rollapps: rollapps, @@ -53,7 +59,7 @@ func (m *MockRollappKeeper) GetStateInfo(ctx sdk.Context, rollappId string, inde return val, found } -func (m *MockRollappKeeper) HandleFraud(ctx sdk.Context, rollappID, clientId string, fraudHeight uint64, seqAddr string) error { +func (m *MockRollappKeeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error { return nil } @@ -61,6 +67,11 @@ type MockIBCClientKeeper struct { clientStates map[string]exported.ClientState } +// ClientStore implements types.IBCClientKeeperExpected. +func (m *MockIBCClientKeeper) ClientStore(ctx sdk.Context, clientID string) types.KVStore { + panic("unimplemented") +} + func NewMockIBCClientKeeper(cs map[string]exported.ClientState) *MockIBCClientKeeper { return &MockIBCClientKeeper{ clientStates: cs, diff --git a/x/lightclient/keeper/canonical_client.go b/x/lightclient/keeper/canonical_client.go index 3cd199545..ba192cf50 100644 --- a/x/lightclient/keeper/canonical_client.go +++ b/x/lightclient/keeper/canonical_client.go @@ -9,6 +9,7 @@ import ( ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/dymensionxyz/dymension/v3/x/lightclient/types" ) @@ -62,7 +63,7 @@ func (k Keeper) GetAllCanonicalClients(ctx sdk.Context) (clients []types.Canonic return } -func (k Keeper) expectedClient(ctx sdk.Context) ibctm.ClientState { +func (k Keeper) expectedClient() ibctm.ClientState { return types.DefaultExpectedCanonicalClientParams() } @@ -77,11 +78,13 @@ func (k Keeper) validClient(ctx sdk.Context, clientID string, cs exported.Client return errChainIDMismatch } - expClient := k.expectedClient(ctx) + expClient := k.expectedClient() if err := types.IsCanonicalClientParamsValid(tmClientState, &expClient); err != nil { return errorsmod.Wrap(err, "params") } + + // FIXME: No need to get all consensus states. should iterate over the consensus states res, err := k.ibcClientKeeper.ConsensusStateHeights(ctx, &ibcclienttypes.QueryConsensusStateHeightsRequest{ ClientId: clientID, Pagination: &query.PageRequest{Limit: maxHeight}, diff --git a/x/lightclient/keeper/client_store.go b/x/lightclient/keeper/client_store.go new file mode 100644 index 000000000..5e91401b8 --- /dev/null +++ b/x/lightclient/keeper/client_store.go @@ -0,0 +1,86 @@ +package keeper + +import ( + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + "github.com/cosmos/ibc-go/v7/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" +) + +// functions here copied from ibc-go/modules/core/02-client/keeper/ +// as we need direct access to the client store + +// getClientState returns the client state for a particular client +func getClientState(clientStore sdk.KVStore, cdc codec.BinaryCodec) exported.ClientState { + bz := clientStore.Get(host.ClientStateKey()) + if len(bz) == 0 { + return nil + } + + return clienttypes.MustUnmarshalClientState(cdc, bz) +} + +// setClientState stores the client state +func setClientState(clientStore sdk.KVStore, cdc codec.BinaryCodec, clientState exported.ClientState) { + key := host.ClientStateKey() + val := clienttypes.MustMarshalClientState(cdc, clientState) + clientStore.Set(key, val) +} + +func setConsensusState(clientStore sdk.KVStore, cdc codec.BinaryCodec, height exported.Height, cs exported.ConsensusState) { + key := host.ConsensusStateKey(height) + val := clienttypes.MustMarshalConsensusState(cdc, cs) + clientStore.Set(key, val) +} + +// setConsensusMetadata sets context time as processed time and set context height as processed height +// as this is internal tendermint light client logic. +// client state and consensus state will be set by client keeper +// set iteration key to provide ability for efficient ordered iteration of consensus states. +func setConsensusMetadata(ctx sdk.Context, clientStore sdk.KVStore, height exported.Height) { + setConsensusMetadataWithValues(clientStore, height, clienttypes.GetSelfHeight(ctx), uint64(ctx.BlockTime().UnixNano())) +} + +// setConsensusMetadataWithValues sets the consensus metadata with the provided values +func setConsensusMetadataWithValues( + clientStore sdk.KVStore, height, + processedHeight exported.Height, + processedTime uint64, +) { + ibctm.SetProcessedTime(clientStore, height, processedTime) + ibctm.SetProcessedHeight(clientStore, height, processedHeight) + ibctm.SetIterationKey(clientStore, height) +} + +// deleteConsensusMetadata deletes the metadata stored for a particular consensus state. +func deleteConsensusMetadata(clientStore sdk.KVStore, height exported.Height) { + deleteProcessedTime(clientStore, height) + deleteProcessedHeight(clientStore, height) + deleteIterationKey(clientStore, height) +} + +// deleteConsensusState deletes the consensus state at the given height +func deleteConsensusState(clientStore sdk.KVStore, height exported.Height) { + key := host.ConsensusStateKey(height) + clientStore.Delete(key) +} + +// deleteProcessedTime deletes the processedTime for a given height +func deleteProcessedTime(clientStore sdk.KVStore, height exported.Height) { + key := ibctm.ProcessedTimeKey(height) + clientStore.Delete(key) +} + +// deleteProcessedHeight deletes the processedHeight for a given height +func deleteProcessedHeight(clientStore sdk.KVStore, height exported.Height) { + key := ibctm.ProcessedHeightKey(height) + clientStore.Delete(key) +} + +// deleteIterationKey deletes the iteration key for a given height +func deleteIterationKey(clientStore sdk.KVStore, height exported.Height) { + key := ibctm.IterationKey(height) + clientStore.Delete(key) +} diff --git a/x/lightclient/keeper/genesis.go b/x/lightclient/keeper/genesis.go index 2cc0d3c2f..155e9a290 100644 --- a/x/lightclient/keeper/genesis.go +++ b/x/lightclient/keeper/genesis.go @@ -3,6 +3,7 @@ package keeper import ( "cosmossdk.io/collections" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/x/lightclient/types" ) @@ -18,13 +19,18 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genesisState types.GenesisState) { panic(err) } } + for _, rollappID := range genesisState.HardForkKeys { + k.SetHardForkInProgress(ctx, rollappID) + } } func (k Keeper) ExportGenesis(ctx sdk.Context) types.GenesisState { clients := k.GetAllCanonicalClients(ctx) + hardForkKeys := k.ListHardForkKeys(ctx) ret := types.GenesisState{ CanonicalClients: clients, + HardForkKeys: hardForkKeys, } if err := k.headerSigners.Walk(ctx, nil, diff --git a/x/lightclient/keeper/genesis_test.go b/x/lightclient/keeper/genesis_test.go index c3d240742..ac0efff28 100644 --- a/x/lightclient/keeper/genesis_test.go +++ b/x/lightclient/keeper/genesis_test.go @@ -4,9 +4,10 @@ import ( "reflect" "testing" + "github.com/stretchr/testify/require" + keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" "github.com/dymensionxyz/dymension/v3/x/lightclient/types" - "github.com/stretchr/testify/require" ) func TestInitGenesis(t *testing.T) { @@ -18,6 +19,7 @@ func TestInitGenesis(t *testing.T) { keeper.InitGenesis(ctx, types.GenesisState{ CanonicalClients: clients, + HardForkKeys: []string{"rollapp-1", "rollapp-2"}, }) ibc, found := keeper.GetCanonicalClient(ctx, "rollapp-1") @@ -26,6 +28,10 @@ func TestInitGenesis(t *testing.T) { ibc, found = keeper.GetCanonicalClient(ctx, "rollapp-2") require.True(t, found) require.Equal(t, "client-2", ibc) + hfks := keeper.ListHardForkKeys(ctx) + require.Len(t, hfks, 2) + require.Equal(t, "rollapp-1", hfks[0]) + require.Equal(t, "rollapp-2", hfks[1]) } func TestExportGenesis(t *testing.T) { @@ -33,6 +39,8 @@ func TestExportGenesis(t *testing.T) { keeper.SetCanonicalClient(ctx, "rollapp-1", "client-1") keeper.SetCanonicalClient(ctx, "rollapp-2", "client-2") + keeper.SetHardForkInProgress(ctx, "rollapp-1") + keeper.SetHardForkInProgress(ctx, "rollapp-2") genesis := keeper.ExportGenesis(ctx) @@ -41,6 +49,9 @@ func TestExportGenesis(t *testing.T) { require.Equal(t, "client-2", genesis.CanonicalClients[1].IbcClientId) require.Equal(t, "rollapp-1", genesis.CanonicalClients[0].RollappId) require.Equal(t, "rollapp-2", genesis.CanonicalClients[1].RollappId) + require.Len(t, genesis.HardForkKeys, 2) + require.Equal(t, "rollapp-1", genesis.HardForkKeys[0]) + require.Equal(t, "rollapp-2", genesis.HardForkKeys[1]) } func TestImportExportGenesis(t *testing.T) { @@ -69,6 +80,7 @@ func TestImportExportGenesis(t *testing.T) { Height: 43, }, }, + HardForkKeys: []string{"rollapp-1", "rollapp-2"}, } k.InitGenesis(ctx, g) diff --git a/x/lightclient/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index 5dde28b9b..8a47e965a 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -48,6 +48,15 @@ func (hook rollappHook) AfterUpdateState( return nil } + // first state after hardfork, should reset the client to active state + if hook.k.IsHardForkingInProgress(ctx, rollappId) { + err := hook.k.ResolveHardFork(ctx, rollappId) + if err != nil { + return errorsmod.Wrap(err, "resolve hard fork") + } + return nil + } + // TODO: check hard fork in progress here seq, err := hook.k.SeqK.RealSequencer(ctx, stateInfo.Sequencer) @@ -65,8 +74,7 @@ func (hook rollappHook) AfterUpdateState( // we now verified everything up to and including stateInfo.GetLatestHeight()-1 // so we should prune everything up to stateInfo.GetLatestHeight()-1 // this removes the unbonding condition for the sequencers - // TODO: when integrating with hard fork PR need to change rollapp argument to client argument - if err := hook.k.PruneSignersBelow(ctx, rollappId, stateInfo.GetLatestHeight()); err != nil { + if err := hook.k.PruneSignersBelow(ctx, client, stateInfo.GetLatestHeight()); err != nil { return errorsmod.Wrap(err, "prune signers") } diff --git a/x/lightclient/keeper/keeper.go b/x/lightclient/keeper/keeper.go index 4b1eea520..ad2c1c685 100644 --- a/x/lightclient/keeper/keeper.go +++ b/x/lightclient/keeper/keeper.go @@ -9,13 +9,15 @@ import ( errorsmod "cosmossdk.io/errors" "github.com/cometbft/cometbft/libs/log" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" + "github.com/dymensionxyz/dymension/v3/internal/collcompat" "github.com/dymensionxyz/dymension/v3/x/lightclient/types" sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" - "github.com/dymensionxyz/gerr-cosmos/gerrc" ) func (k Keeper) Logger(ctx sdk.Context) log.Logger { @@ -96,71 +98,16 @@ func (k Keeper) CanUnbond(ctx sdk.Context, seq sequencertypes.Sequencer) error { }) } -// PruneSignersAbove removes bookkeeping for all heights ABOVE h for given rollapp +// PruneSignersAbove removes bookkeeping for all heights ABOVE h for given client // This should only be called after canonical client set -// TODO: plug into hard fork -func (k Keeper) PruneSignersAbove(ctx sdk.Context, rollapp string, h uint64) error { - client, ok := k.GetCanonicalClient(ctx, rollapp) - if !ok { - return gerrc.ErrInternal.Wrap(` -prune light client signers for rollapp before canonical client is set -this suggests fork happened prior to genesis bridge completion, which -shouldnt be allowed -`) - } - rng := collections.NewPrefixedPairRange[string, uint64](client).StartExclusive(h) - - seqs := make([]string, 0) - heights := make([]uint64, 0) - - // collect first to avoid del while iterating - if err := k.clientHeightToSigner.Walk(ctx, rng, func(key collections.Pair[string, uint64], value string) (stop bool, err error) { - seqs = append(seqs, value) - heights = append(heights, key.K2()) - return false, nil - }); err != nil { - return errorsmod.Wrap(err, "walk signers") - } - - for i := 0; i < len(seqs); i++ { - if err := k.RemoveSigner(ctx, seqs[i], client, heights[i]); err != nil { - return errorsmod.Wrap(err, "remove signer") - } - } - return nil +func (k Keeper) PruneSignersAbove(ctx sdk.Context, client string, h uint64) error { + return k.pruneSigners(ctx, client, h, true) } -// PruneSignersBelow removes bookkeeping for all heights BELOW h for given rollapp +// PruneSignersBelow removes bookkeeping for all heights BELOW h for given clientId // This should only be called after canonical client set -func (k Keeper) PruneSignersBelow(ctx sdk.Context, rollapp string, h uint64) error { - client, ok := k.GetCanonicalClient(ctx, rollapp) - if !ok { - return gerrc.ErrInternal.Wrap(` -prune light client signers for rollapp before canonical client is set -this suggests fork happened prior to genesis bridge completion, which -shouldnt be allowed -`) - } - rng := collections.NewPrefixedPairRange[string, uint64](client).EndExclusive(h) - - seqs := make([]string, 0) - heights := make([]uint64, 0) - - // collect first to avoid del while iterating - if err := k.clientHeightToSigner.Walk(ctx, rng, func(key collections.Pair[string, uint64], value string) (stop bool, err error) { - seqs = append(seqs, value) - heights = append(heights, key.K2()) - return false, nil - }); err != nil { - return errorsmod.Wrap(err, "walk signers") - } - - for i := 0; i < len(seqs); i++ { - if err := k.RemoveSigner(ctx, seqs[i], client, heights[i]); err != nil { - return errorsmod.Wrap(err, "remove signer") - } - } - return nil +func (k Keeper) PruneSignersBelow(ctx sdk.Context, client string, h uint64) error { + return k.pruneSigners(ctx, client, h, false) } // GetSigner returns the sequencer address who signed the header in the update @@ -197,12 +144,64 @@ func (k Keeper) LightClient(goCtx context.Context, req *types.QueryGetLightClien return &types.QueryGetLightClientResponse{ClientId: id}, nil } -func (k Keeper) ExpectedClientState(goCtx context.Context, req *types.QueryExpectedClientStateRequest) (*types.QueryExpectedClientStateResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - c := k.expectedClient(ctx) +func (k Keeper) ExpectedClientState(context.Context, *types.QueryExpectedClientStateRequest) (*types.QueryExpectedClientStateResponse, error) { + c := k.expectedClient() anyClient, err := ibcclienttypes.PackClientState(&c) if err != nil { return nil, errorsmod.Wrap(errors.Join(gerrc.ErrInternal, err), "pack client state") } return &types.QueryExpectedClientStateResponse{ClientState: anyClient}, nil } + +func (k Keeper) SetHardForkInProgress(ctx sdk.Context, rollappID string) { + ctx.KVStore(k.storeKey).Set(types.HardForkKey(rollappID), []byte{0x01}) +} + +// remove the hardfork key from the store +func (k Keeper) setHardForkResolved(ctx sdk.Context, rollappID string) { + ctx.KVStore(k.storeKey).Delete(types.HardForkKey(rollappID)) +} + +// checks if rollapp is hard forking +func (k Keeper) IsHardForkingInProgress(ctx sdk.Context, rollappID string) bool { + return ctx.KVStore(k.storeKey).Has(types.HardForkKey(rollappID)) +} + +func (k Keeper) ListHardForkKeys(ctx sdk.Context) []string { + prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), types.HardForkPrefix) + iter := prefixStore.Iterator(nil, nil) + defer iter.Close() // nolint: errcheck + var ret []string + for ; iter.Valid(); iter.Next() { + ret = append(ret, string(iter.Key())) + } + return ret +} + +func (k Keeper) pruneSigners(ctx sdk.Context, client string, h uint64, isAbove bool) error { + var rng *collections.PairRange[string, uint64] + if isAbove { + rng = collections.NewPrefixedPairRange[string, uint64](client).StartExclusive(h) + } else { + rng = collections.NewPrefixedPairRange[string, uint64](client).EndExclusive(h) + } + + seqs := make([]string, 0) + heights := make([]uint64, 0) + + // collect first to avoid del while iterating + if err := k.clientHeightToSigner.Walk(ctx, rng, func(key collections.Pair[string, uint64], value string) (stop bool, err error) { + seqs = append(seqs, value) + heights = append(heights, key.K2()) + return false, nil + }); err != nil { + return errorsmod.Wrap(err, "walk signers") + } + + for i := 0; i < len(seqs); i++ { + if err := k.RemoveSigner(ctx, seqs[i], client, heights[i]); err != nil { + return errorsmod.Wrap(err, "remove signer") + } + } + return nil +} diff --git a/x/lightclient/keeper/keeper_test.go b/x/lightclient/keeper/keeper_test.go index ea5c59758..80cf0d554 100644 --- a/x/lightclient/keeper/keeper_test.go +++ b/x/lightclient/keeper/keeper_test.go @@ -56,7 +56,7 @@ func (s *TestSuite) TestUnbondConditionFlow() { utest.IsErr(s.Require(), err, sequencertypes.ErrUnbondNotAllowed) // we prune some, but still not allowed - err = s.k().PruneSignersAbove(s.Ctx, seq.RollappId, 6) + err = s.k().PruneSignersAbove(s.Ctx, client, 6) s.Require().NoError(err) err = s.k().CanUnbond(s.Ctx, seq) @@ -97,7 +97,7 @@ func (s *TestSuite) TestPruneBelow() { utest.IsErr(s.Require(), err, sequencertypes.ErrUnbondNotAllowed) // we prune some, but still not allowed - err = s.k().PruneSignersBelow(s.Ctx, seq.RollappId, 6) + err = s.k().PruneSignersBelow(s.Ctx, client, 6) s.Require().NoError(err) err = s.k().CanUnbond(s.Ctx, seq) diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go new file mode 100644 index 000000000..b5fbfae71 --- /dev/null +++ b/x/lightclient/keeper/rollback.go @@ -0,0 +1,125 @@ +package keeper + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/dymensionxyz/gerr-cosmos/gerrc" + + clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" + commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" + + ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" +) + +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappId string, newRevisionHeight uint64) error { + return hook.k.RollbackCanonicalClient(ctx, rollappId, newRevisionHeight) +} + +func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, newRevisionHeight uint64) error { + client, found := k.GetCanonicalClient(ctx, rollappId) + if !found { + return gerrc.ErrFailedPrecondition.Wrap("canonical client not found") + } + cs := k.ibcClientKeeper.ClientStore(ctx, client) + + // iterate over all consensus states and metadata in the client store + IterateConsensusStateDescending(cs, func(h exported.Height) bool { + // iterate until we pass the new revision height + if h.GetRevisionHeight() < newRevisionHeight { + return true + } + + // delete consensus state and metadata + deleteConsensusState(cs, h) + deleteConsensusMetadata(cs, h) + + return false + }) + + // clean the optimistic updates valset + err := k.PruneSignersAbove(ctx, client, newRevisionHeight-1) + if err != nil { + return errorsmod.Wrap(err, "prune signers above") + } + + // marks that hard fork is in progress + k.SetHardForkInProgress(ctx, rollappId) + + // freeze the client + // it will be released after the hardfork is resolved (on the next state update) + k.freezeClient(cs, newRevisionHeight) + + return nil +} + +// ResolveHardFork resolves the hard fork by resetting the client to the valid state +// and adding consensus states based on the block descriptors +// CONTRACT: canonical client is already set, state info exists +func (k Keeper) ResolveHardFork(ctx sdk.Context, rollappID string) error { + client, _ := k.GetCanonicalClient(ctx, rollappID) // already checked in the caller + clientStore := k.ibcClientKeeper.ClientStore(ctx, client) + + stateinfo, _ := k.rollappKeeper.GetLatestStateInfo(ctx, rollappID) // already checked in the caller + height := stateinfo.StartHeight + bd := stateinfo.BDs.BD[0] + + // get the valHash of this sequencer + // we assume the proposer of the first state update after the hard fork won't be rotated in the next block + proposer, _ := k.SeqK.RealSequencer(ctx, stateinfo.Sequencer) + valHash, _ := proposer.ValsetHash() + + // unfreeze the client and set the latest height + k.resetClientToValidState(clientStore, height) + // add consensus states based on the block descriptors + cs := ibctm.ConsensusState{ + Timestamp: bd.Timestamp, + Root: commitmenttypes.NewMerkleRoot(bd.StateRoot), + NextValidatorsHash: valHash, + } + + setConsensusState(clientStore, k.cdc, clienttypes.NewHeight(1, height), &cs) + setConsensusMetadata(ctx, clientStore, clienttypes.NewHeight(1, height)) + + k.setHardForkResolved(ctx, rollappID) + return nil +} + +// freezeClient freezes the client by setting the frozen height to the current height +func (k Keeper) freezeClient(clientStore sdk.KVStore, height uint64) { + c := getClientState(clientStore, k.cdc) + tmClientState, _ := c.(*ibctm.ClientState) + + // freeze the client + tmClientState.FrozenHeight = clienttypes.NewHeight(1, height) + tmClientState.LatestHeight = clienttypes.NewHeight(1, height) + + setClientState(clientStore, k.cdc, tmClientState) +} + +// freezeClient freezes the client by setting the frozen height to the current height +func (k Keeper) resetClientToValidState(clientStore sdk.KVStore, height uint64) { + c := getClientState(clientStore, k.cdc) + tmClientState, _ := c.(*ibctm.ClientState) + + // unfreeze the client and set the latest height + tmClientState.FrozenHeight = clienttypes.ZeroHeight() + tmClientState.LatestHeight = clienttypes.NewHeight(1, height) + + setClientState(clientStore, k.cdc, tmClientState) +} + +// IterateConsensusStateDescending iterates through all consensus states in descending order +// until cb returns true. +func IterateConsensusStateDescending(clientStore sdk.KVStore, cb func(height exported.Height) (stop bool)) { + iterator := sdk.KVStoreReversePrefixIterator(clientStore, []byte(ibctm.KeyIterateConsensusStatePrefix)) + defer iterator.Close() // nolint: errcheck + + for ; iterator.Valid(); iterator.Next() { + iterKey := iterator.Key() + height := ibctm.GetHeightFromIterationKey(iterKey) + if cb(height) { + break + } + } +} diff --git a/x/lightclient/types/errors.go b/x/lightclient/types/errors.go index f5d6fb055..c4f3b1517 100644 --- a/x/lightclient/types/errors.go +++ b/x/lightclient/types/errors.go @@ -9,4 +9,8 @@ var ( ErrStateRootsMismatch = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "block descriptor state root does not match tendermint header app hash") ErrValidatorHashMismatch = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "next validator hash does not match the sequencer for h+1") ErrTimestampMismatch = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "block descriptor timestamp does not match tendermint header timestamp") + ErrSequencerNotFound = errorsmod.Wrap(gerrc.ErrNotFound, "sequencer for given valhash") + ErrorMissingClientState = errorsmod.Wrap(gerrc.ErrInternal, "client state was expected, but not found") + ErrorInvalidClientType = errorsmod.Wrap(gerrc.ErrInternal, "client state is not a tendermint client") + ErrorHardForkInProgress = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "update light client until forking is finished") ) diff --git a/x/lightclient/types/expected_keepers.go b/x/lightclient/types/expected_keepers.go index a368071e5..59999b6d1 100644 --- a/x/lightclient/types/expected_keepers.go +++ b/x/lightclient/types/expected_keepers.go @@ -20,8 +20,8 @@ type SequencerKeeperExpected interface { type RollappKeeperExpected interface { GetRollapp(ctx sdk.Context, rollappId string) (val rollapptypes.Rollapp, found bool) FindStateInfoByHeight(ctx sdk.Context, rollappId string, height uint64) (*rollapptypes.StateInfo, error) + GetLatestStateInfo(ctx sdk.Context, rollappId string) (rollapptypes.StateInfo, bool) SetRollapp(ctx sdk.Context, rollapp rollapptypes.Rollapp) - HandleFraud(ctx sdk.Context, rollappID, clientId string, fraudHeight uint64, seqAddr string) error } type IBCClientKeeperExpected interface { @@ -29,6 +29,7 @@ type IBCClientKeeperExpected interface { GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) IterateClientStates(ctx sdk.Context, prefix []byte, cb func(clientID string, cs exported.ClientState) bool) ConsensusStateHeights(c context.Context, req *ibcclienttypes.QueryConsensusStateHeightsRequest) (*ibcclienttypes.QueryConsensusStateHeightsResponse, error) + ClientStore(ctx sdk.Context, clientID string) sdk.KVStore } type IBCChannelKeeperExpected interface { diff --git a/x/lightclient/types/genesis.go b/x/lightclient/types/genesis.go index d6c0b2399..d12d11eae 100644 --- a/x/lightclient/types/genesis.go +++ b/x/lightclient/types/genesis.go @@ -1,6 +1,6 @@ package types -import fmt "fmt" +import "fmt" func DefaultGenesisState() GenesisState { return GenesisState{ diff --git a/x/lightclient/types/genesis.pb.go b/x/lightclient/types/genesis.pb.go index 737c834f9..94c4e0e5b 100644 --- a/x/lightclient/types/genesis.pb.go +++ b/x/lightclient/types/genesis.pb.go @@ -88,6 +88,7 @@ func (m *HeaderSignerEntry) GetHeight() uint64 { type GenesisState struct { CanonicalClients []CanonicalClient `protobuf:"bytes,1,rep,name=canonical_clients,json=canonicalClients,proto3" json:"canonical_clients"` HeaderSigners []HeaderSignerEntry `protobuf:"bytes,3,rep,name=header_signers,json=headerSigners,proto3" json:"header_signers"` + HardForkKeys []string `protobuf:"bytes,4,rep,name=hard_fork_keys,json=hardForkKeys,proto3" json:"hard_fork_keys,omitempty"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -137,6 +138,13 @@ func (m *GenesisState) GetHeaderSigners() []HeaderSignerEntry { return nil } +func (m *GenesisState) GetHardForkKeys() []string { + if m != nil { + return m.HardForkKeys + } + return nil +} + type CanonicalClient struct { RollappId string `protobuf:"bytes,1,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` IbcClientId string `protobuf:"bytes,2,opt,name=ibc_client_id,json=ibcClientId,proto3" json:"ibc_client_id,omitempty"` @@ -200,30 +208,32 @@ func init() { } var fileDescriptor_5520440548912168 = []byte{ - // 363 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x4f, 0x4b, 0xfb, 0x40, - 0x14, 0x4c, 0x7e, 0x2d, 0xe5, 0xd7, 0xad, 0xd5, 0x76, 0x11, 0x09, 0x8a, 0xb1, 0xe4, 0x54, 0x10, - 0x12, 0xb1, 0x08, 0x5e, 0x6d, 0x11, 0xed, 0x35, 0xf5, 0xe4, 0x25, 0x24, 0x9b, 0x67, 0xb2, 0x90, - 0xee, 0xc6, 0xec, 0x56, 0x1a, 0x3f, 0x85, 0x1f, 0xab, 0xc7, 0x1e, 0xc5, 0x83, 0x48, 0xfb, 0x45, - 0x24, 0x7f, 0x2c, 0x6d, 0x45, 0xf4, 0xb6, 0x33, 0xfb, 0x86, 0x79, 0x33, 0x3c, 0x74, 0xe6, 0xa7, - 0x63, 0x60, 0x82, 0x72, 0x36, 0x4d, 0x9f, 0xad, 0x15, 0xb0, 0x22, 0x1a, 0x84, 0x92, 0x44, 0x14, - 0x98, 0xb4, 0x02, 0x60, 0x20, 0xa8, 0x30, 0xe3, 0x84, 0x4b, 0x8e, 0x8d, 0x75, 0x85, 0xb9, 0x02, - 0xe6, 0x9a, 0xe2, 0x70, 0x3f, 0xe0, 0x01, 0xcf, 0xc7, 0xad, 0xec, 0x55, 0x28, 0x8d, 0x09, 0x6a, - 0xdf, 0x82, 0xeb, 0x43, 0x32, 0xa2, 0x01, 0x83, 0xe4, 0x9a, 0xc9, 0x24, 0xc5, 0xa7, 0xa8, 0x2d, - 0xe0, 0x71, 0x02, 0x8c, 0x40, 0xe2, 0xb8, 0xbe, 0x9f, 0x80, 0x10, 0x9a, 0xda, 0x51, 0xbb, 0x75, - 0xbb, 0xb5, 0xfa, 0xb8, 0x2a, 0x78, 0x7c, 0x84, 0xea, 0x85, 0x83, 0x43, 0x7d, 0xed, 0x5f, 0x3e, - 0xf4, 0xbf, 0x20, 0x86, 0x3e, 0x3e, 0x40, 0xb5, 0x10, 0xb2, 0x25, 0xb4, 0x4a, 0x47, 0xed, 0x56, - 0xed, 0x12, 0x19, 0x6f, 0x2a, 0xda, 0xb9, 0x29, 0x22, 0x8c, 0xa4, 0x2b, 0x01, 0x3f, 0xa0, 0x36, - 0x71, 0x19, 0x67, 0x94, 0xb8, 0x91, 0x53, 0xc8, 0x33, 0xcb, 0x4a, 0xb7, 0x71, 0xde, 0x33, 0x7f, - 0x4f, 0x67, 0x0e, 0xbe, 0xc4, 0x83, 0x1c, 0xf7, 0xab, 0xb3, 0xf7, 0x13, 0xc5, 0x6e, 0x91, 0x4d, - 0x5a, 0x60, 0x0f, 0xed, 0x86, 0x79, 0x5e, 0x47, 0xe4, 0x81, 0x85, 0x56, 0xc9, 0x4d, 0x2e, 0xfe, - 0x62, 0xf2, 0xad, 0xa9, 0xd2, 0xa6, 0x19, 0xae, 0x7d, 0x08, 0xe3, 0x0e, 0xed, 0x6d, 0xad, 0x83, - 0x8f, 0x11, 0x4a, 0x78, 0x14, 0xb9, 0x71, 0x9c, 0xb5, 0x54, 0x54, 0x59, 0x2f, 0x99, 0xa1, 0x8f, - 0x0d, 0xd4, 0xa4, 0x1e, 0x71, 0xb6, 0x7b, 0x6c, 0x50, 0x8f, 0x0c, 0xca, 0x2a, 0xfb, 0xf6, 0x6c, - 0xa1, 0xab, 0xf3, 0x85, 0xae, 0x7e, 0x2c, 0x74, 0xf5, 0x65, 0xa9, 0x2b, 0xf3, 0xa5, 0xae, 0xbc, - 0x2e, 0x75, 0xe5, 0xfe, 0x32, 0xa0, 0x32, 0x9c, 0x78, 0x26, 0xe1, 0x63, 0xeb, 0x87, 0xd3, 0x79, - 0xea, 0x59, 0xd3, 0x8d, 0xfb, 0x91, 0x69, 0x0c, 0xc2, 0xab, 0xe5, 0x47, 0xd0, 0xfb, 0x0c, 0x00, - 0x00, 0xff, 0xff, 0xb7, 0x25, 0x65, 0x00, 0x72, 0x02, 0x00, 0x00, + // 395 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0xcd, 0xca, 0xd3, 0x40, + 0x14, 0x4d, 0xbe, 0x94, 0x0f, 0x33, 0xdf, 0x8f, 0xed, 0x20, 0x12, 0x14, 0x63, 0x09, 0x2e, 0x02, + 0x42, 0x22, 0x16, 0xc1, 0xad, 0x2d, 0xfe, 0x14, 0x77, 0xa9, 0x2b, 0x37, 0x21, 0x99, 0xb9, 0x4d, + 0x86, 0xa6, 0x33, 0x71, 0x66, 0x2a, 0x8d, 0x2b, 0x1f, 0xc1, 0xc7, 0xea, 0xb2, 0x4b, 0x57, 0x22, + 0xed, 0x8b, 0x48, 0x7e, 0x2c, 0x6d, 0x45, 0x74, 0x37, 0xe7, 0xcc, 0x3d, 0x9c, 0x7b, 0x0e, 0x17, + 0x3d, 0xa3, 0xd5, 0x12, 0xb8, 0x62, 0x82, 0xaf, 0xab, 0x2f, 0xe1, 0x01, 0x84, 0x05, 0xcb, 0x72, + 0x4d, 0x0a, 0x06, 0x5c, 0x87, 0x19, 0x70, 0x50, 0x4c, 0x05, 0xa5, 0x14, 0x5a, 0x60, 0xef, 0x58, + 0x11, 0x1c, 0x40, 0x70, 0xa4, 0x78, 0x70, 0x2f, 0x13, 0x99, 0x68, 0xc6, 0xc3, 0xfa, 0xd5, 0x2a, + 0xbd, 0x15, 0x1a, 0xbc, 0x83, 0x84, 0x82, 0x9c, 0xb1, 0x8c, 0x83, 0x7c, 0xcd, 0xb5, 0xac, 0xf0, + 0x53, 0x34, 0x50, 0xf0, 0x69, 0x05, 0x9c, 0x80, 0x8c, 0x13, 0x4a, 0x25, 0x28, 0xe5, 0x98, 0x43, + 0xd3, 0xb7, 0xa3, 0xfe, 0xe1, 0xe3, 0x55, 0xcb, 0xe3, 0x87, 0xc8, 0x6e, 0x1d, 0x62, 0x46, 0x9d, + 0x8b, 0x66, 0xe8, 0x4e, 0x4b, 0x4c, 0x29, 0xbe, 0x8f, 0x2e, 0x73, 0xa8, 0x97, 0x70, 0xac, 0xa1, + 0xe9, 0xf7, 0xa2, 0x0e, 0x79, 0x5f, 0x2f, 0xd0, 0xf5, 0xdb, 0x36, 0xc2, 0x4c, 0x27, 0x1a, 0xf0, + 0x1c, 0x0d, 0x48, 0xc2, 0x05, 0x67, 0x24, 0x29, 0xe2, 0x56, 0x5e, 0x5b, 0x5a, 0xfe, 0xd5, 0xf3, + 0x51, 0xf0, 0xef, 0x74, 0xc1, 0xe4, 0xb7, 0x78, 0xd2, 0xe0, 0x71, 0x6f, 0xf3, 0xe3, 0xb1, 0x11, + 0xf5, 0xc9, 0x29, 0xad, 0x70, 0x8a, 0x6e, 0xf3, 0x26, 0x6f, 0xac, 0x9a, 0xc0, 0xca, 0xb1, 0x1a, + 0x93, 0x17, 0xff, 0x63, 0xf2, 0x47, 0x53, 0x9d, 0xcd, 0x4d, 0x7e, 0xf4, 0xa1, 0xf0, 0x13, 0x74, + 0x9b, 0x27, 0x92, 0xc6, 0x73, 0x21, 0x17, 0xf1, 0x02, 0x2a, 0xe5, 0xf4, 0x86, 0x96, 0x6f, 0x47, + 0xd7, 0x35, 0xfb, 0x46, 0xc8, 0xc5, 0x7b, 0xa8, 0x94, 0xf7, 0x01, 0xdd, 0x3d, 0x5b, 0x1a, 0x3f, + 0x42, 0x48, 0x8a, 0xa2, 0x48, 0xca, 0xb2, 0xee, 0xb2, 0x2d, 0xdc, 0xee, 0x98, 0x29, 0xc5, 0x1e, + 0xba, 0x61, 0x29, 0x89, 0xcf, 0xdb, 0xbe, 0x62, 0x29, 0x99, 0x74, 0x85, 0x8f, 0xa3, 0xcd, 0xce, + 0x35, 0xb7, 0x3b, 0xd7, 0xfc, 0xb9, 0x73, 0xcd, 0x6f, 0x7b, 0xd7, 0xd8, 0xee, 0x5d, 0xe3, 0xfb, + 0xde, 0x35, 0x3e, 0xbe, 0xcc, 0x98, 0xce, 0x57, 0x69, 0x40, 0xc4, 0x32, 0xfc, 0xcb, 0x81, 0x7d, + 0x1e, 0x85, 0xeb, 0x93, 0x2b, 0xd3, 0x55, 0x09, 0x2a, 0xbd, 0x6c, 0x4e, 0x65, 0xf4, 0x2b, 0x00, + 0x00, 0xff, 0xff, 0x68, 0x01, 0x4e, 0x62, 0x98, 0x02, 0x00, 0x00, } func (m *HeaderSignerEntry) Marshal() (dAtA []byte, err error) { @@ -288,6 +298,15 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.HardForkKeys) > 0 { + for iNdEx := len(m.HardForkKeys) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.HardForkKeys[iNdEx]) + copy(dAtA[i:], m.HardForkKeys[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.HardForkKeys[iNdEx]))) + i-- + dAtA[i] = 0x22 + } + } if len(m.HeaderSigners) > 0 { for iNdEx := len(m.HeaderSigners) - 1; iNdEx >= 0; iNdEx-- { { @@ -405,6 +424,12 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.HardForkKeys) > 0 { + for _, s := range m.HardForkKeys { + l = len(s) + n += 1 + l + sovGenesis(uint64(l)) + } + } return n } @@ -661,6 +686,38 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field HardForkKeys", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.HardForkKeys = append(m.HardForkKeys, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/lightclient/types/keys.go b/x/lightclient/types/keys.go index 4b64bd35c..fe49e6e16 100644 --- a/x/lightclient/types/keys.go +++ b/x/lightclient/types/keys.go @@ -13,6 +13,7 @@ const ( var ( RollappClientKey = []byte{0x01} canonicalClientKey = []byte{0x04} + HardForkPrefix = []byte{0x05} HeaderSignersPrefixKey = collections.NewPrefix("headerSigners/") ClientHeightToSigner = collections.NewPrefix("clientHeightToSigner/") ) @@ -28,3 +29,9 @@ func CanonicalClientKey(clientID string) []byte { key = append(key, []byte(clientID)...) return key } + +func HardForkKey(rollappID string) []byte { + key := HardForkPrefix + key = append(key, []byte(rollappID)...) + return key +} diff --git a/x/rollapp/client/cli/query_latest_height.go b/x/rollapp/client/cli/query_latest_height.go index c4ca3b51f..531696335 100644 --- a/x/rollapp/client/cli/query_latest_height.go +++ b/x/rollapp/client/cli/query_latest_height.go @@ -1,8 +1,6 @@ package cli import ( - "context" - "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" @@ -34,7 +32,7 @@ func CmdShowLatestHeight() *cobra.Command { Finalized: argFinalized, } - res, err := queryClient.LatestHeight(context.Background(), req) + res, err := queryClient.LatestHeight(cmd.Context(), req) if err != nil { return err } diff --git a/x/rollapp/client/cli/tx_submit_fraud_proposal.go b/x/rollapp/client/cli/tx_submit_fraud_proposal.go deleted file mode 100644 index d90022e16..000000000 --- a/x/rollapp/client/cli/tx_submit_fraud_proposal.go +++ /dev/null @@ -1,62 +0,0 @@ -package cli - -import ( - "strconv" - - "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/client/tx" - govcli "github.com/cosmos/cosmos-sdk/x/gov/client/cli" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - "github.com/spf13/cobra" - - "github.com/dymensionxyz/dymension/v3/utils" - "github.com/dymensionxyz/dymension/v3/x/rollapp/types" -) - -// NewCmdSubmitFraudProposal submits a fraud proposal -func NewCmdSubmitFraudProposal() *cobra.Command { - cmd := &cobra.Command{ - Use: "submit-fraud-proposal ", - Short: "submit a fraud proposal", - Args: cobra.ExactArgs(4), - RunE: func(cmd *cobra.Command, args []string) error { - clientCtx, err := client.GetClientTxContext(cmd) - if err != nil { - return err - } - - proposal, deposit, err := utils.ParseProposal(cmd) - if err != nil { - return err - } - - rollappID := args[0] - height, err := strconv.ParseUint(args[1], 10, 64) - if err != nil { - return err - } - - proposerAddr := args[2] - ibcClientID := args[3] - - content := types.NewSubmitFraudProposal(proposal.Title, proposal.Description, rollappID, height, proposerAddr, ibcClientID) - msg, err := govtypes.NewMsgSubmitProposal(content, deposit, clientCtx.GetFromAddress()) - if err != nil { - return err - } - - txfCli, err := tx.NewFactoryCLI(clientCtx, cmd.Flags()) - if err != nil { - return err - } - txf := txfCli.WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) - return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) - }, - } - - cmd.Flags().String(govcli.FlagTitle, "", "The proposal title") - cmd.Flags().String(govcli.FlagDescription, "", "The proposal description") - cmd.Flags().String(govcli.FlagDeposit, "", "The proposal deposit") - - return cmd -} diff --git a/x/rollapp/client/proposal_handler.go b/x/rollapp/client/proposal_handler.go deleted file mode 100644 index 67a8cb083..000000000 --- a/x/rollapp/client/proposal_handler.go +++ /dev/null @@ -1,9 +0,0 @@ -package client - -import ( - govclient "github.com/cosmos/cosmos-sdk/x/gov/client" - - "github.com/dymensionxyz/dymension/v3/x/rollapp/client/cli" -) - -var SubmitFraudHandler = govclient.NewProposalHandler(cli.NewCmdSubmitFraudProposal) diff --git a/x/rollapp/genesis.go b/x/rollapp/genesis.go index 67adb5492..9880dcc32 100644 --- a/x/rollapp/genesis.go +++ b/x/rollapp/genesis.go @@ -51,9 +51,9 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) panic(err) } } - // Set all the vulnerable DRS versions - for _, elem := range genState.VulnerableDrsVersions { - err := k.SetVulnerableDRSVersion(ctx, elem) + // Set all the obsolete DRS versions + for _, elem := range genState.ObsoleteDrsVersions { + err := k.SetObsoleteDRSVersion(ctx, elem) if err != nil { panic(err) } @@ -102,11 +102,11 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { panic(err) } - drsVersions, err := k.GetAllVulnerableDRSVersions(ctx) + drsVersions, err := k.GetAllObsoleteDRSVersions(ctx) if err != nil { panic(err) } - genesis.VulnerableDrsVersions = drsVersions + genesis.ObsoleteDrsVersions = drsVersions return genesis } diff --git a/x/rollapp/genesis_test.go b/x/rollapp/genesis_test.go index c7fa7feb7..7511f8536 100644 --- a/x/rollapp/genesis_test.go +++ b/x/rollapp/genesis_test.go @@ -15,7 +15,7 @@ import ( func TestInitExportGenesis(t *testing.T) { const ( rollappID1 = "rollapp_1234-1" - rollappID2 = "rollupp_1235-2" + rollappID2 = "rollupp_1235-1" appID1 = "app1" appID2 = "app2" ) diff --git a/x/rollapp/keeper/block_height_to_finalization_queue.go b/x/rollapp/keeper/block_height_to_finalization_queue.go index 6278b1e9d..8dd77df3a 100644 --- a/x/rollapp/keeper/block_height_to_finalization_queue.go +++ b/x/rollapp/keeper/block_height_to_finalization_queue.go @@ -27,7 +27,6 @@ func (k Keeper) CanUnbond(ctx sdk.Context, seq sequencertypes.Sequencer) error { // PruneSequencerHeights removes bookkeeping for all heights ABOVE h for given sequencers // On rollback, this should be called passing all sequencers who sequenced a rolled back block -// TODO: plug into hard fork func (k Keeper) PruneSequencerHeights(ctx sdk.Context, sequencers []string, h uint64) error { for _, seqAddr := range sequencers { rng := collections.NewPrefixedPairRange[string, uint64](seqAddr).StartExclusive(h) diff --git a/x/rollapp/keeper/block_height_to_finalization_queue_test.go b/x/rollapp/keeper/block_height_to_finalization_queue_test.go index db088a178..a5a695301 100644 --- a/x/rollapp/keeper/block_height_to_finalization_queue_test.go +++ b/x/rollapp/keeper/block_height_to_finalization_queue_test.go @@ -888,11 +888,18 @@ func TestUnbondConditionFlow(t *testing.T) { require.NoError(t, err) } + pairs, err := k.AllSequencerHeightPairs(ctx) + require.NoError(t, err) + require.Len(t, pairs, 10) + err = k.CanUnbond(ctx, seq) require.True(t, errorsmod.IsOf(err, sequencertypes.ErrUnbondNotAllowed)) err = k.PruneSequencerHeights(ctx, []string{seq.Address}, 6) require.NoError(t, err) + pairs, err = k.AllSequencerHeightPairs(ctx) + require.NoError(t, err) + require.Len(t, pairs, 7) // removed heights above 6 err = k.CanUnbond(ctx, seq) require.True(t, errorsmod.IsOf(err, sequencertypes.ErrUnbondNotAllowed)) diff --git a/x/rollapp/keeper/expected_keepers.go b/x/rollapp/keeper/expected_keepers.go index 10f00d5b7..46c5dbabf 100644 --- a/x/rollapp/keeper/expected_keepers.go +++ b/x/rollapp/keeper/expected_keepers.go @@ -9,21 +9,13 @@ import ( "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) -type AccountKeeper interface { - GetModuleAddress(name string) sdk.AccAddress -} - -type IBCClientKeeper interface { - GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) - SetClientState(ctx sdk.Context, clientID string, clientState exported.ClientState) -} - type ChannelKeeper interface { GetChannelClientState(ctx sdk.Context, portID, channelID string) (string, exported.ClientState, error) } type SequencerKeeper interface { SlashLiveness(ctx sdk.Context, rollappID string) error + PunishSequencer(ctx sdk.Context, seqAddr string, rewardee *sdk.AccAddress) error GetProposer(ctx sdk.Context, rollappId string) types.Sequencer } diff --git a/x/rollapp/keeper/fraud_handler.go b/x/rollapp/keeper/fraud_handler.go deleted file mode 100644 index 1d0d6aadf..000000000 --- a/x/rollapp/keeper/fraud_handler.go +++ /dev/null @@ -1,113 +0,0 @@ -package keeper - -import ( - "errors" - "fmt" - - errorsmod "cosmossdk.io/errors" - - sdk "github.com/cosmos/cosmos-sdk/types" - - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - cometbfttypes "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" - - common "github.com/dymensionxyz/dymension/v3/x/common/types" - "github.com/dymensionxyz/dymension/v3/x/rollapp/types" -) - -// HandleFraud handles the fraud evidence submitted by the user. -func (k Keeper) HandleFraud(ctx sdk.Context, rollappID, clientID string, fraudHeight uint64, seqAddr string) error { - stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, fraudHeight) - if err != nil { - return err - } - - // check height is not finalized - if stateInfo.Status == common.Status_FINALIZED { - return errorsmod.Wrapf(types.ErrDisputeAlreadyFinalized, "state info for height %d is already finalized", fraudHeight) - } - - // check height is not reverted - if stateInfo.Status == common.Status_REVERTED { - return errorsmod.Wrapf(types.ErrDisputeAlreadyReverted, "state info for height %d is already reverted", fraudHeight) - } - - // check the sequencer for this height is the same as the one in the fraud evidence - if stateInfo.Sequencer != seqAddr { - return errorsmod.Wrapf(types.ErrWrongProposerAddr, "sequencer address %s does not match the one in the state info", seqAddr) - } - - // check that the clientID is correct - err = k.verifyClientID(ctx, rollappID, clientID) - if err != nil { - return errors.Join(types.ErrWrongClientId, err) - } - - // freeze the rollapp and revert all pending states - err = k.FreezeRollapp(ctx, rollappID) - if err != nil { - return fmt.Errorf("freeze rollapp: %w", err) - } - - // slash the sequencer, clean delayed packets - err = k.hooks.FraudSubmitted(ctx, rollappID, fraudHeight, seqAddr) - if err != nil { - return err - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeFraud, - sdk.NewAttribute(types.AttributeKeyRollappId, rollappID), - sdk.NewAttribute(types.AttributeKeyFraudHeight, fmt.Sprint(fraudHeight)), - sdk.NewAttribute(types.AttributeKeyFraudSequencer, seqAddr), - sdk.NewAttribute(types.AttributeKeyClientID, clientID), - ), - ) - - return nil -} - -// freeze IBC client state -func (k Keeper) freezeClientState(ctx sdk.Context, clientId string) error { - clientState, ok := k.ibcClientKeeper.GetClientState(ctx, clientId) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidClientState, "client state for clientID %s not found", clientId) - } - - tmClientState, ok := clientState.(*cometbfttypes.ClientState) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidClientState, "client state with ID %s is not a tendermint client state", clientId) - } - - tmClientState.FrozenHeight = clienttypes.NewHeight(tmClientState.GetLatestHeight().GetRevisionHeight(), tmClientState.GetLatestHeight().GetRevisionNumber()) - k.ibcClientKeeper.SetClientState(ctx, clientId, tmClientState) - - return nil -} - -// RevertPendingStates reverts all pending states of a rollapp. It iterates over all the pending states -// on all the available for rollapp heights. -func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string) error { - // Get all pending states for the rollapp independently of the height - queuePerHeight, err := k.GetFinalizationQueueByRollapp(ctx, rollappID) - if err != nil { - return fmt.Errorf("get finalization queue by rollapp: %s: %w", rollappID, err) - } - - // Each queue contains the states to finalize for the specified height - for _, queue := range queuePerHeight { - for _, stateInfoIndex := range queue.FinalizationQueue { - stateInfo, _ := k.GetStateInfo(ctx, stateInfoIndex.RollappId, stateInfoIndex.Index) - stateInfo.Status = common.Status_REVERTED - k.SetStateInfo(ctx, stateInfo) - } - - err = k.RemoveFinalizationQueue(ctx, queue.CreationHeight, queue.RollappId) - if err != nil { - return fmt.Errorf("remove finalization queue: %w", err) - } - } - - return nil -} diff --git a/x/rollapp/keeper/fraud_handler_test.go b/x/rollapp/keeper/fraud_handler_test.go deleted file mode 100644 index 2153477d7..000000000 --- a/x/rollapp/keeper/fraud_handler_test.go +++ /dev/null @@ -1,226 +0,0 @@ -package keeper_test - -import ( - common "github.com/dymensionxyz/dymension/v3/x/common/types" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -// Happy Flow -// - frozen rollapp -// - slashed sequecner and unbonded all other sequencers -// - reverted states -// - cleared queue - -func (suite *RollappTestSuite) TestHandleFraud() { - var err error - - ctx := &suite.Ctx - keeper := suite.App.RollappKeeper - initialheight := uint64(10) - suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialheight)) - - numOfSequencers := uint64(3) - 1 // already created one with rollapp - numOfStates := uint64(100) - numOfBlocks := uint64(10) - fraudHeight := uint64(300) - - // unrelated rollapp just to validate it's unaffected - rollapp2, proposer2 := suite.CreateDefaultRollappAndProposer() - - // create rollapp and sequencers before fraud evidence - rollapp, proposer := suite.CreateDefaultRollappAndProposer() - for i := uint64(0); i < numOfSequencers-1; i++ { - _ = suite.CreateDefaultSequencer(*ctx, rollapp) - } - - // send state updates - var lastHeight uint64 = 1 - - for i := uint64(0); i < numOfStates; i++ { - _, err = suite.PostStateUpdate(*ctx, rollapp, proposer, lastHeight, numOfBlocks) - suite.Require().Nil(err) - - lastHeight, err = suite.PostStateUpdate(*ctx, rollapp2, proposer2, lastHeight, numOfBlocks) - suite.Require().Nil(err) - - suite.Ctx = suite.Ctx.WithBlockHeight(suite.Ctx.BlockHeader().Height + 1) - } - - // finalize some of the states - suite.App.RollappKeeper.FinalizeRollappStates(suite.Ctx.WithBlockHeight(20)) - - // assert before fraud submission - suite.assertBeforeFraud(rollapp, fraudHeight) - - err = keeper.HandleFraud(*ctx, rollapp, "", fraudHeight, proposer) - suite.Require().Nil(err) - - suite.assertFraudHandled(rollapp) -} - -// Fail - Invalid rollapp -func (suite *RollappTestSuite) TestHandleFraud_InvalidRollapp() { - ctx := &suite.Ctx - keeper := suite.App.RollappKeeper - - rollapp, proposer := suite.CreateDefaultRollappAndProposer() - _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) - suite.Require().Nil(err) - - err = keeper.HandleFraud(*ctx, "invalidRollapp", "", 2, proposer) - suite.Require().NotNil(err) -} - -// Fail - Wrong height -func (suite *RollappTestSuite) TestHandleFraud_WrongHeight() { - ctx := &suite.Ctx - keeper := suite.App.RollappKeeper - - rollapp, proposer := suite.CreateDefaultRollappAndProposer() - _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) - suite.Require().Nil(err) - - err = keeper.HandleFraud(*ctx, rollapp, "", 100, proposer) - suite.Require().NotNil(err) -} - -// Fail - Wrong sequencer address -func (suite *RollappTestSuite) TestHandleFraud_WrongSequencer() { - ctx := &suite.Ctx - keeper := suite.App.RollappKeeper - - rollapp, proposer := suite.CreateDefaultRollappAndProposer() - _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) - suite.Require().Nil(err) - - err = keeper.HandleFraud(*ctx, rollapp, "", 2, "wrongSequencer") - suite.Require().NotNil(err) -} - -// Fail - Wrong channel-ID -func (suite *RollappTestSuite) TestHandleFraud_WrongChannelID() { - ctx := &suite.Ctx - keeper := suite.App.RollappKeeper - - rollapp, proposer := suite.CreateDefaultRollappAndProposer() - _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) - suite.Require().Nil(err) - - err = keeper.HandleFraud(*ctx, rollapp, "wrongChannelID", 2, proposer) - suite.Require().NotNil(err) -} - -// Fail - Disputing already reverted state -func (suite *RollappTestSuite) TestHandleFraud_AlreadyReverted() { - var err error - ctx := &suite.Ctx - keeper := suite.App.RollappKeeper - numOfSequencers := uint64(3) - 1 // already created one with rollapp - numOfStates := uint64(10) - - rollapp, proposer := suite.CreateDefaultRollappAndProposer() - for i := uint64(0); i < numOfSequencers-1; i++ { - _ = suite.CreateDefaultSequencer(*ctx, rollapp) - } - - // send state updates - var lastHeight uint64 = 1 - for i := uint64(0); i < numOfStates; i++ { - lastHeight, err = suite.PostStateUpdate(*ctx, rollapp, proposer, lastHeight, uint64(10)) - suite.Require().Nil(err) - - suite.Ctx = suite.Ctx.WithBlockHeight(suite.Ctx.BlockHeader().Height + 1) - } - - err = keeper.HandleFraud(*ctx, rollapp, "", 11, proposer) - suite.Require().Nil(err) - - err = keeper.HandleFraud(*ctx, rollapp, "", 1, proposer) - suite.Require().NotNil(err) -} - -// Fail - Disputing already finalized state -func (suite *RollappTestSuite) TestHandleFraud_AlreadyFinalized() { - ctx := &suite.Ctx - keeper := suite.App.RollappKeeper - - rollapp, proposer := suite.CreateDefaultRollappAndProposer() - _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) - suite.Require().Nil(err) - - // finalize state - suite.Ctx = suite.Ctx.WithBlockHeight(ctx.BlockHeight() + int64(keeper.DisputePeriodInBlocks(*ctx))) - suite.App.RollappKeeper.FinalizeRollappStates(suite.Ctx) - stateInfo, err := suite.App.RollappKeeper.FindStateInfoByHeight(suite.Ctx, rollapp, 1) - suite.Require().Nil(err) - suite.Require().Equal(common.Status_FINALIZED, stateInfo.Status) - - err = keeper.HandleFraud(*ctx, rollapp, "", 2, proposer) - suite.Require().NotNil(err) -} - -// TODO: test IBC freeze - -/* ---------------------------------- utils --------------------------------- */ - -// assert before fraud submission, to validate the Test itself -func (suite *RollappTestSuite) assertBeforeFraud(rollappId string, height uint64) { - rollapp, found := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappId) - suite.Require().True(found) - suite.Require().False(rollapp.Frozen) - - // check sequencers - sequencers := suite.App.SequencerKeeper.RollappSequencers(suite.Ctx, rollappId) - for _, sequencer := range sequencers { - suite.Require().Equal(types.Bonded, sequencer.Status) - } - - // check states - stateInfo, err := suite.App.RollappKeeper.FindStateInfoByHeight(suite.Ctx, rollappId, height) - suite.Require().Nil(err) - suite.Require().Equal(common.Status_PENDING, stateInfo.Status) - - // check queue - expectedHeight := stateInfo.CreationHeight + suite.App.RollappKeeper.DisputePeriodInBlocks(suite.Ctx) - queue, found := suite.App.RollappKeeper.GetFinalizationQueue(suite.Ctx, expectedHeight, rollappId) - suite.Require().True(found) - - found = false - for _, stateInfoIndex := range queue.FinalizationQueue { - if stateInfoIndex.RollappId == rollappId { - val, _ := suite.App.RollappKeeper.GetStateInfo(suite.Ctx, rollappId, stateInfoIndex.Index) - suite.Require().Equal(common.Status_PENDING, val.Status) - found = true - break - } - } - suite.Require().True(found) -} - -func (suite *RollappTestSuite) assertFraudHandled(rollappId string) { - rollapp, found := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappId) - suite.Require().True(found) - suite.Require().True(rollapp.Frozen) - - // check states - finalIdx, _ := suite.App.RollappKeeper.GetLatestFinalizedStateIndex(suite.Ctx, rollappId) - start := finalIdx.Index + 1 - endIdx, _ := suite.App.RollappKeeper.GetLatestStateInfoIndex(suite.Ctx, rollappId) - end := endIdx.Index - - for i := start; i <= end; i++ { - stateInfo, found := suite.App.RollappKeeper.GetStateInfo(suite.Ctx, rollappId, i) - suite.Require().True(found) - suite.Require().Equal(common.Status_REVERTED, stateInfo.Status, "state info for height %d is not reverted", stateInfo.StartHeight) - } - - // check queue - queue, err := suite.App.RollappKeeper.GetEntireFinalizationQueue(suite.Ctx) - suite.Require().NoError(err) - suite.Greater(len(queue), 0) - for _, q := range queue { - for _, stateInfoIndex := range q.FinalizationQueue { - suite.Require().NotEqual(rollappId, stateInfoIndex.RollappId) - } - } -} diff --git a/x/rollapp/keeper/fraud_proposal.go b/x/rollapp/keeper/fraud_proposal.go new file mode 100644 index 000000000..00187be7c --- /dev/null +++ b/x/rollapp/keeper/fraud_proposal.go @@ -0,0 +1,74 @@ +package keeper + +import ( + "context" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" +) + +// SubmitRollappFraud handles the submission of a fraud proposal +// The fraud proposal can be submitted by the gov module +// We log here, as the error is not bubbled up to the user through the gov proposal +func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappFraudProposal) (*types.MsgRollappFraudProposalResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + if msg.Authority != k.authority { + err := errorsmod.Wrap(gerrc.ErrUnauthenticated, "only the gov module can submit fraud proposals") + ctx.Logger().Error(err.Error()) + return nil, err + } + + if err := msg.ValidateBasic(); err != nil { + err = errorsmod.Wrap(gerrc.ErrInvalidArgument, "invalid msg") + ctx.Logger().Error(err.Error()) + return nil, err + } + + rollapp, found := k.GetRollapp(ctx, msg.RollappId) + if !found { + err := errorsmod.Wrap(gerrc.ErrNotFound, "rollapp not found") + ctx.Logger().Error(err.Error()) + return nil, err + } + + // check revision number + if rollapp.RevisionNumber != msg.RollappRevision { + err := errorsmod.Wrap(gerrc.ErrFailedPrecondition, "revision number mismatch") + ctx.Logger().Error(err.Error()) + return nil, err + } + + // validate the rollapp is past its genesis bridge phase + if !rollapp.IsTransferEnabled() { + err := errorsmod.Wrap(gerrc.ErrFailedPrecondition, "rollapp is not past genesis bridge phase") + ctx.Logger().Error(err.Error()) + return nil, err + } + + // punish the sequencer if needed + if msg.PunishSequencerAddress != "" { + err := k.sequencerKeeper.PunishSequencer(ctx, msg.PunishSequencerAddress, msg.MustRewardee()) + if err != nil { + err = errorsmod.Wrap(err, "jail sequencer") + ctx.Logger().Error(err.Error()) + return nil, err + } + } + + // hard fork the rollapp + // it will revert the future pending states to the specified height + // and increment the revision number + // will fail if state already finalized + err := k.HardFork(ctx, msg.RollappId, msg.FraudHeight) + if err != nil { + err = errorsmod.Wrap(err, "hard fork") + ctx.Logger().Error(err.Error()) + return nil, err + } + + return &types.MsgRollappFraudProposalResponse{}, nil +} diff --git a/x/rollapp/keeper/grpc_query_get_state_info_by_height_test.go b/x/rollapp/keeper/grpc_query_get_state_info_by_height_test.go index fa3dc0e27..f6e5bec22 100644 --- a/x/rollapp/keeper/grpc_query_get_state_info_by_height_test.go +++ b/x/rollapp/keeper/grpc_query_get_state_info_by_height_test.go @@ -2,11 +2,10 @@ package keeper_test import ( "math/rand" - "strconv" "testing" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" "github.com/dymensionxyz/sdk-utils/utils/urand" "github.com/stretchr/testify/require" @@ -16,47 +15,11 @@ import ( "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) -// Prevent strconv unused error -var _ = strconv.IntSize - const ( maxNumOfBlocks = 1000 ) -func createNStateInfoAndIndex(keeper *keeper.Keeper, ctx sdk.Context, n int, rollappId string) []types.StateInfo { - keeper.SetRollapp(ctx, types.Rollapp{ - RollappId: rollappId, - }) - items := make([]types.StateInfo, n) - StartHeight := uint64(1) - for i := range items { - numBlocks := uint64(rand.Intn(maxNumOfBlocks) + 1) //nolint:gosec // this is for a test - stateInfo := types.StateInfo{ - StateInfoIndex: types.StateInfoIndex{ - RollappId: rollappId, - Index: uint64(i + 1), - }, - StartHeight: StartHeight, - NumBlocks: numBlocks, - } - StartHeight += stateInfo.NumBlocks - - keeper.SetStateInfo(ctx, stateInfo) - keeper.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ - RollappId: rollappId, - Index: stateInfo.StateInfoIndex.Index, - }) - - items[i] = stateInfo - } - keeper.SetLatestFinalizedStateIndex(ctx, types.StateInfoIndex{ - RollappId: rollappId, - Index: items[n-1].StateInfoIndex.Index, - }) - return items -} - -func TestStateInfoByHeightLatestStateInfoIndex(t *testing.T) { +func TestStateInfoByHeight_NoStateInfos(t *testing.T) { k, ctx := keepertest.RollappKeeper(t) wctx := sdk.WrapSDKContext(ctx) rollappId := "rollappid_1234-1" @@ -68,33 +31,10 @@ func TestStateInfoByHeightLatestStateInfoIndex(t *testing.T) { Height: 100, } _, err := k.StateInfo(wctx, request) - require.EqualError(t, err, errorsmod.Wrapf(types.ErrNotFound, "LatestStateInfoIndex wasn't found for rollappId=%s", rollappId).Error()) -} - -func TestStateInfoByHeightMissingStateInfo(t *testing.T) { - k, ctx := keepertest.RollappKeeper(t) - wctx := sdk.WrapSDKContext(ctx) - - rollappId := urand.RollappID() - k.SetRollapp(ctx, types.Rollapp{ - RollappId: rollappId, - }) - k.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ - RollappId: rollappId, - Index: uint64(85), - }) - request := &types.QueryGetStateInfoRequest{ - RollappId: rollappId, - Height: 100, - } - _, err := k.StateInfo(wctx, request) - errIndex := 1 + (85-1)/2 // Using binary search, the middle index is lookedup first and is missing. - require.EqualError(t, err, errorsmod.Wrapf(types.ErrNotFound, - "StateInfo wasn't found for rollappId=%s, index=%d", - rollappId, errIndex).Error()) + require.ErrorIs(t, err, gerrc.ErrNotFound) } -func TestStateInfoByHeightMissingStateInfo1(t *testing.T) { +func TestStateInfoByHeight_MissingStateInfo(t *testing.T) { k, ctx := keepertest.RollappKeeper(t) wctx := sdk.WrapSDKContext(ctx) @@ -116,10 +56,7 @@ func TestStateInfoByHeightMissingStateInfo1(t *testing.T) { NumBlocks: 1, }) _, err := k.StateInfo(wctx, request) - errIndex := 1 + (60-1)/2 // Using binary search, the middle index is lookedup first and is missing. - require.EqualError(t, err, errorsmod.Wrapf(types.ErrNotFound, - "StateInfo wasn't found for rollappId=%s, index=%d", - rollappId, errIndex).Error()) + require.ErrorIs(t, err, types.ErrStateNotExists) } func TestStateInfoByHeightErr(t *testing.T) { @@ -183,7 +120,7 @@ func TestStateInfoByHeightErr(t *testing.T) { RollappId: rollappID, Height: 10000000, }, - err: types.ErrStateNotExists, + err: gerrc.ErrNotFound, }, } { t.Run(tc.desc, func(t *testing.T) { @@ -246,3 +183,37 @@ func TestStateInfoByHeightValidDecreasingBlockBatches(t *testing.T) { } } } + +/* ---------------------------------- utils --------------------------------- */ +func createNStateInfoAndIndex(keeper *keeper.Keeper, ctx sdk.Context, n int, rollappId string) []types.StateInfo { + keeper.SetRollapp(ctx, types.Rollapp{ + RollappId: rollappId, + }) + items := make([]types.StateInfo, n) + StartHeight := uint64(1) + for i := range items { + numBlocks := uint64(rand.Intn(maxNumOfBlocks) + 1) //nolint:gosec // this is for a test + stateInfo := types.StateInfo{ + StateInfoIndex: types.StateInfoIndex{ + RollappId: rollappId, + Index: uint64(i + 1), + }, + StartHeight: StartHeight, + NumBlocks: numBlocks, + } + StartHeight += stateInfo.NumBlocks + + keeper.SetStateInfo(ctx, stateInfo) + keeper.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ + RollappId: rollappId, + Index: stateInfo.StateInfoIndex.Index, + }) + + items[i] = stateInfo + } + keeper.SetLatestFinalizedStateIndex(ctx, types.StateInfoIndex{ + RollappId: rollappId, + Index: items[n-1].StateInfoIndex.Index, + }) + return items +} diff --git a/x/rollapp/keeper/grpc_query_obsolete_drs_versions.go b/x/rollapp/keeper/grpc_query_obsolete_drs_versions.go index 156442b73..d79532393 100644 --- a/x/rollapp/keeper/grpc_query_obsolete_drs_versions.go +++ b/x/rollapp/keeper/grpc_query_obsolete_drs_versions.go @@ -16,7 +16,7 @@ func (k Keeper) ObsoleteDRSVersions(goCtx context.Context, req *types.QueryObsol } ctx := sdk.UnwrapSDKContext(goCtx) - versions, err := k.GetAllVulnerableDRSVersions(ctx) + versions, err := k.GetAllObsoleteDRSVersions(ctx) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/rollapp/keeper/grpc_query_obsolete_drs_versions_test.go b/x/rollapp/keeper/grpc_query_obsolete_drs_versions_test.go index 97f9856d6..d0fdd6b65 100644 --- a/x/rollapp/keeper/grpc_query_obsolete_drs_versions_test.go +++ b/x/rollapp/keeper/grpc_query_obsolete_drs_versions_test.go @@ -15,13 +15,13 @@ func TestObsoleteDRSVersionsQuery(t *testing.T) { wctx := sdk.WrapSDKContext(ctx) const obsoleteDRSVersion uint32 = 1234567890 - err := keeper.SetVulnerableDRSVersion(ctx, obsoleteDRSVersion) + err := keeper.SetObsoleteDRSVersion(ctx, obsoleteDRSVersion) require.NoError(t, err) response, err := keeper.ObsoleteDRSVersions(wctx, &types.QueryObsoleteDRSVersionsRequest{}) require.NoError(t, err) - expected, err := keeper.GetAllVulnerableDRSVersions(ctx) + expected, err := keeper.GetAllObsoleteDRSVersions(ctx) require.NoError(t, err) require.EqualValues(t, expected, response.DrsVersions) } diff --git a/x/rollapp/keeper/grpc_query_state_info.go b/x/rollapp/keeper/grpc_query_state_info.go index b37a05a0d..441814a38 100644 --- a/x/rollapp/keeper/grpc_query_state_info.go +++ b/x/rollapp/keeper/grpc_query_state_info.go @@ -5,11 +5,11 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/gerr-cosmos/gerrc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" ) func (k Keeper) StateInfo(c context.Context, req *types.QueryGetStateInfoRequest) (*types.QueryGetStateInfoResponse, error) { @@ -68,20 +68,22 @@ func (k Keeper) FindStateInfoByHeight(ctx sdk.Context, rollappId string, height return nil, types.ErrUnknownRollappID } - stateInfoIndex, found := k.GetLatestStateInfoIndex(ctx, rollappId) - if !found { + // check that height is already committed + ss, found := k.GetLatestStateInfo(ctx, rollappId) + if !found || height > ss.GetLatestHeight() { return nil, errorsmod.Wrapf(gerrc.ErrNotFound, "LatestStateInfoIndex wasn't found for rollappId=%s", rollappId) } + // initial interval to search in - startInfoIndex := uint64(1) - endInfoIndex := stateInfoIndex.Index + startInfoIndex := uint64(1) // TODO: handle pruned states (https://github.com/dymensionxyz/dymension/issues/1307) + endInfoIndex := ss.StateInfoIndex.Index for startInfoIndex <= endInfoIndex { midIndex := startInfoIndex + (endInfoIndex-startInfoIndex)/2 state, ok := k.GetStateInfo(ctx, rollappId, midIndex) if !ok { - return nil, errorsmod.Wrapf(gerrc.ErrNotFound, "StateInfo wasn't found for rollappId=%s, index=%d", rollappId, midIndex) + return nil, errorsmod.Wrapf(types.ErrStateNotExists, "StateInfo wasn't found for rollappId=%s, index=%d", rollappId, midIndex) } if state.ContainsHeight(height) { return &state, nil diff --git a/x/rollapp/keeper/grpc_query_state_info_test.go b/x/rollapp/keeper/grpc_query_state_info_test.go index 2513cd07f..136cfecb5 100644 --- a/x/rollapp/keeper/grpc_query_state_info_test.go +++ b/x/rollapp/keeper/grpc_query_state_info_test.go @@ -9,6 +9,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "github.com/dymensionxyz/gerr-cosmos/gerrc" "github.com/dymensionxyz/sdk-utils/utils/urand" keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" @@ -164,7 +165,7 @@ func TestFindStateInfoByHeight(t *testing.T) { rollappId: rollappID, height: 10, }, - err: types.ErrStateNotExists, + err: gerrc.ErrNotFound, }, } for _, tc := range testCase { diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go new file mode 100644 index 000000000..c15b4c644 --- /dev/null +++ b/x/rollapp/keeper/hard_fork.go @@ -0,0 +1,195 @@ +package keeper + +import ( + "fmt" + "sort" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + + common "github.com/dymensionxyz/dymension/v3/x/common/types" + "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" +) + +// HardFork handles the fraud evidence submitted by the user. +func (k Keeper) HardFork(ctx sdk.Context, rollappID string, newRevisionHeight uint64) error { + rollapp, found := k.GetRollapp(ctx, rollappID) + if !found { + return gerrc.ErrNotFound + } + + lastValidHeight, err := k.RevertPendingStates(ctx, rollappID, newRevisionHeight) + if err != nil { + return errorsmod.Wrap(err, "revert pending states") + } + newRevisionHeight = lastValidHeight + 1 + + // update revision number + rollapp.RevisionNumber += 1 + rollapp.RevisionStartHeight = newRevisionHeight + k.SetRollapp(ctx, rollapp) + + // handle the sequencers, clean delayed packets, handle light client + err = k.hooks.OnHardFork(ctx, rollappID, newRevisionHeight) + if err != nil { + return errorsmod.Wrap(err, "hard fork callback") + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeFraud, + sdk.NewAttribute(types.AttributeKeyRollappId, rollappID), + sdk.NewAttribute(types.AttributeKeyFraudHeight, fmt.Sprint(newRevisionHeight)), + ), + ) + + return nil +} + +// RevertPendingStates removes state updates until the one specified and included +// returns the latest height of the state info +func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, newRevisionHeight uint64) (uint64, error) { + // find the affected state info index + stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, newRevisionHeight) + if err == nil { + // check the disputed state info is not already finalized + if stateInfo.Status == common.Status_FINALIZED { + return 0, errorsmod.Wrapf(types.ErrDisputeAlreadyFinalized, "state info for height %d is already finalized", newRevisionHeight) + } + } else if errorsmod.IsOf(err, gerrc.ErrNotFound) { + // if not found, it's a future height. + // use latest state info + s, ok := k.GetLatestStateInfo(ctx, rollappID) + if !ok { + return 0, errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "no state info found for rollapp: %s", rollappID) + } + stateInfo = &s + } else { + return 0, err + } + + // update the last state info before the fraud height + // it removes all block descriptors after the fraud height + // and sets the next proposer to the empty string + stateInfo, err = k.UpdateLastStateInfo(ctx, stateInfo, newRevisionHeight) + if err != nil { + return 0, errorsmod.Wrap(err, "update last state info") + } + lastStateIdxToKeep := stateInfo.StateInfoIndex.Index + + // clear states updates post the fraud height + revertedStatesCount := 0 // Counter for reverted state updates + uniqueProposers := make(map[string]struct{}) // Map to manage unique proposers + + lastIdx, _ := k.GetLatestStateInfoIndex(ctx, rollappID) + for i := lastStateIdxToKeep + 1; i <= lastIdx.Index; i++ { + // Add the proposer to the unique map + uniqueProposers[k.MustGetStateInfo(ctx, rollappID, i).Sequencer] = struct{}{} + + // clear the state info + k.RemoveStateInfo(ctx, rollappID, i) + revertedStatesCount++ // Increment the counter + } + + k.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ + RollappId: rollappID, + Index: lastStateIdxToKeep, + }) + + // remove all the pending states from the finalization queue + err = k.pruneFinalizationsAbove(ctx, rollappID, lastStateIdxToKeep) + if err != nil { + return 0, fmt.Errorf("remove finalization queue: %w", err) + } + + // remove the sequencers heights + lastStateInfo := k.MustGetStateInfo(ctx, rollappID, lastStateIdxToKeep) + err = k.PruneSequencerHeights(ctx, mapKeysToSlice(uniqueProposers), lastStateInfo.GetLatestHeight()) + if err != nil { + return 0, errorsmod.Wrap(err, "prune sequencer heights") + } + + ctx.Logger().Info(fmt.Sprintf("Reverted state updates for rollapp: %s, count: %d", rollappID, revertedStatesCount)) + return lastStateInfo.GetLatestHeight(), nil +} + +// UpdateLastStateInfo truncates the state info to the last valid block before the fraud height. +// It returns the last state +func (k Keeper) UpdateLastStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) (*types.StateInfo, error) { + if fraudHeight < stateInfo.StartHeight { + return nil, errorsmod.Wrapf(gerrc.ErrInternal, "state info start height is greater than fraud height") + } + + if stateInfo.StartHeight == fraudHeight { + // If fraud height is at the beginning of the state info, return the previous index to keep + var ok bool + *stateInfo, ok = k.GetStateInfo(ctx, stateInfo.StateInfoIndex.RollappId, stateInfo.StateInfoIndex.Index-1) + if !ok { + return nil, errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "no state info found for rollapp: %s", stateInfo.StateInfoIndex.RollappId) + } + } else if stateInfo.GetLatestHeight() >= fraudHeight { + // Remove block descriptors until the one we need to rollback to + truncatedBDs := stateInfo.BDs.BD[:fraudHeight-stateInfo.StartHeight] + + // Update the state info to reflect truncated data + stateInfo.NumBlocks = uint64(len(truncatedBDs)) + stateInfo.BDs.BD = truncatedBDs + } + + // Update the state info in the keeper + stateInfo.NextProposer = "" + k.SetStateInfo(ctx, *stateInfo) + return stateInfo, nil +} + +func (k Keeper) HardForkToLatest(ctx sdk.Context, rollappID string) error { + lastBatch, ok := k.GetLatestStateInfo(ctx, rollappID) + if !ok { + return errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "can't hard fork, no state info found") + } + // we invoke a hard fork on the last posted batch without reverting any states + return k.HardFork(ctx, rollappID, lastBatch.GetLatestHeight()+1) +} + +func mapKeysToSlice(m map[string]struct{}) []string { + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + return keys +} + +func (k Keeper) pruneFinalizationsAbove(ctx sdk.Context, rollappID string, lastStateIdxToKeep uint64) error { + queuePerHeight, err := k.GetFinalizationQueueByRollapp(ctx, rollappID) + if err != nil { + return errorsmod.Wrap(err, "get finalization q by rollapp") + } + for _, q := range queuePerHeight { + leftPendingStates := []types.StateInfoIndex{} + for _, stateInfoIndex := range q.FinalizationQueue { + // keep state info indexes with index less than the rollback index + if stateInfoIndex.Index <= lastStateIdxToKeep { + leftPendingStates = append(leftPendingStates, stateInfoIndex) + continue + } + } + + if len(leftPendingStates) == 0 { + if err := k.RemoveFinalizationQueue(ctx, q.CreationHeight, rollappID); err != nil { + return errorsmod.Wrap(err, "remove finalization queue") + } + } else { + if err := k.SetFinalizationQueue(ctx, types.BlockHeightToFinalizationQueue{ + RollappId: rollappID, + CreationHeight: q.CreationHeight, + FinalizationQueue: leftPendingStates, + }); err != nil { + return errorsmod.Wrap(err, "set finalization queue") + } + } + } + return nil +} diff --git a/x/rollapp/keeper/hard_fork_test.go b/x/rollapp/keeper/hard_fork_test.go new file mode 100644 index 000000000..44ec81b7f --- /dev/null +++ b/x/rollapp/keeper/hard_fork_test.go @@ -0,0 +1,161 @@ +package keeper_test + +import ( + common "github.com/dymensionxyz/dymension/v3/x/common/types" +) + +// TestHardFork - Test the HardFork function +// - deleted states +// - pending queue is cleared up to the fraud height +// - revision number incremented +func (suite *RollappTestSuite) TestHardFork() { + numOfSequencers := uint64(3) - 1 // already created one with rollapp + numOfStates := uint64(100) + numOfFinalizedStates := uint64(10) + numOfBlocks := uint64(10) + + testCases := []struct { + name string + statesCommitted uint64 + statesFinalized uint64 + fraudHeight uint64 + expectError bool + }{ + // happy flows (fraud at different heights, states contains blocks 1-10, 11-20, 21-30, ...) + {"Fraud at start of batch", numOfStates, numOfFinalizedStates, 101, false}, + {"Fraud in middle of batch", numOfStates, numOfFinalizedStates, 107, false}, + {"Fraud at end of batch", numOfStates, numOfFinalizedStates, 200, false}, + {"Fraud at future height", 10, 1, 300, false}, + + // error flows + {"first batch not committed yet", 0, 0, 10, true}, + {"first block of the first batch", 1, 0, 1, true}, + {"height already finalized", numOfStates, numOfFinalizedStates, 20, true}, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + // Reset the state for the next test case + suite.SetupTest() + suite.App.RollappKeeper.SetHooks(nil) // disable hooks + + initialHeight := uint64(1) + suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialHeight)) + + // unrelated rollapp just to validate it's unaffected + rollapp2, proposer2 := suite.CreateDefaultRollappAndProposer() + var ( + err error + lastHeight uint64 = 1 + ) + for i := uint64(0); i < numOfStates; i++ { + suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialHeight + i)) + lastHeight, err = suite.PostStateUpdate(suite.Ctx, rollapp2, proposer2, lastHeight, numOfBlocks) + suite.Require().NoError(err) + } + + // create rollapp and sequencers before fraud evidence + rollappId, proposer := suite.CreateDefaultRollappAndProposer() + for i := uint64(0); i < numOfSequencers-1; i++ { + _ = suite.CreateDefaultSequencer(suite.Ctx, rollappId) + } + + // send state updates + lastHeight = 1 + for i := uint64(0); i < tc.statesCommitted; i++ { + suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialHeight + i)) + lastHeight, err = suite.PostStateUpdate(suite.Ctx, rollappId, proposer, lastHeight, numOfBlocks) + suite.Require().NoError(err) + } + + // Assert initial stats (revision 0, states pending) + suite.assertNotForked(rollappId) + queue, err := suite.App.RollappKeeper.GetFinalizationQueueByRollapp(suite.Ctx, rollappId) + suite.Require().NoError(err) + suite.Require().Len(queue, int(tc.statesCommitted)) + + // finalize some of the states + suite.App.RollappKeeper.FinalizeRollappStates(suite.Ctx.WithBlockHeight(int64(initialHeight + tc.statesFinalized))) + + err = suite.App.RollappKeeper.HardFork(suite.Ctx, rollappId, tc.fraudHeight) + if tc.expectError { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + suite.assertFraudHandled(rollappId, tc.fraudHeight) + } + }) + } +} + +// Fail - Invalid rollapp +func (suite *RollappTestSuite) TestHardFork_InvalidRollapp() { + ctx := &suite.Ctx + keeper := suite.App.RollappKeeper + + rollapp, proposer := suite.CreateDefaultRollappAndProposer() + _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) + suite.Require().Nil(err) + + err = keeper.HardFork(*ctx, "invalidRollapp", 2) + suite.Require().Error(err) +} + +// Fail - Disputing already finalized state +func (suite *RollappTestSuite) TestHardFork_AlreadyFinalized() { + ctx := &suite.Ctx + keeper := suite.App.RollappKeeper + + rollapp, proposer := suite.CreateDefaultRollappAndProposer() + _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) + suite.Require().Nil(err) + + // finalize state + suite.Ctx = suite.Ctx.WithBlockHeight(ctx.BlockHeight() + int64(keeper.DisputePeriodInBlocks(*ctx))) + suite.App.RollappKeeper.FinalizeRollappStates(suite.Ctx) + stateInfo, err := suite.App.RollappKeeper.FindStateInfoByHeight(suite.Ctx, rollapp, 1) + suite.Require().Nil(err) + suite.Require().Equal(common.Status_FINALIZED, stateInfo.Status) + + err = keeper.HardFork(*ctx, rollapp, 2) + suite.Require().NotNil(err) +} + +/* ---------------------------------- utils --------------------------------- */ +func (suite *RollappTestSuite) assertFraudHandled(rollappId string, height uint64) { + rollapp, found := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappId) + suite.Require().True(found) + suite.Require().Equal(uint64(1), rollapp.RevisionNumber) + + // check states were deleted + // the last state should have height less than the fraud height + lastestStateInfo, ok := suite.App.RollappKeeper.GetLatestStateInfo(suite.Ctx, rollappId) + if ok { + suite.Require().Less(lastestStateInfo.GetLatestHeight(), height) + } + + // check sequencers heights + sequencers, err := suite.App.RollappKeeper.AllSequencerHeightPairs(suite.Ctx) + suite.Require().NoError(err) + + ok = false + for _, seq := range sequencers { + if seq.Sequencer == lastestStateInfo.Sequencer { + suite.Require().Less(seq.Height, height) + ok = true + } + } + suite.Require().True(ok) + + // check queue + queue, err := suite.App.RollappKeeper.GetFinalizationQueueByRollapp(suite.Ctx, rollappId) + suite.Require().NoError(err) + suite.Require().Greater(len(queue), 0) + for _, q := range queue { + for _, stateInfoIndex := range q.FinalizationQueue { + if stateInfoIndex.RollappId == rollappId { + suite.Require().LessOrEqual(stateInfoIndex.Index, lastestStateInfo.StateInfoIndex.Index) + } + } + } +} diff --git a/x/rollapp/keeper/hooks_listeners.go b/x/rollapp/keeper/hooks_listeners.go deleted file mode 100644 index 89b757634..000000000 --- a/x/rollapp/keeper/hooks_listeners.go +++ /dev/null @@ -1,29 +0,0 @@ -package keeper - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -var _ sequencertypes.Hooks = SequencerHooks{} - -type SequencerHooks struct { - *Keeper -} - -func (k SequencerHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, before, after sequencertypes.Sequencer) { - // Start the liveness clock from zero - // NOTE: it could make more sense if liveness was a property of the sequencer rather than the rollapp - // TODO: tech debt https://github.com/dymensionxyz/dymension/issues/1357 - - ra := k.MustGetRollapp(ctx, rollapp) - k.ResetLivenessClock(ctx, &ra) - if !after.Sentinel() { - k.ScheduleLivenessEvent(ctx, &ra) - } - k.SetRollapp(ctx, ra) -} - -func (s SequencerHooks) AfterKickProposer(ctx sdk.Context, kicked sequencertypes.Sequencer) { - // TODO: trigger a hard fork -} diff --git a/x/rollapp/keeper/invariants.go b/x/rollapp/keeper/invariants.go index e218cf1ea..c843c24cb 100644 --- a/x/rollapp/keeper/invariants.go +++ b/x/rollapp/keeper/invariants.go @@ -97,9 +97,6 @@ func BlockHeightToFinalizationQueueInvariant(k Keeper) sdk.Invariant { continue } - if rollapp.GetFrozen() { - continue - } latestStateIdx, _ := k.GetLatestStateInfoIndex(ctx, rollapp.RollappId) latestFinalizedStateIdx, _ := k.GetLatestFinalizedStateIndex(ctx, rollapp.RollappId) diff --git a/x/rollapp/keeper/keeper.go b/x/rollapp/keeper/keeper.go index 26ed34164..03ed5a5e9 100644 --- a/x/rollapp/keeper/keeper.go +++ b/x/rollapp/keeper/keeper.go @@ -34,15 +34,13 @@ type Keeper struct { paramstore paramtypes.Subspace authority string // authority is the x/gov module account - accKeeper AccountKeeper - ibcClientKeeper IBCClientKeeper canonicalClientKeeper CanonicalLightClientKeeper channelKeeper ChannelKeeper sequencerKeeper SequencerKeeper bankKeeper BankKeeper transferKeeper TransferKeeper - vulnerableDRSVersions collections.KeySet[uint32] + obsoleteDRSVersions collections.KeySet[uint32] registeredRollappDenoms collections.KeySet[collections.Pair[string, string]] // finalizationQueue is a map from creation height and rollapp to the finalization queue. // Key: (creation height, rollappID), Value: state indexes to finalize. @@ -58,9 +56,7 @@ func NewKeeper( cdc codec.BinaryCodec, storeKey storetypes.StoreKey, ps paramtypes.Subspace, - ak AccountKeeper, channelKeeper ChannelKeeper, - ibcclientKeeper IBCClientKeeper, sequencerKeeper SequencerKeeper, bankKeeper BankKeeper, transferKeeper TransferKeeper, @@ -86,15 +82,13 @@ func NewKeeper( hooks: nil, channelKeeper: channelKeeper, authority: authority, - accKeeper: ak, - ibcClientKeeper: ibcclientKeeper, sequencerKeeper: sequencerKeeper, bankKeeper: bankKeeper, transferKeeper: transferKeeper, - vulnerableDRSVersions: collections.NewKeySet( + obsoleteDRSVersions: collections.NewKeySet( sb, - collections.NewPrefix(types.VulnerableDRSVersionsKeyPrefix), - "vulnerable_drs_versions", + collections.NewPrefix(types.ObsoleteDRSVersionsKeyPrefix), + "obsolete_drs_versions", collections.Uint32Key, ), registeredRollappDenoms: collections.NewKeySet[collections.Pair[string, string]]( @@ -152,9 +146,6 @@ func (k *Keeper) SetCanonicalClientKeeper(kk CanonicalLightClientKeeper) { /* -------------------------------------------------------------------------- */ func (k *Keeper) SetHooks(sh types.MultiRollappHooks) { - if k.hooks != nil { - panic("cannot set rollapp hooks twice") - } k.hooks = sh } diff --git a/x/rollapp/keeper/liveness_test.go b/x/rollapp/keeper/liveness_test.go index d199f6a98..272acebfc 100644 --- a/x/rollapp/keeper/liveness_test.go +++ b/x/rollapp/keeper/liveness_test.go @@ -180,6 +180,11 @@ type livenessMockSequencerKeeper struct { slashes map[string]int } +func (l livenessMockSequencerKeeper) PunishSequencer(ctx sdk.Context, seqAddr string, rewardee *sdk.AccAddress) error { + // TODO implement me + panic("implement me") +} + func newLivenessMockSequencerKeeper() livenessMockSequencerKeeper { return livenessMockSequencerKeeper{ make(map[string]int), diff --git a/x/rollapp/keeper/msg_server.go b/x/rollapp/keeper/msg_server.go index 77d78ce33..50e25b376 100644 --- a/x/rollapp/keeper/msg_server.go +++ b/x/rollapp/keeper/msg_server.go @@ -5,12 +5,12 @@ import ( ) type msgServer struct { - Keeper + *Keeper } // NewMsgServerImpl returns an implementation of the MsgServer interface // for the provided Keeper. -func NewMsgServerImpl(keeper Keeper) types.MsgServer { +func NewMsgServerImpl(keeper *Keeper) types.MsgServer { return &msgServer{Keeper: keeper} } diff --git a/x/rollapp/keeper/msg_server_create_rollapp.go b/x/rollapp/keeper/msg_server_create_rollapp.go index 66a720378..423cf5408 100644 --- a/x/rollapp/keeper/msg_server_create_rollapp.go +++ b/x/rollapp/keeper/msg_server_create_rollapp.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/sdk-utils/utils/uevent" @@ -16,6 +17,13 @@ func (k msgServer) CreateRollapp(goCtx context.Context, msg *types.MsgCreateRoll // Already validated chain id in ValidateBasic, so we assume it's valid rollappId := types.MustNewChainID(msg.RollappId) + // when creating a new Rollapp, the chainID revision number should always be 1 + // As we manage rollapp revision in the RollappKeeper, we don't allow increasing chainID revision number. + // (IBC has it's own concept of revision which we assume is always 1) + if rollappId.GetRevisionNumber() != 1 { + return nil, errorsmod.Wrapf(types.ErrInvalidRollappID, "revision number should be 1, got: %d", rollappId.GetRevisionNumber()) + } + if err := k.CheckIfRollappExists(ctx, rollappId); err != nil { return nil, err } diff --git a/x/rollapp/keeper/msg_server_create_rollapp_test.go b/x/rollapp/keeper/msg_server_create_rollapp_test.go index e15b824c5..0f5ec5bf2 100644 --- a/x/rollapp/keeper/msg_server_create_rollapp_test.go +++ b/x/rollapp/keeper/msg_server_create_rollapp_test.go @@ -58,7 +58,6 @@ func (suite *RollappTestSuite) TestCreateRollappAlreadyExists() { name string rollappId string expErr error - malleate func() }{ { name: "same ID", @@ -72,19 +71,6 @@ func (suite *RollappTestSuite) TestCreateRollappAlreadyExists() { name: "same name, different EIP155", rollappId: "rollapp_2345-1", expErr: types.ErrRollappExists, - }, { - name: "same ID, forked", - rollappId: "rollapp_1234-2", - malleate: func() { - r := rollapp.GetRollapp() - r.Frozen = true - suite.App.RollappKeeper.SetRollapp(suite.Ctx, r) - }, - expErr: nil, - }, { - name: "different rollapp, revision not 1", - rollappId: "trollapp_2345-2", - expErr: types.ErrInvalidRollappID, }, } for _, test := range tests { @@ -97,10 +83,6 @@ func (suite *RollappTestSuite) TestCreateRollappAlreadyExists() { GenesisInfo: mockGenesisInfo, } - if test.malleate != nil { - test.malleate() - } - suite.FundForAliasRegistration(newRollapp) _, err := suite.msgServer.CreateRollapp(goCtx, &newRollapp) @@ -109,142 +91,6 @@ func (suite *RollappTestSuite) TestCreateRollappAlreadyExists() { } } -func (suite *RollappTestSuite) TestCreateRollappId() { - suite.SetupTest() - - tests := []struct { - name string - rollappId string - revision uint64 - expErr error - }{ - { - name: "default is valid", - rollappId: "rollapp_1234-1", - revision: 1, - expErr: nil, - }, - { - name: "too long id", - rollappId: "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_1234-1", - expErr: types.ErrInvalidRollappID, - }, - { - name: "wrong EIP155", - rollappId: "rollapp_ea2413-1", - expErr: types.ErrInvalidRollappID, - }, - { - name: "no EIP155 with revision", - rollappId: "rollapp-1", - expErr: types.ErrInvalidRollappID, - }, - { - name: "starts with dash", - rollappId: "-1234", - expErr: types.ErrInvalidRollappID, - }, - { - name: "revision set without eip155", - rollappId: "rollapp-3", - expErr: types.ErrInvalidRollappID, - }, - { - name: "revision not set", - rollappId: "rollapp", - expErr: types.ErrInvalidRollappID, - }, - { - name: "invalid revision", - rollappId: "rollapp_1234-x", - expErr: types.ErrInvalidRollappID, - }, - } - for _, test := range tests { - suite.Run(test.name, func() { - id, err := types.NewChainID(test.rollappId) - suite.Require().ErrorIs(err, test.expErr) - suite.Require().Equal(test.revision, id.GetRevisionNumber()) - }) - } -} - -func (suite *RollappTestSuite) TestForkChainId() { - tests := []struct { - name string - rollappId string - newRollappId string - valid bool - }{ - { - name: "valid eip155 id", - rollappId: "rollapp_1234-1", - newRollappId: "rollapp_1234-2", - valid: true, - }, - { - name: "non-valid eip155 id", - rollappId: "rollapp_1234-1", - newRollappId: "rollapp_1234-5", - valid: false, - }, - { - name: "same eip155 but different name", - rollappId: "rollapp_1234-1", - newRollappId: "rollapy_1234-2", - valid: false, - }, - } - for _, test := range tests { - suite.Run(test.name, func() { - suite.SetupTest() - goCtx := sdk.WrapSDKContext(suite.Ctx) - rollappMsg := types.MsgCreateRollapp{ - Creator: alice, - RollappId: test.rollappId, - InitialSequencer: sample.AccAddress(), - Alias: "rollapp1", - VmType: types.Rollapp_EVM, - Metadata: &mockRollappMetadata, - GenesisInfo: mockGenesisInfo, - } - - suite.FundForAliasRegistration(rollappMsg) - - _, err := suite.msgServer.CreateRollapp(goCtx, &rollappMsg) - suite.Require().NoError(err) - rollapp, found := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappMsg.RollappId) - suite.Require().True(found) - rollapp.Frozen = true - suite.App.RollappKeeper.SetRollapp(suite.Ctx, rollapp) - - genesisInfo := mockGenesisInfo - genesisInfo.GenesisChecksum = "checksum1" - - rollappMsg2 := types.MsgCreateRollapp{ - Creator: alice, - RollappId: test.newRollappId, - InitialSequencer: sample.AccAddress(), - Alias: "rollapp2", - VmType: types.Rollapp_EVM, - Metadata: &mockRollappMetadata, - GenesisInfo: genesisInfo, - } - - suite.FundForAliasRegistration(rollappMsg2) - - _, err = suite.msgServer.CreateRollapp(goCtx, &rollappMsg2) - if test.valid { - suite.Require().NoError(err) - _, found = suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappMsg2.RollappId) - suite.Require().True(found) - } else { - suite.Require().ErrorIs(err, types.ErrInvalidRollappID) - } - }) - } -} - func (suite *RollappTestSuite) TestOverwriteEIP155Key() { tests := []struct { name string diff --git a/x/rollapp/keeper/msg_server_mark_obsolete_rollapps.go b/x/rollapp/keeper/msg_server_mark_obsolete_rollapps.go new file mode 100644 index 000000000..3766bb560 --- /dev/null +++ b/x/rollapp/keeper/msg_server_mark_obsolete_rollapps.go @@ -0,0 +1,85 @@ +package keeper + +import ( + "context" + "fmt" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" + "github.com/dymensionxyz/sdk-utils/utils/uevent" + "github.com/osmosis-labs/osmosis/v15/osmoutils" + + "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +func (k msgServer) MarkObsoleteRollapps(goCtx context.Context, msg *types.MsgMarkObsoleteRollapps) (*types.MsgMarkObsoleteRollappsResponse, error) { + err := msg.ValidateBasic() + if err != nil { + return nil, err + } + + if msg.Authority != k.authority { + return nil, errorsmod.Wrap(gerrc.ErrInvalidArgument, "only the gov module can mark obsolete rollapps") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + obsoleteNum, err := k.Keeper.MarkObsoleteRollapps(ctx, msg.DrsVersions) + if err != nil { + return nil, fmt.Errorf("mark obsolete rollapps: %w", err) + } + + err = uevent.EmitTypedEvent(ctx, &types.EventMarkObsoleteRollapps{ + ObsoleteRollappNum: uint64(obsoleteNum), + DrsVersions: msg.DrsVersions, + }) + if err != nil { + return nil, fmt.Errorf("emit event: %w", err) + } + + return &types.MsgMarkObsoleteRollappsResponse{}, nil +} + +func (k Keeper) MarkObsoleteRollapps(ctx sdk.Context, drsVersions []uint32) (int, error) { + obsoleteVersions := make(map[uint32]struct{}) + for _, v := range drsVersions { + obsoleteVersions[v] = struct{}{} + // this also saves in the state the obsolete version + err := k.SetObsoleteDRSVersion(ctx, v) + if err != nil { + return 0, fmt.Errorf("set obsolete DRS version: %w", err) + } + } + + var ( + logger = k.Logger(ctx) + obsoleteNum int + ) + for _, rollapp := range k.GetAllRollapps(ctx) { + info, found := k.GetLatestStateInfo(ctx, rollapp.RollappId) + if !found { + logger.With("rollapp_id", rollapp.RollappId).Info("no latest state info for rollapp") + continue + } + + // check only last block descriptor DRS, since if that last is not obsolete it means the rollapp already upgraded and is not obsolete anymore + bd := info.BDs.BD[len(info.BDs.BD)-1] + + _, obsolete := obsoleteVersions[bd.DrsVersion] + if obsolete { + // If this fails, no state change happens + err := osmoutils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error { + return k.HardForkToLatest(ctx, rollapp.RollappId) + }) + if err != nil { + // We do not want to fail if one rollapp cannot to be marked as obsolete + k.Logger(ctx).With("rollapp_id", rollapp.RollappId, "drs_version", bd.DrsVersion, "error", err.Error()). + Error("Failed to mark rollapp as obsolete") + } + obsoleteNum++ + } + } + + return obsoleteNum, nil +} diff --git a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go b/x/rollapp/keeper/msg_server_mark_obsolete_rollapps_test.go similarity index 51% rename from x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go rename to x/rollapp/keeper/msg_server_mark_obsolete_rollapps_test.go index 76401e263..2d1c9a81f 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go +++ b/x/rollapp/keeper/msg_server_mark_obsolete_rollapps_test.go @@ -10,11 +10,10 @@ import ( "github.com/dymensionxyz/sdk-utils/utils/uslice" "github.com/dymensionxyz/dymension/v3/app/apptesting" - "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) -func (s *RollappTestSuite) TestMarkVulnerableRollapps() { +func (s *RollappTestSuite) TestMarkObsoleteRollapps() { type rollapp struct { name string drsVersion uint32 @@ -22,11 +21,11 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { govModule := authtypes.NewModuleAddress(govtypes.ModuleName).String() tests := []struct { - name string - authority string - rollapps []rollapp - vulnVersions []uint32 - expError error + name string + authority string + rollapps []rollapp + obsoleteVersions []uint32 + expError error }{ { name: "happy path 1", @@ -39,7 +38,7 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { {name: "rollappe_5-1", drsVersion: 1}, {name: "rollappf_6-1", drsVersion: 2}, }, - vulnVersions: []uint32{ + obsoleteVersions: []uint32{ 1, 2, }, @@ -52,7 +51,7 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { {name: "rollappa_1-1", drsVersion: 2}, {name: "rollappd_2-1", drsVersion: 1}, }, - vulnVersions: []uint32{ + obsoleteVersions: []uint32{ 1, }, expError: nil, @@ -68,14 +67,14 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { {name: "rollappe_5-1", drsVersion: 0}, {name: "rollappf_6-1", drsVersion: 2}, }, - vulnVersions: []uint32{ + obsoleteVersions: []uint32{ 1, 2, }, expError: nil, }, { - name: "empty DRS version is also vulnerable", + name: "empty DRS version is also obsolete", authority: govModule, rollapps: []rollapp{ {name: "rollappa_1-1", drsVersion: 3}, @@ -85,7 +84,7 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { {name: "rollappe_5-1", drsVersion: 0}, {name: "rollappf_6-1", drsVersion: 1}, }, - vulnVersions: []uint32{ + obsoleteVersions: []uint32{ 0, 1, 2, @@ -99,7 +98,7 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { {name: "rollappa_1-1", drsVersion: 2}, {name: "rollappe_2-1", drsVersion: 1}, }, - vulnVersions: []uint32{ + obsoleteVersions: []uint32{ 1, }, expError: gerrc.ErrInvalidArgument, @@ -109,13 +108,14 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { for _, tc := range tests { s.Run(tc.name, func() { s.SetupTest() + s.App.RollappKeeper.SetHooks(nil) // disable hooks // prepare test data - vulnVersions := uslice.ToKeySet(tc.vulnVersions) - // list of expected vulnerable rollapps - expectedVulnRollappIDs := make([]string, 0, len(tc.vulnVersions)) - // list of expected non-vulnerable rollapps - expectedNonVulnRollappIDs := make([]string, 0, len(tc.vulnVersions)) + obsoleteVersions := uslice.ToKeySet(tc.obsoleteVersions) + // list of expected obsolete rollapps + expectedObsoleteRollappIDs := make([]string, 0, len(tc.rollapps)) + // list of expected non-obsolete rollapps + expectedNonObsoleteRollappIDs := make([]string, 0, len(tc.rollapps)) // create rollapps for every rollapp record from the test case for _, ra := range tc.rollapps { // create a rollapp @@ -128,69 +128,71 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { s.Require().Nil(err) // fill lists with expectations - if _, vuln := vulnVersions[ra.drsVersion]; vuln { - expectedVulnRollappIDs = append(expectedVulnRollappIDs, ra.name) + if _, obsolete := obsoleteVersions[ra.drsVersion]; obsolete { + expectedObsoleteRollappIDs = append(expectedObsoleteRollappIDs, ra.name) } else { - expectedNonVulnRollappIDs = append(expectedNonVulnRollappIDs, ra.name) + expectedNonObsoleteRollappIDs = append(expectedNonObsoleteRollappIDs, ra.name) } } // trigger the message we want to test - _, err := s.msgServer.MarkVulnerableRollapps(s.Ctx, &types.MsgMarkVulnerableRollapps{ + _, err := s.msgServer.MarkObsoleteRollapps(s.Ctx, &types.MsgMarkObsoleteRollapps{ Authority: tc.authority, - DrsVersions: tc.vulnVersions, + DrsVersions: tc.obsoleteVersions, }) // validate results if tc.expError != nil { - s.Error(err) - // TODO: try using errors.Is! - s.ErrorContains(err, tc.expError.Error()) + s.ErrorIs(err, tc.expError) // check the event is not emitted - eventName := proto.MessageName(new(types.EventMarkVulnerableRollapps)) + eventName := proto.MessageName(new(types.EventMarkObsoleteRollapps)) s.AssertEventEmitted(s.Ctx, eventName, 0) - // check non-vulnerable rollapps: all rollapps are still non-vulnerable - nonVulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, keeper.FilterNonVulnerable) - actualNonVulnRollappIDs := uslice.Map(nonVulnRa, func(r types.Rollapp) string { return r.RollappId }) - allRollapps := slices.Concat(expectedVulnRollappIDs, expectedNonVulnRollappIDs) - s.ElementsMatch(allRollapps, actualNonVulnRollappIDs) + // check non-obsolete rollapps: all rollapps are still non-obsolete + nonObsoleteRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterNonForked) + actualNonObsoleteRollappIDs := uslice.Map(nonObsoleteRa, func(r types.Rollapp) string { return r.RollappId }) + allRollapps := slices.Concat(expectedObsoleteRollappIDs, expectedNonObsoleteRollappIDs) + s.ElementsMatch(allRollapps, actualNonObsoleteRollappIDs) - // check vulnerable rollapps: no vulnerable rollapps - vulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterVulnerable) - s.Empty(vulnRa) + // check obsolete rollapps: no obsolete rollapps + obsoleteRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterForked) + s.Empty(obsoleteRa) - // check the vulnerable version set is empty - actualVulnVersions, err := s.App.RollappKeeper.GetAllVulnerableDRSVersions(s.Ctx) + // check the obsolete version set is empty + actualObsoleteVersions, err := s.App.RollappKeeper.GetAllObsoleteDRSVersions(s.Ctx) s.Require().NoError(err) - s.Require().Empty(actualVulnVersions) + s.Require().Empty(actualObsoleteVersions) } else { s.NoError(err) // check the event is emitted - eventName := proto.MessageName(new(types.EventMarkVulnerableRollapps)) + eventName := proto.MessageName(new(types.EventMarkObsoleteRollapps)) s.AssertEventEmitted(s.Ctx, eventName, 1) - // check non-vulnerable rollapps - nonVulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, keeper.FilterNonVulnerable) - actualNonVulnRollappIDs := uslice.Map(nonVulnRa, func(r types.Rollapp) string { return r.RollappId }) - s.ElementsMatch(expectedNonVulnRollappIDs, actualNonVulnRollappIDs) + // check non-obsolete rollapps + nonObsoleteRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterNonForked) + actualNonObsoleteRollappIDs := uslice.Map(nonObsoleteRa, func(r types.Rollapp) string { return r.RollappId }) + s.ElementsMatch(expectedNonObsoleteRollappIDs, actualNonObsoleteRollappIDs) - // check vulnerable rollapps - vulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterVulnerable) - actualVulnRollappIDs := uslice.Map(vulnRa, func(r types.Rollapp) string { return r.RollappId }) - s.ElementsMatch(expectedVulnRollappIDs, actualVulnRollappIDs) + // check obsolete rollapps + obsoleteRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterForked) + actualObsoleteRollappIDs := uslice.Map(obsoleteRa, func(r types.Rollapp) string { return r.RollappId }) + s.ElementsMatch(expectedObsoleteRollappIDs, actualObsoleteRollappIDs) - // check the vulnerable version set - actualVulnVersions, err := s.App.RollappKeeper.GetAllVulnerableDRSVersions(s.Ctx) + // check the obsolete version set + actualObsoleteVersions, err := s.App.RollappKeeper.GetAllObsoleteDRSVersions(s.Ctx) s.Require().NoError(err) - s.Require().ElementsMatch(tc.vulnVersions, actualVulnVersions) + s.Require().ElementsMatch(tc.obsoleteVersions, actualObsoleteVersions) } }) } } -func FilterVulnerable(b types.Rollapp) bool { - return b.Frozen +func FilterForked(b types.Rollapp) bool { + return b.RevisionNumber > 0 +} + +func FilterNonForked(b types.Rollapp) bool { + return b.RevisionNumber == 0 } diff --git a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go deleted file mode 100644 index 7cc0be3a3..000000000 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go +++ /dev/null @@ -1,86 +0,0 @@ -package keeper - -import ( - "context" - "fmt" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/gerr-cosmos/gerrc" - "github.com/dymensionxyz/sdk-utils/utils/uevent" - "github.com/osmosis-labs/osmosis/v15/osmoutils" - - "github.com/dymensionxyz/dymension/v3/x/rollapp/types" -) - -func (k msgServer) MarkVulnerableRollapps(goCtx context.Context, msg *types.MsgMarkVulnerableRollapps) (*types.MsgMarkVulnerableRollappsResponse, error) { - err := msg.ValidateBasic() - if err != nil { - return nil, err - } - - if msg.Authority != k.authority { - return nil, errorsmod.Wrap(gerrc.ErrInvalidArgument, "only the gov module can mark vulnerable rollapps") - } - - ctx := sdk.UnwrapSDKContext(goCtx) - - vulnerableNum, err := k.Keeper.MarkVulnerableRollapps(ctx, msg.DrsVersions) - if err != nil { - return nil, fmt.Errorf("mark vulnerable rollapps: %w", err) - } - - err = uevent.EmitTypedEvent(ctx, &types.EventMarkVulnerableRollapps{ - VulnerableRollappNum: uint64(vulnerableNum), - DrsVersions: msg.DrsVersions, - }) - if err != nil { - return nil, fmt.Errorf("emit event: %w", err) - } - - return &types.MsgMarkVulnerableRollappsResponse{}, nil -} - -func (k Keeper) MarkVulnerableRollapps(ctx sdk.Context, drsVersions []uint32) (int, error) { - vulnerableVersions := make(map[uint32]struct{}) - for _, v := range drsVersions { - vulnerableVersions[v] = struct{}{} - // this also saves in the state the vulnerable version - err := k.SetVulnerableDRSVersion(ctx, v) - if err != nil { - return 0, fmt.Errorf("set vulnerable DRS version: %w", err) - } - } - - var ( - logger = k.Logger(ctx) - nonVulnerable = k.FilterRollapps(ctx, FilterNonVulnerable) - vulnerableNum int - ) - for _, rollapp := range nonVulnerable { - info, found := k.GetLatestStateInfo(ctx, rollapp.RollappId) - if !found { - logger.With("rollapp_id", rollapp.RollappId).Info("no latest state info for rollapp") - continue - } - - // check only last block descriptor DRS, since if that last is not vulnerable it means the rollapp already upgraded and is not vulnerable anymore - bd := info.BDs.BD[len(info.BDs.BD)-1] - - _, vulnerable := vulnerableVersions[bd.DrsVersion] - if vulnerable { - // If this fails, no state change happens - err := osmoutils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error { - return k.MarkRollappAsVulnerable(ctx, rollapp.RollappId) - }) - if err != nil { - // We do not want to fail if one rollapp cannot to be marked as vulnerable - k.Logger(ctx).With("rollapp_id", rollapp.RollappId, "drs_version", bd.DrsVersion, "error", err.Error()). - Error("Failed to mark rollapp as vulnerable") - } - vulnerableNum++ - } - } - - return vulnerableNum, nil -} diff --git a/x/rollapp/keeper/msg_server_transfer_ownership.go b/x/rollapp/keeper/msg_server_transfer_ownership.go index d6498eca6..bcec1413d 100644 --- a/x/rollapp/keeper/msg_server_transfer_ownership.go +++ b/x/rollapp/keeper/msg_server_transfer_ownership.go @@ -27,10 +27,6 @@ func (k msgServer) TransferOwnership(goCtx context.Context, msg *types.MsgTransf return nil, types.ErrUnauthorizedSigner } - if rollapp.Frozen { - return nil, types.ErrRollappFrozen - } - if rollapp.Owner == msg.NewOwner { return nil, types.ErrSameOwner } diff --git a/x/rollapp/keeper/msg_server_transfer_ownership_test.go b/x/rollapp/keeper/msg_server_transfer_ownership_test.go index 7daa17c46..dee5da051 100644 --- a/x/rollapp/keeper/msg_server_transfer_ownership_test.go +++ b/x/rollapp/keeper/msg_server_transfer_ownership_test.go @@ -45,16 +45,6 @@ func (suite *RollappTestSuite) TestTransferOwnership() { bob, alice, rollappId, ), expError: types.ErrUnauthorizedSigner, - }, { - name: "Transfer rollapp ownership: failed, frozen rollapp", - request: types.NewMsgTransferOwnership( - alice, bob, rollappId, - ), - malleate: func(rollapp types.Rollapp) types.Rollapp { - rollapp.Frozen = true - return rollapp - }, - expError: types.ErrRollappFrozen, }, { name: "Transfer rollapp ownership: failed, invalid current owner address", request: types.NewMsgTransferOwnership( diff --git a/x/rollapp/keeper/msg_server_update_rollapp_test.go b/x/rollapp/keeper/msg_server_update_rollapp_test.go index 63ff08db1..ab5bb3d31 100644 --- a/x/rollapp/keeper/msg_server_update_rollapp_test.go +++ b/x/rollapp/keeper/msg_server_update_rollapp_test.go @@ -22,7 +22,6 @@ func (suite *RollappTestSuite) TestUpdateRollapp() { update *types.MsgUpdateRollappInformation rollappLaunched bool genInfoSealed bool - frozen bool expError error expRollapp types.Rollapp }{ @@ -79,15 +78,6 @@ func (suite *RollappTestSuite) TestUpdateRollapp() { InitialSequencer: initialSequencerAddress, }, expError: sdkerrors.ErrUnauthorized, - }, { - name: "Update rollapp: fail - try to update a frozen rollapp", - update: &types.MsgUpdateRollappInformation{ - Owner: alice, - RollappId: rollappId, - InitialSequencer: initialSequencerAddress, - }, - frozen: true, - expError: types.ErrRollappFrozen, }, { name: "Update rollapp: fail - try to update InitialSequencer when launched", update: &types.MsgUpdateRollappInformation{ @@ -162,7 +152,6 @@ func (suite *RollappTestSuite) TestUpdateRollapp() { Owner: alice, InitialSequencer: "", ChannelId: "", - Frozen: false, Launched: true, VmType: types.Rollapp_EVM, Metadata: &mockRollappMetadata, @@ -201,7 +190,6 @@ func (suite *RollappTestSuite) TestUpdateRollapp() { Owner: alice, InitialSequencer: "", ChannelId: "", - Frozen: false, Launched: false, VmType: types.Rollapp_EVM, Metadata: &mockRollappMetadata, @@ -236,7 +224,6 @@ func (suite *RollappTestSuite) TestUpdateRollapp() { Owner: alice, InitialSequencer: "", ChannelId: "", - Frozen: tc.frozen, Launched: tc.rollappLaunched, VmType: types.Rollapp_EVM, Metadata: &types.RollappMetadata{ diff --git a/x/rollapp/keeper/msg_server_update_state.go b/x/rollapp/keeper/msg_server_update_state.go index d2e482781..198355997 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -2,10 +2,10 @@ package keeper import ( "context" - "fmt" errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" @@ -20,11 +20,6 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) return nil, types.ErrUnknownRollappID } - // verify the rollapp is not frozen - if rollapp.Frozen { - return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "rollapp is frozen") - } - // call the before-update-state hook // currently used by `x/sequencer` to: // 1. validate the state update submitter @@ -34,19 +29,11 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) return nil, errorsmod.Wrap(err, "before update state") } - for _, bd := range msg.BDs.BD { - // verify the DRS version is not vulnerable - if k.IsDRSVersionVulnerable(ctx, bd.DrsVersion) { - // the rollapp is not marked as vulnerable yet, mark it now - err := k.MarkRollappAsVulnerable(ctx, msg.RollappId) - if err != nil { - return nil, fmt.Errorf("mark rollapp vulnerable: %w", err) - } - k.Logger(ctx).With("rollapp_id", msg.RollappId, "drs_version", bd.DrsVersion). - Info("non-frozen rollapp tried to submit MsgUpdateState with the vulnerable DRS version, mark the rollapp as vulnerable") - // we must return non-error if we want the changes to be saved - return &types.MsgUpdateStateResponse{}, nil - } + // validate correct rollapp revision number + if rollapp.RevisionNumber != msg.RollappRevision { + return nil, errorsmod.Wrapf(types.ErrWrongRollappRevision, + "expected revision number (%d), but received (%d)", + rollapp.RevisionNumber, msg.RollappRevision) } // retrieve last updating index @@ -91,12 +78,6 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) } newIndex = lastIndex + 1 - // Write new index information to the store - k.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ - RollappId: msg.RollappId, - Index: newIndex, - }) - // it takes the actual proposer because the next one have already been set // by the sequencer rotation in k.hooks.BeforeUpdateState // the proposer we get is the one that will propose the next block. @@ -116,9 +97,24 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) blockTime, val.Address, ) + + // verify the DRS version is not obsolete + // check only last block descriptor DRS, since if that last is not obsolete it means the rollapp already upgraded and is not obsolete anymore + if k.IsStateUpdateObsolete(ctx, stateInfo) { + return nil, errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "MsgUpdateState with an obsolete DRS version. rollapp_id: %s, drs_version: %d", + msg.RollappId, stateInfo.GetLatestBlockDescriptor().DrsVersion) + } + + // Write new index information to the store + k.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ + RollappId: msg.RollappId, + Index: newIndex, + }) // Write new state information to the store indexed by k.SetStateInfo(ctx, *stateInfo) + // call the after-update-state hook + // currently used by `x/lightclient` to validate the state update in regards to the light client err = k.hooks.AfterUpdateState(ctx, msg.RollappId, stateInfo) if err != nil { return nil, errorsmod.Wrap(err, "hook: after update state") @@ -145,6 +141,7 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) return nil, errorsmod.Wrap(err, "set finalization queue") } + // FIXME: only single save can be done with the latest height for _, bd := range msg.BDs.BD { if err := k.SaveSequencerHeight(ctx, stateInfo.Sequencer, bd.Height); err != nil { return nil, errorsmod.Wrap(err, "save sequencer height") @@ -166,3 +163,8 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) return &types.MsgUpdateStateResponse{}, nil } + +// IsStateUpdateObsolete checks if the given DRS version is obsolete +func (k msgServer) IsStateUpdateObsolete(ctx sdk.Context, stateInfo *types.StateInfo) bool { + return k.IsDRSVersionObsolete(ctx, stateInfo.GetLatestBlockDescriptor().DrsVersion) +} diff --git a/x/rollapp/keeper/msg_server_update_state_test.go b/x/rollapp/keeper/msg_server_update_state_test.go index 7e0baa4f3..c478408f1 100644 --- a/x/rollapp/keeper/msg_server_update_state_test.go +++ b/x/rollapp/keeper/msg_server_update_state_test.go @@ -6,7 +6,6 @@ import ( abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - "github.com/dymensionxyz/gerr-cosmos/gerrc" "github.com/dymensionxyz/sdk-utils/utils/urand" "github.com/dymensionxyz/dymension/v3/testutil/sample" @@ -100,11 +99,11 @@ func (suite *RollappTestSuite) TestUpdateState() { } } -func (s *RollappTestSuite) TestUpdateStateVulnerableRollapp() { +func (s *RollappTestSuite) TestUpdateStateObsoleteRollapp() { const ( - raName = "rollapptest_1-1" - nonVulnerableVersion = 2 - vulnerableVersion = 1 + raName = "rollapptest_1-1" + nonObsoleteVersion = 2 + obsoleteVersion = 1 ) // create a rollapp @@ -112,51 +111,21 @@ func (s *RollappTestSuite) TestUpdateStateVulnerableRollapp() { // create a sequencer proposer := s.CreateDefaultSequencer(s.Ctx, raName) - // create the initial state update with non-vulnerable version - expectedLastHeight, err := s.PostStateUpdateWithDRSVersion(s.Ctx, raName, proposer, 1, uint64(3), nonVulnerableVersion) + // create the initial state update with non-obsolete version + expectedNextHeight, err := s.PostStateUpdateWithDRSVersion(s.Ctx, raName, proposer, 1, uint64(3), nonObsoleteVersion) s.Require().Nil(err) // check the rollapp's last height actualLastHeight := s.GetRollappLastHeight(raName) - s.Require().Equal(expectedLastHeight, actualLastHeight) + s.Require().Equal(expectedNextHeight-1, actualLastHeight) - // mark a DRS version as vulnerable. note that the last state update of the rollapp wasn't vulnerable - vulnNum, err := s.App.RollappKeeper.MarkVulnerableRollapps(s.Ctx, []uint32{vulnerableVersion}) + // mark a DRS version as obsolete + err = s.App.RollappKeeper.SetObsoleteDRSVersion(s.Ctx, obsoleteVersion) s.Require().NoError(err) - s.Require().Equal(0, vulnNum) - // check the version is vulnerable - ok := s.App.RollappKeeper.IsDRSVersionVulnerable(s.Ctx, vulnerableVersion) - s.Require().True(ok) - - // the rollapp is not vulnerable at this step - ok = s.IsRollappVulnerable(raName) - s.Require().False(ok) - - // create a new update using the vulnerable version - _, err = s.PostStateUpdateWithDRSVersion(s.Ctx, raName, proposer, 1, uint64(3), vulnerableVersion) - s.Require().NoError(err) - - // the rollapp now is vulnerable - ok = s.IsRollappVulnerable(raName) - s.Require().True(ok) - - // the rollapp state is not updated - actualLastHeight = s.GetRollappLastHeight(raName) - s.Require().Equal(expectedLastHeight, actualLastHeight) - - // create one more update using the vulnerable version. this time we expect an error. - _, err = s.PostStateUpdateWithDRSVersion(s.Ctx, raName, proposer, 1, uint64(3), vulnerableVersion) + // create a new update using the obsolete version + _, err = s.PostStateUpdateWithDRSVersion(s.Ctx, raName, proposer, expectedNextHeight, uint64(3), obsoleteVersion) s.Require().Error(err) - s.Assert().ErrorIs(err, gerrc.ErrFailedPrecondition) - - // the rollapp is still vulnerable - ok = s.IsRollappVulnerable(raName) - s.Require().True(ok) - - // the rollapp state is still not updated - actualLastHeight = s.GetRollappLastHeight(raName) - s.Require().Equal(expectedLastHeight, actualLastHeight) } func (suite *RollappTestSuite) TestUpdateStateUnknownRollappId() { diff --git a/x/rollapp/keeper/registered_denoms.go b/x/rollapp/keeper/registered_denoms.go index 339e8017a..d8e4265de 100644 --- a/x/rollapp/keeper/registered_denoms.go +++ b/x/rollapp/keeper/registered_denoms.go @@ -32,3 +32,8 @@ func (k Keeper) IterateRegisteredDenoms(ctx sdk.Context, rollappID string, cb fu return cb(item.K2()) }) } + +func (k Keeper) ClearRegisteredDenoms(ctx sdk.Context, rollappID string) error { + rng := collections.NewPrefixedPairRange[string, string](rollappID) + return k.registeredRollappDenoms.Clear(ctx, rng) +} diff --git a/x/rollapp/keeper/rollapp.go b/x/rollapp/keeper/rollapp.go index e803a851f..d632e5ddd 100644 --- a/x/rollapp/keeper/rollapp.go +++ b/x/rollapp/keeper/rollapp.go @@ -26,10 +26,6 @@ func (k Keeper) CheckAndUpdateRollappFields(ctx sdk.Context, update *types.MsgUp return current, sdkerrors.ErrUnauthorized } - if current.Frozen { - return current, types.ErrRollappFrozen - } - // immutable values cannot be updated when the rollapp is launched if update.UpdatingImmutableValues() && current.Launched { return current, types.ErrImmutableFieldUpdateAfterLaunched @@ -86,32 +82,14 @@ func (k Keeper) CheckIfRollappExists(ctx sdk.Context, rollappId types.ChainID) e return types.ErrRollappExists } - existingRollapp, isFound := k.GetRollappByEIP155(ctx, rollappId.GetEIP155ID()) - // allow replacing EIP155 only when forking (previous rollapp is frozen) - if !isFound { - // if not forking, check to see if the Rollapp has been registered before with same name - if _, isFound = k.GetRollappByName(ctx, rollappId.GetName()); isFound { - return types.ErrRollappExists - } - // when creating a new Rollapp, the revision number should always be 1 - if rollappId.GetRevisionNumber() != 1 { - return errorsmod.Wrapf(types.ErrInvalidRollappID, "revision number should be 1, got: %d", rollappId.GetRevisionNumber()) - } - return nil - } - if !existingRollapp.Frozen { + if _, isFound := k.GetRollappByEIP155(ctx, rollappId.GetEIP155ID()); isFound { return types.ErrRollappExists } - existingRollappChainId := types.MustNewChainID(existingRollapp.RollappId) - if rollappId.GetName() != existingRollappChainId.GetName() { - return errorsmod.Wrapf(types.ErrInvalidRollappID, "rollapp name should be %s", existingRollappChainId.GetName()) + if _, isFound := k.GetRollappByName(ctx, rollappId.GetName()); isFound { + return types.ErrRollappExists } - nextRevisionNumber := existingRollappChainId.GetRevisionNumber() + 1 - if rollappId.GetRevisionNumber() != nextRevisionNumber { - return errorsmod.Wrapf(types.ErrInvalidRollappID, "revision number should be %d", nextRevisionNumber) - } return nil } @@ -311,86 +289,6 @@ func (k Keeper) IsRollappStarted(ctx sdk.Context, rollappId string) bool { return found } -func (k Keeper) MarkRollappAsVulnerable(ctx sdk.Context, rollappId string) error { - return k.FreezeRollapp(ctx, rollappId) -} - -// FreezeRollapp marks the rollapp as frozen and reverts all pending states. -// NB! This method is going to be changed as soon as the "Freezing" ADR is ready. -func (k Keeper) FreezeRollapp(ctx sdk.Context, rollappID string) error { - rollapp, found := k.GetRollapp(ctx, rollappID) - if !found { - return gerrc.ErrNotFound - } - - rollapp.Frozen = true - - err := k.RevertPendingStates(ctx, rollappID) - if err != nil { - return fmt.Errorf("revert pending states: %w", err) - } - - if rollapp.ChannelId != "" { - clientID, _, err := k.channelKeeper.GetChannelClientState(ctx, "transfer", rollapp.ChannelId) - if err != nil { - return fmt.Errorf("get channel client state: %w", err) - } - - err = k.freezeClientState(ctx, clientID) - if err != nil { - return fmt.Errorf("freeze client state: %w", err) - } - } - - k.SetRollapp(ctx, rollapp) - return nil -} - -// verifyClientID verifies that the provided clientID is the same clientID used by the provided rollapp. -// Possible scenarios: -// 1. both channelID and clientID are empty -> okay -// 2. channelID is empty while clientID is not -> error: rollapp does not have a channel -// 3. clientID is empty while channelID is not -> error: rollapp does have a channel, but the provided clientID is empty -// 4. both channelID and clientID are not empty -> okay: compare the provided channelID against the one from IBC -func (k Keeper) verifyClientID(ctx sdk.Context, rollappID, clientID string) error { - rollapp, found := k.GetRollapp(ctx, rollappID) - if !found { - return gerrc.ErrNotFound - } - - var ( - emptyRollappChannelID = rollapp.ChannelId == "" - emptyClientID = clientID == "" - ) - - switch { - // both channelID and clientID are empty - case emptyRollappChannelID && emptyClientID: - return nil // everything is fine, expected scenario - - // channelID is empty while clientID is not - case emptyRollappChannelID: - return fmt.Errorf("rollapp does not have a channel: rollapp '%s'", rollappID) - - // clientID is empty while channelID is not - case emptyClientID: - return fmt.Errorf("empty clientID while the rollapp channelID is not empty") - - // both channelID and clientID are not empty - default: - // extract rollapp channelID - extractedClientId, _, err := k.channelKeeper.GetChannelClientState(ctx, "transfer", rollapp.ChannelId) - if err != nil { - return fmt.Errorf("get channel client state: %w", err) - } - // compare it with the passed clientID - if extractedClientId != clientID { - return fmt.Errorf("clientID does not match the one in the rollapp: clientID %s, rollapp clientID %s", clientID, extractedClientId) - } - return nil - } -} - func (k Keeper) FilterRollapps(ctx sdk.Context, f func(types.Rollapp) bool) []types.Rollapp { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.RollappKeyPrefix)) iterator := sdk.KVStorePrefixIterator(store, []byte{}) @@ -407,24 +305,20 @@ func (k Keeper) FilterRollapps(ctx sdk.Context, f func(types.Rollapp) bool) []ty return result } -func FilterNonVulnerable(b types.Rollapp) bool { - return !b.IsVulnerable() -} - -func (k Keeper) IsDRSVersionVulnerable(ctx sdk.Context, version uint32) bool { - ok, err := k.vulnerableDRSVersions.Has(ctx, version) +func (k Keeper) IsDRSVersionObsolete(ctx sdk.Context, version uint32) bool { + ok, err := k.obsoleteDRSVersions.Has(ctx, version) if err != nil { - panic(fmt.Sprintf("checking if DRS version is vulnerable: %v", err)) + panic(fmt.Sprintf("checking if DRS version is obsolete: %v", err)) } return ok } -func (k Keeper) SetVulnerableDRSVersion(ctx sdk.Context, version uint32) error { - return k.vulnerableDRSVersions.Set(ctx, version) +func (k Keeper) SetObsoleteDRSVersion(ctx sdk.Context, version uint32) error { + return k.obsoleteDRSVersions.Set(ctx, version) } -func (k Keeper) GetAllVulnerableDRSVersions(ctx sdk.Context) ([]uint32, error) { - iter, err := k.vulnerableDRSVersions.Iterate(ctx, nil) +func (k Keeper) GetAllObsoleteDRSVersions(ctx sdk.Context) ([]uint32, error) { + iter, err := k.obsoleteDRSVersions.Iterate(ctx, nil) if err != nil { return nil, err } diff --git a/x/rollapp/keeper/rollapp_suite_test.go b/x/rollapp/keeper/rollapp_suite_test.go index 663501969..1708c84a1 100644 --- a/x/rollapp/keeper/rollapp_suite_test.go +++ b/x/rollapp/keeper/rollapp_suite_test.go @@ -53,7 +53,7 @@ func (suite *RollappTestSuite) SetupTest() { queryClient := types.NewQueryClient(queryHelper) suite.App = app - suite.msgServer = keeper.NewMsgServerImpl(*app.RollappKeeper) + suite.msgServer = keeper.NewMsgServerImpl(app.RollappKeeper) suite.seqMsgServer = sequencerkeeper.NewMsgServerImpl(app.SequencerKeeper) suite.Ctx = ctx suite.queryClient = queryClient @@ -72,14 +72,13 @@ func TestRollappKeeperTestSuite(t *testing.T) { suite.Run(t, new(RollappTestSuite)) } -func (suite *RollappTestSuite) IsRollappVulnerable(rollappID string) bool { - ra, ok := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappID) - suite.Require().True(ok) - return ra.IsVulnerable() +func (suite *RollappTestSuite) assertNotForked(rollappID string) { + rollapp, _ := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappID) + suite.Zero(rollapp.RevisionNumber) } func (suite *RollappTestSuite) GetRollappLastHeight(rollappID string) uint64 { stateInfo, ok := suite.App.RollappKeeper.GetLatestStateInfo(suite.Ctx, rollappID) suite.Require().True(ok) - return stateInfo.GetLatestHeight() + 1 + return stateInfo.GetLatestHeight() } diff --git a/x/rollapp/keeper/sequencer_hooks.go b/x/rollapp/keeper/sequencer_hooks.go new file mode 100644 index 000000000..e21a78582 --- /dev/null +++ b/x/rollapp/keeper/sequencer_hooks.go @@ -0,0 +1,46 @@ +package keeper + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" +) + +var _ sequencertypes.Hooks = SequencerHooks{} + +type SequencerHooks struct { + *Keeper +} + +// AfterRecoveryFromHalt is called after a new sequencer is set the proposer for an halted rollapp. +// We assume the rollapp had forked once halted +func (h SequencerHooks) AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, newSeq sequencertypes.Sequencer) error { + // Start the liveness clock from zero + // NOTE: it could make more sense if liveness was a property of the sequencer rather than the rollapp + // TODO: tech debt https://github.com/dymensionxyz/dymension/issues/1357 + + ra := h.Keeper.MustGetRollapp(ctx, rollapp) + h.Keeper.ResetLivenessClock(ctx, &ra) + h.Keeper.ScheduleLivenessEvent(ctx, &ra) + h.Keeper.SetRollapp(ctx, ra) + + // if the rollapp has a state info, set the next proposer to this sequencer + sInfo, ok := h.Keeper.GetLatestStateInfo(ctx, rollapp) + if !ok { + return nil + } + sInfo.NextProposer = newSeq.Address + h.Keeper.SetStateInfo(ctx, sInfo) + + return nil +} + +// AfterKickProposer is called after a sequencer is kicked from being a proposer. +// We hard fork the rollapp to the latest state so it'll be ready for the next proposer +func (h SequencerHooks) AfterKickProposer(ctx sdk.Context, kicked sequencertypes.Sequencer) error { + err := h.Keeper.HardForkToLatest(ctx, kicked.RollappId) + if err != nil { + return errorsmod.Wrap(err, "hard fork to latest") + } + return nil +} diff --git a/x/rollapp/keeper/state_info.go b/x/rollapp/keeper/state_info.go index 734734740..9810e7bb4 100644 --- a/x/rollapp/keeper/state_info.go +++ b/x/rollapp/keeper/state_info.go @@ -37,7 +37,6 @@ func (k Keeper) GetStateInfo( return val, true } -// GetLatestStateInfo is utility func (k Keeper) GetLatestStateInfo(ctx sdk.Context, rollappId string, ) (types.StateInfo, bool) { @@ -48,6 +47,16 @@ func (k Keeper) GetLatestStateInfo(ctx sdk.Context, return k.GetStateInfo(ctx, rollappId, ix.GetIndex()) } +func (k Keeper) GetLatestFinalizedStateInfo(ctx sdk.Context, + rollappId string, +) (types.StateInfo, bool) { + ix, ok := k.GetLatestFinalizedStateIndex(ctx, rollappId) + if !ok { + return types.StateInfo{}, false + } + return k.GetStateInfo(ctx, rollappId, ix.GetIndex()) +} + func (k Keeper) MustGetStateInfo(ctx sdk.Context, rollappId string, index uint64, diff --git a/x/rollapp/module.go b/x/rollapp/module.go index 82a504d21..5136d16ed 100644 --- a/x/rollapp/module.go +++ b/x/rollapp/module.go @@ -127,7 +127,8 @@ func (am AppModule) Name() string { // RegisterServices registers a GRPC query service to respond to the // module-specific GRPC queries. func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(*am.keeper)) + types.RegisterProposalMsgServer(cfg.MsgServer(), am.keeper) + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) } diff --git a/x/rollapp/proposal_handler.go b/x/rollapp/proposal_handler.go deleted file mode 100644 index e0659d56f..000000000 --- a/x/rollapp/proposal_handler.go +++ /dev/null @@ -1,31 +0,0 @@ -package rollapp - -import ( - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" - "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - - errorsmod "cosmossdk.io/errors" -) - -func NewRollappProposalHandler(k *keeper.Keeper) govtypes.Handler { - return func(ctx sdk.Context, content govtypes.Content) error { - switch c := content.(type) { - case *types.SubmitFraudProposal: - return HandleSubmitFraudProposal(ctx, k, c) - default: - return errorsmod.Wrapf(types.ErrUnknownRequest, "unrecognized rollapp proposal content type: %T", c) - } - } -} - -func HandleSubmitFraudProposal(ctx sdk.Context, k *keeper.Keeper, p *types.SubmitFraudProposal) error { - err := k.HandleFraud(ctx, p.RollappId, p.IbcClientId, p.FraudelentHeight, p.FraudelentSequencerAddress) - if err != nil { - return err - } - return nil -} diff --git a/x/rollapp/types/chain_id_test.go b/x/rollapp/types/chain_id_test.go new file mode 100644 index 000000000..5c6d8f92f --- /dev/null +++ b/x/rollapp/types/chain_id_test.go @@ -0,0 +1,68 @@ +package types + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestChainID(t *testing.T) { + tests := []struct { + name string + rollappId string + revision uint64 + expErr error + }{ + { + name: "default is valid", + rollappId: "rollapp_1234-1", + revision: 1, + expErr: nil, + }, + { + name: "too long id", + rollappId: "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz_1234-1", + expErr: ErrInvalidRollappID, + }, + { + name: "wrong EIP155", + rollappId: "rollapp_ea2413-1", + expErr: ErrInvalidRollappID, + }, + { + name: "no EIP155 with revision", + rollappId: "rollapp-1", + expErr: ErrInvalidRollappID, + }, + { + name: "starts with dash", + rollappId: "-1234", + expErr: ErrInvalidRollappID, + }, + { + name: "revision set without eip155", + rollappId: "rollapp-3", + expErr: ErrInvalidRollappID, + }, + { + name: "revision not set", + rollappId: "rollapp", + expErr: ErrInvalidRollappID, + }, + { + name: "invalid revision", + rollappId: "rollapp_1234-x", + expErr: ErrInvalidRollappID, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + id, err := NewChainID(test.rollappId) + require.ErrorIs(t, err, test.expErr) + if err == nil { + require.Equal(t, test.revision, id.GetRevisionNumber()) + } + }) + } +} diff --git a/x/rollapp/types/codec.go b/x/rollapp/types/codec.go index 3b37c5560..a548611ba 100644 --- a/x/rollapp/types/codec.go +++ b/x/rollapp/types/codec.go @@ -6,8 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" - - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) func RegisterCodec(cdc *codec.LegacyAmino) { @@ -18,8 +16,8 @@ func RegisterCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgAddApp{}, "rollapp/AddApp", nil) cdc.RegisterConcrete(&MsgUpdateApp{}, "rollapp/UpdateApp", nil) cdc.RegisterConcrete(&MsgRemoveApp{}, "rollapp/RemoveApp", nil) - cdc.RegisterConcrete(&MsgMarkVulnerableRollapps{}, "rollapp/MarkVulnerableRollapps", nil) - cdc.RegisterConcrete(&SubmitFraudProposal{}, "rollapp/SubmitFraudProposal", nil) + cdc.RegisterConcrete(&MsgRollappFraudProposal{}, "rollapp/RollappFraudProposal", nil) + cdc.RegisterConcrete(&MsgMarkObsoleteRollapps{}, "rollapp/MarkObsoleteRollapps", nil) } func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { @@ -31,9 +29,9 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { &MsgAddApp{}, &MsgUpdateApp{}, &MsgRemoveApp{}, - &MsgMarkVulnerableRollapps{}, + &MsgRollappFraudProposal{}, + &MsgMarkObsoleteRollapps{}, ) - registry.RegisterImplementations((*govtypes.Content)(nil), &SubmitFraudProposal{}) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/rollapp/types/errors.go b/x/rollapp/types/errors.go index 1283fca93..df24a33f5 100644 --- a/x/rollapp/types/errors.go +++ b/x/rollapp/types/errors.go @@ -52,8 +52,8 @@ var ( /* ------------------------------ fraud related ----------------------------- */ ErrDisputeAlreadyFinalized = errorsmod.Register(ModuleName, 2000, "disputed height already finalized") - ErrDisputeAlreadyReverted = errorsmod.Register(ModuleName, 2001, "disputed height already reverted") ErrWrongClientId = errorsmod.Register(ModuleName, 2002, "client id does not match the rollapp") ErrWrongProposerAddr = errorsmod.Register(ModuleName, 2003, "wrong proposer address") ErrInvalidDRSVersion = errorsmod.Register(ModuleName, 2004, "wrong DRS version") + ErrWrongRollappRevision = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "wrong rollapp revision") ) diff --git a/x/rollapp/types/events.pb.go b/x/rollapp/types/events.pb.go index 31c3e2cb4..7d6ee9de3 100644 --- a/x/rollapp/types/events.pb.go +++ b/x/rollapp/types/events.pb.go @@ -154,25 +154,25 @@ func (m *EventAppRemoved) GetApp() *App { return nil } -type EventMarkVulnerableRollapps struct { - // VulnerableRollappNum is a number of rollapps that were marked as vulnerable. - VulnerableRollappNum uint64 `protobuf:"varint,1,opt,name=vulnerable_rollapp_num,json=vulnerableRollappNum,proto3" json:"vulnerable_rollapp_num,omitempty"` - // DrsVersions is a list of DRS versions that were marked as vulnerable. +type EventMarkObsoleteRollapps struct { + // ObsoleteRollappNum is a number of rollapps that were marked as obsolete. + ObsoleteRollappNum uint64 `protobuf:"varint,1,opt,name=obsolete_rollapp_num,json=obsoleteRollappNum,proto3" json:"obsolete_rollapp_num,omitempty"` + // DrsVersions is a list of DRS versions that were marked as obsolete. DrsVersions []uint32 `protobuf:"varint,2,rep,packed,name=drs_versions,json=drsVersions,proto3" json:"drs_versions,omitempty"` } -func (m *EventMarkVulnerableRollapps) Reset() { *m = EventMarkVulnerableRollapps{} } -func (m *EventMarkVulnerableRollapps) String() string { return proto.CompactTextString(m) } -func (*EventMarkVulnerableRollapps) ProtoMessage() {} -func (*EventMarkVulnerableRollapps) Descriptor() ([]byte, []int) { +func (m *EventMarkObsoleteRollapps) Reset() { *m = EventMarkObsoleteRollapps{} } +func (m *EventMarkObsoleteRollapps) String() string { return proto.CompactTextString(m) } +func (*EventMarkObsoleteRollapps) ProtoMessage() {} +func (*EventMarkObsoleteRollapps) Descriptor() ([]byte, []int) { return fileDescriptor_e0f74405c12dec3c, []int{3} } -func (m *EventMarkVulnerableRollapps) XXX_Unmarshal(b []byte) error { +func (m *EventMarkObsoleteRollapps) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *EventMarkVulnerableRollapps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *EventMarkObsoleteRollapps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_EventMarkVulnerableRollapps.Marshal(b, m, deterministic) + return xxx_messageInfo_EventMarkObsoleteRollapps.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -182,26 +182,26 @@ func (m *EventMarkVulnerableRollapps) XXX_Marshal(b []byte, deterministic bool) return b[:n], nil } } -func (m *EventMarkVulnerableRollapps) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventMarkVulnerableRollapps.Merge(m, src) +func (m *EventMarkObsoleteRollapps) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventMarkObsoleteRollapps.Merge(m, src) } -func (m *EventMarkVulnerableRollapps) XXX_Size() int { +func (m *EventMarkObsoleteRollapps) XXX_Size() int { return m.Size() } -func (m *EventMarkVulnerableRollapps) XXX_DiscardUnknown() { - xxx_messageInfo_EventMarkVulnerableRollapps.DiscardUnknown(m) +func (m *EventMarkObsoleteRollapps) XXX_DiscardUnknown() { + xxx_messageInfo_EventMarkObsoleteRollapps.DiscardUnknown(m) } -var xxx_messageInfo_EventMarkVulnerableRollapps proto.InternalMessageInfo +var xxx_messageInfo_EventMarkObsoleteRollapps proto.InternalMessageInfo -func (m *EventMarkVulnerableRollapps) GetVulnerableRollappNum() uint64 { +func (m *EventMarkObsoleteRollapps) GetObsoleteRollappNum() uint64 { if m != nil { - return m.VulnerableRollappNum + return m.ObsoleteRollappNum } return 0 } -func (m *EventMarkVulnerableRollapps) GetDrsVersions() []uint32 { +func (m *EventMarkObsoleteRollapps) GetDrsVersions() []uint32 { if m != nil { return m.DrsVersions } @@ -212,7 +212,7 @@ func init() { proto.RegisterType((*EventAppAdded)(nil), "dymensionxyz.dymension.rollapp.EventAppAdded") proto.RegisterType((*EventAppUpdated)(nil), "dymensionxyz.dymension.rollapp.EventAppUpdated") proto.RegisterType((*EventAppRemoved)(nil), "dymensionxyz.dymension.rollapp.EventAppRemoved") - proto.RegisterType((*EventMarkVulnerableRollapps)(nil), "dymensionxyz.dymension.rollapp.EventMarkVulnerableRollapps") + proto.RegisterType((*EventMarkObsoleteRollapps)(nil), "dymensionxyz.dymension.rollapp.EventMarkObsoleteRollapps") } func init() { @@ -220,7 +220,7 @@ func init() { } var fileDescriptor_e0f74405c12dec3c = []byte{ - // 279 bytes of a gzipped FileDescriptorProto + // 277 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4e, 0xa9, 0xcc, 0x4d, 0xcd, 0x2b, 0xce, 0xcc, 0xcf, 0xab, 0xa8, 0xac, 0xd2, 0x87, 0x73, 0xf4, 0x8b, 0xf2, 0x73, 0x72, 0x12, 0x0b, 0x0a, 0xf4, 0x53, 0xcb, 0x52, 0xf3, 0x4a, 0x8a, 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, @@ -229,16 +229,16 @@ var fileDescriptor_e0f74405c12dec3c = []byte{ 0x25, 0x35, 0x45, 0xc8, 0x94, 0x8b, 0x39, 0xb1, 0xa0, 0x40, 0x82, 0x51, 0x81, 0x51, 0x83, 0xdb, 0x48, 0x59, 0x0f, 0xbf, 0x45, 0x7a, 0x8e, 0x05, 0x05, 0x41, 0x20, 0xf5, 0x4a, 0x1e, 0x5c, 0xfc, 0x30, 0x73, 0x42, 0x0b, 0x52, 0x12, 0x4b, 0xa8, 0x62, 0x52, 0x50, 0x6a, 0x6e, 0x7e, 0x19, 0xf9, - 0x26, 0x95, 0x71, 0x49, 0x83, 0x4d, 0xf2, 0x4d, 0x2c, 0xca, 0x0e, 0x2b, 0xcd, 0xc9, 0x4b, 0x2d, - 0x4a, 0x4c, 0xca, 0x49, 0x0d, 0x82, 0x28, 0x2b, 0x16, 0x32, 0xe1, 0x12, 0x2b, 0x83, 0x8b, 0xc6, - 0x43, 0x75, 0xc7, 0xe7, 0x95, 0xe6, 0x82, 0x2d, 0x62, 0x09, 0x12, 0x29, 0x43, 0xd7, 0xe3, 0x57, - 0x9a, 0x2b, 0xa4, 0xc8, 0xc5, 0x93, 0x52, 0x54, 0x1c, 0x5f, 0x96, 0x5a, 0x04, 0xb2, 0xb4, 0x58, - 0x82, 0x49, 0x81, 0x59, 0x83, 0x37, 0x88, 0x3b, 0xa5, 0xa8, 0x38, 0x0c, 0x2a, 0xe4, 0xe4, 0x77, - 0xe2, 0x91, 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, - 0x70, 0xe1, 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x26, 0xe9, 0x99, 0x25, 0x19, 0xa5, - 0x49, 0x7a, 0xc9, 0xf9, 0xb9, 0xfa, 0x38, 0xa2, 0xa8, 0xcc, 0x58, 0xbf, 0x02, 0x1e, 0x4f, 0x25, - 0x95, 0x05, 0xa9, 0xc5, 0x49, 0x6c, 0xe0, 0xa8, 0x32, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x4b, - 0xae, 0xca, 0xc3, 0x23, 0x02, 0x00, 0x00, + 0x26, 0x15, 0x70, 0x49, 0x82, 0x4d, 0xf2, 0x4d, 0x2c, 0xca, 0xf6, 0x4f, 0x2a, 0xce, 0xcf, 0x49, + 0x2d, 0x49, 0x0d, 0x82, 0x28, 0x2a, 0x16, 0x32, 0xe0, 0x12, 0xc9, 0x87, 0x8a, 0xc5, 0x43, 0x75, + 0xc6, 0xe7, 0x95, 0xe6, 0x82, 0x2d, 0x61, 0x09, 0x12, 0xca, 0x47, 0x55, 0xef, 0x57, 0x9a, 0x2b, + 0xa4, 0xc8, 0xc5, 0x93, 0x52, 0x54, 0x1c, 0x5f, 0x96, 0x5a, 0x04, 0xb2, 0xae, 0x58, 0x82, 0x49, + 0x81, 0x59, 0x83, 0x37, 0x88, 0x3b, 0xa5, 0xa8, 0x38, 0x0c, 0x2a, 0xe4, 0xe4, 0x77, 0xe2, 0x91, + 0x1c, 0xe3, 0x85, 0x47, 0x72, 0x8c, 0x0f, 0x1e, 0xc9, 0x31, 0x4e, 0x78, 0x2c, 0xc7, 0x70, 0xe1, + 0xb1, 0x1c, 0xc3, 0x8d, 0xc7, 0x72, 0x0c, 0x51, 0x26, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, + 0xc9, 0xf9, 0xb9, 0xfa, 0x38, 0x22, 0xa7, 0xcc, 0x58, 0xbf, 0x02, 0x1e, 0x43, 0x25, 0x95, 0x05, + 0xa9, 0xc5, 0x49, 0x6c, 0xe0, 0x48, 0x32, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x9b, 0x93, 0xbd, + 0x81, 0x1d, 0x02, 0x00, 0x00, } func (m *EventAppAdded) Marshal() (dAtA []byte, err error) { @@ -346,7 +346,7 @@ func (m *EventAppRemoved) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *EventMarkVulnerableRollapps) Marshal() (dAtA []byte, err error) { +func (m *EventMarkObsoleteRollapps) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -356,12 +356,12 @@ func (m *EventMarkVulnerableRollapps) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *EventMarkVulnerableRollapps) MarshalTo(dAtA []byte) (int, error) { +func (m *EventMarkObsoleteRollapps) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *EventMarkVulnerableRollapps) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *EventMarkObsoleteRollapps) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -384,8 +384,8 @@ func (m *EventMarkVulnerableRollapps) MarshalToSizedBuffer(dAtA []byte) (int, er i-- dAtA[i] = 0x12 } - if m.VulnerableRollappNum != 0 { - i = encodeVarintEvents(dAtA, i, uint64(m.VulnerableRollappNum)) + if m.ObsoleteRollappNum != 0 { + i = encodeVarintEvents(dAtA, i, uint64(m.ObsoleteRollappNum)) i-- dAtA[i] = 0x8 } @@ -442,14 +442,14 @@ func (m *EventAppRemoved) Size() (n int) { return n } -func (m *EventMarkVulnerableRollapps) Size() (n int) { +func (m *EventMarkObsoleteRollapps) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.VulnerableRollappNum != 0 { - n += 1 + sovEvents(uint64(m.VulnerableRollappNum)) + if m.ObsoleteRollappNum != 0 { + n += 1 + sovEvents(uint64(m.ObsoleteRollappNum)) } if len(m.DrsVersions) > 0 { l = 0 @@ -725,7 +725,7 @@ func (m *EventAppRemoved) Unmarshal(dAtA []byte) error { } return nil } -func (m *EventMarkVulnerableRollapps) Unmarshal(dAtA []byte) error { +func (m *EventMarkObsoleteRollapps) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -748,17 +748,17 @@ func (m *EventMarkVulnerableRollapps) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: EventMarkVulnerableRollapps: wiretype end group for non-group") + return fmt.Errorf("proto: EventMarkObsoleteRollapps: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: EventMarkVulnerableRollapps: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: EventMarkObsoleteRollapps: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field VulnerableRollappNum", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ObsoleteRollappNum", wireType) } - m.VulnerableRollappNum = 0 + m.ObsoleteRollappNum = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -768,7 +768,7 @@ func (m *EventMarkVulnerableRollapps) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.VulnerableRollappNum |= uint64(b&0x7F) << shift + m.ObsoleteRollappNum |= uint64(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/rollapp/types/fraud_proposal.pb.go b/x/rollapp/types/fraud_proposal.pb.go new file mode 100644 index 000000000..861064106 --- /dev/null +++ b/x/rollapp/types/fraud_proposal.pb.go @@ -0,0 +1,766 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: dymensionxyz/dymension/rollapp/fraud_proposal.proto + +package types + +import ( + context "context" + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "github.com/cosmos/gogoproto/gogoproto" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type MsgRollappFraudProposal struct { + // Authority is the authority address. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` + // RollappID is the rollapp id. + RollappId string `protobuf:"bytes,2,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` + // rollapp revision. used to verify the rollapp revision is the same as the one in the fraud proposal + RollappRevision uint64 `protobuf:"varint,3,opt,name=rollapp_revision,json=rollappRevision,proto3" json:"rollapp_revision,omitempty"` + // The height of the fraudelent block + FraudHeight uint64 `protobuf:"varint,4,opt,name=fraud_height,json=fraudHeight,proto3" json:"fraud_height,omitempty"` + // sequencer address to punish. optional + PunishSequencerAddress string `protobuf:"bytes,6,opt,name=punish_sequencer_address,json=punishSequencerAddress,proto3" json:"punish_sequencer_address,omitempty"` + // rewardAddr is bech32 for sdk acc addr + Rewardee string `protobuf:"bytes,7,opt,name=rewardee,proto3" json:"rewardee,omitempty"` +} + +func (m *MsgRollappFraudProposal) Reset() { *m = MsgRollappFraudProposal{} } +func (m *MsgRollappFraudProposal) String() string { return proto.CompactTextString(m) } +func (*MsgRollappFraudProposal) ProtoMessage() {} +func (*MsgRollappFraudProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_120f0332aea0a45b, []int{0} +} +func (m *MsgRollappFraudProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRollappFraudProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRollappFraudProposal.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRollappFraudProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRollappFraudProposal.Merge(m, src) +} +func (m *MsgRollappFraudProposal) XXX_Size() int { + return m.Size() +} +func (m *MsgRollappFraudProposal) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRollappFraudProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRollappFraudProposal proto.InternalMessageInfo + +func (m *MsgRollappFraudProposal) GetAuthority() string { + if m != nil { + return m.Authority + } + return "" +} + +func (m *MsgRollappFraudProposal) GetRollappId() string { + if m != nil { + return m.RollappId + } + return "" +} + +func (m *MsgRollappFraudProposal) GetRollappRevision() uint64 { + if m != nil { + return m.RollappRevision + } + return 0 +} + +func (m *MsgRollappFraudProposal) GetFraudHeight() uint64 { + if m != nil { + return m.FraudHeight + } + return 0 +} + +func (m *MsgRollappFraudProposal) GetPunishSequencerAddress() string { + if m != nil { + return m.PunishSequencerAddress + } + return "" +} + +func (m *MsgRollappFraudProposal) GetRewardee() string { + if m != nil { + return m.Rewardee + } + return "" +} + +type MsgRollappFraudProposalResponse struct { +} + +func (m *MsgRollappFraudProposalResponse) Reset() { *m = MsgRollappFraudProposalResponse{} } +func (m *MsgRollappFraudProposalResponse) String() string { return proto.CompactTextString(m) } +func (*MsgRollappFraudProposalResponse) ProtoMessage() {} +func (*MsgRollappFraudProposalResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_120f0332aea0a45b, []int{1} +} +func (m *MsgRollappFraudProposalResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgRollappFraudProposalResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgRollappFraudProposalResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgRollappFraudProposalResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgRollappFraudProposalResponse.Merge(m, src) +} +func (m *MsgRollappFraudProposalResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgRollappFraudProposalResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgRollappFraudProposalResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgRollappFraudProposalResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgRollappFraudProposal)(nil), "dymensionxyz.dymension.rollapp.MsgRollappFraudProposal") + proto.RegisterType((*MsgRollappFraudProposalResponse)(nil), "dymensionxyz.dymension.rollapp.MsgRollappFraudProposalResponse") +} + +func init() { + proto.RegisterFile("dymensionxyz/dymension/rollapp/fraud_proposal.proto", fileDescriptor_120f0332aea0a45b) +} + +var fileDescriptor_120f0332aea0a45b = []byte{ + // 392 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xbf, 0x4e, 0xe3, 0x40, + 0x10, 0xc6, 0xb3, 0xb9, 0x28, 0x77, 0xd9, 0x9c, 0xee, 0x4e, 0xab, 0x13, 0xb1, 0x2c, 0x30, 0x49, + 0xaa, 0x40, 0xe1, 0x15, 0x04, 0x09, 0x44, 0x83, 0xa0, 0x40, 0x50, 0x04, 0x21, 0xa7, 0xa3, 0xb1, + 0x9c, 0x78, 0xb1, 0x57, 0x8a, 0xbd, 0xcb, 0xae, 0x1d, 0x62, 0x4a, 0x4a, 0x0a, 0xc4, 0x13, 0xf0, + 0x0c, 0x3c, 0x06, 0x65, 0x4a, 0x4a, 0x94, 0x14, 0xbc, 0x06, 0xf2, 0xdf, 0xa4, 0x09, 0x05, 0x95, + 0x3d, 0xbf, 0x6f, 0x3e, 0x7d, 0x33, 0xf6, 0xc0, 0xae, 0x1d, 0x79, 0xc4, 0x97, 0x94, 0xf9, 0x93, + 0xe8, 0x0e, 0x17, 0x05, 0x16, 0x6c, 0x34, 0xb2, 0x38, 0xc7, 0xd7, 0xc2, 0x0a, 0x6d, 0x93, 0x0b, + 0xc6, 0x99, 0xb4, 0x46, 0x3a, 0x17, 0x2c, 0x60, 0x48, 0x5b, 0x36, 0xe9, 0x45, 0xa1, 0x67, 0x26, + 0xf5, 0xbf, 0xc3, 0x1c, 0x96, 0xb4, 0xe2, 0xf8, 0x2d, 0x75, 0xa9, 0x8d, 0x21, 0x93, 0x1e, 0x93, + 0xd8, 0x93, 0x0e, 0x1e, 0xef, 0xc4, 0x8f, 0x54, 0x68, 0x3f, 0x94, 0x61, 0xa3, 0x27, 0x1d, 0x23, + 0x75, 0x9f, 0xc6, 0x89, 0x97, 0x59, 0x20, 0x5a, 0x87, 0x35, 0x2b, 0x0c, 0x5c, 0x26, 0x68, 0x10, + 0x29, 0xa0, 0x09, 0x3a, 0x35, 0x63, 0x01, 0xd0, 0x06, 0x84, 0x59, 0xa6, 0x49, 0x6d, 0xa5, 0x9c, + 0xca, 0x19, 0x39, 0xb7, 0xd1, 0x16, 0xfc, 0x97, 0xcb, 0x82, 0x8c, 0x69, 0x3c, 0xa3, 0xf2, 0xa3, + 0x09, 0x3a, 0x15, 0xe3, 0x6f, 0xc6, 0x8d, 0x0c, 0xa3, 0x16, 0xfc, 0x9d, 0xae, 0xea, 0x12, 0xea, + 0xb8, 0x81, 0x52, 0x49, 0xda, 0xea, 0x09, 0x3b, 0x4b, 0x10, 0x3a, 0x80, 0x0a, 0x0f, 0x7d, 0x2a, + 0x5d, 0x53, 0x92, 0x9b, 0x90, 0xf8, 0x43, 0x22, 0x4c, 0xcb, 0xb6, 0x05, 0x91, 0x52, 0xa9, 0x26, + 0xd1, 0x6b, 0xa9, 0xde, 0xcf, 0xe5, 0xe3, 0x54, 0x45, 0x2a, 0xfc, 0x25, 0xc8, 0xad, 0x25, 0x6c, + 0x42, 0x94, 0x9f, 0x49, 0x67, 0x51, 0x1f, 0xfe, 0xb9, 0xff, 0x78, 0xd9, 0x5e, 0xac, 0xd4, 0x6e, + 0xc1, 0xcd, 0x15, 0xdf, 0xc2, 0x20, 0x92, 0x33, 0x5f, 0x92, 0xdd, 0x67, 0x00, 0xeb, 0x39, 0xec, + 0x49, 0x07, 0x3d, 0x02, 0x88, 0xfa, 0xe1, 0xc0, 0xa3, 0xc1, 0xb2, 0x0d, 0xed, 0xeb, 0x5f, 0xff, + 0x26, 0x7d, 0x45, 0x8e, 0x7a, 0xf4, 0x4d, 0x63, 0x3e, 0xe0, 0xc9, 0xc5, 0xeb, 0x4c, 0x03, 0xd3, + 0x99, 0x06, 0xde, 0x67, 0x1a, 0x78, 0x9a, 0x6b, 0xa5, 0xe9, 0x5c, 0x2b, 0xbd, 0xcd, 0xb5, 0xd2, + 0xd5, 0x9e, 0x43, 0x03, 0x37, 0x1c, 0xe8, 0x43, 0xe6, 0xe1, 0x15, 0x97, 0x37, 0xee, 0xe2, 0x49, + 0x71, 0x7e, 0x41, 0xc4, 0x89, 0x1c, 0x54, 0x93, 0x3b, 0xe9, 0x7e, 0x06, 0x00, 0x00, 0xff, 0xff, + 0xbe, 0x68, 0xc5, 0x9b, 0xad, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// ProposalMsgClient is the client API for ProposalMsg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type ProposalMsgClient interface { + SubmitRollappFraud(ctx context.Context, in *MsgRollappFraudProposal, opts ...grpc.CallOption) (*MsgRollappFraudProposalResponse, error) +} + +type proposalMsgClient struct { + cc grpc1.ClientConn +} + +func NewProposalMsgClient(cc grpc1.ClientConn) ProposalMsgClient { + return &proposalMsgClient{cc} +} + +func (c *proposalMsgClient) SubmitRollappFraud(ctx context.Context, in *MsgRollappFraudProposal, opts ...grpc.CallOption) (*MsgRollappFraudProposalResponse, error) { + out := new(MsgRollappFraudProposalResponse) + err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.rollapp.ProposalMsg/SubmitRollappFraud", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ProposalMsgServer is the server API for ProposalMsg service. +type ProposalMsgServer interface { + SubmitRollappFraud(context.Context, *MsgRollappFraudProposal) (*MsgRollappFraudProposalResponse, error) +} + +// UnimplementedProposalMsgServer can be embedded to have forward compatible implementations. +type UnimplementedProposalMsgServer struct { +} + +func (*UnimplementedProposalMsgServer) SubmitRollappFraud(ctx context.Context, req *MsgRollappFraudProposal) (*MsgRollappFraudProposalResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SubmitRollappFraud not implemented") +} + +func RegisterProposalMsgServer(s grpc1.Server, srv ProposalMsgServer) { + s.RegisterService(&_ProposalMsg_serviceDesc, srv) +} + +func _ProposalMsg_SubmitRollappFraud_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgRollappFraudProposal) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ProposalMsgServer).SubmitRollappFraud(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dymensionxyz.dymension.rollapp.ProposalMsg/SubmitRollappFraud", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ProposalMsgServer).SubmitRollappFraud(ctx, req.(*MsgRollappFraudProposal)) + } + return interceptor(ctx, in, info, handler) +} + +var _ProposalMsg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "dymensionxyz.dymension.rollapp.ProposalMsg", + HandlerType: (*ProposalMsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SubmitRollappFraud", + Handler: _ProposalMsg_SubmitRollappFraud_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "dymensionxyz/dymension/rollapp/fraud_proposal.proto", +} + +func (m *MsgRollappFraudProposal) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRollappFraudProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRollappFraudProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Rewardee) > 0 { + i -= len(m.Rewardee) + copy(dAtA[i:], m.Rewardee) + i = encodeVarintFraudProposal(dAtA, i, uint64(len(m.Rewardee))) + i-- + dAtA[i] = 0x3a + } + if len(m.PunishSequencerAddress) > 0 { + i -= len(m.PunishSequencerAddress) + copy(dAtA[i:], m.PunishSequencerAddress) + i = encodeVarintFraudProposal(dAtA, i, uint64(len(m.PunishSequencerAddress))) + i-- + dAtA[i] = 0x32 + } + if m.FraudHeight != 0 { + i = encodeVarintFraudProposal(dAtA, i, uint64(m.FraudHeight)) + i-- + dAtA[i] = 0x20 + } + if m.RollappRevision != 0 { + i = encodeVarintFraudProposal(dAtA, i, uint64(m.RollappRevision)) + i-- + dAtA[i] = 0x18 + } + if len(m.RollappId) > 0 { + i -= len(m.RollappId) + copy(dAtA[i:], m.RollappId) + i = encodeVarintFraudProposal(dAtA, i, uint64(len(m.RollappId))) + i-- + dAtA[i] = 0x12 + } + if len(m.Authority) > 0 { + i -= len(m.Authority) + copy(dAtA[i:], m.Authority) + i = encodeVarintFraudProposal(dAtA, i, uint64(len(m.Authority))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgRollappFraudProposalResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgRollappFraudProposalResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgRollappFraudProposalResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintFraudProposal(dAtA []byte, offset int, v uint64) int { + offset -= sovFraudProposal(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgRollappFraudProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Authority) + if l > 0 { + n += 1 + l + sovFraudProposal(uint64(l)) + } + l = len(m.RollappId) + if l > 0 { + n += 1 + l + sovFraudProposal(uint64(l)) + } + if m.RollappRevision != 0 { + n += 1 + sovFraudProposal(uint64(m.RollappRevision)) + } + if m.FraudHeight != 0 { + n += 1 + sovFraudProposal(uint64(m.FraudHeight)) + } + l = len(m.PunishSequencerAddress) + if l > 0 { + n += 1 + l + sovFraudProposal(uint64(l)) + } + l = len(m.Rewardee) + if l > 0 { + n += 1 + l + sovFraudProposal(uint64(l)) + } + return n +} + +func (m *MsgRollappFraudProposalResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovFraudProposal(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozFraudProposal(x uint64) (n int) { + return sovFraudProposal(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgRollappFraudProposal) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRollappFraudProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRollappFraudProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthFraudProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthFraudProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RollappId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthFraudProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthFraudProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RollappId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RollappRevision", wireType) + } + m.RollappRevision = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RollappRevision |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FraudHeight", wireType) + } + m.FraudHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.FraudHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PunishSequencerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthFraudProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthFraudProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PunishSequencerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rewardee", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthFraudProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthFraudProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Rewardee = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipFraudProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthFraudProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgRollappFraudProposalResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgRollappFraudProposalResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgRollappFraudProposalResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipFraudProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthFraudProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipFraudProposal(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthFraudProposal + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupFraudProposal + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthFraudProposal + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthFraudProposal = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowFraudProposal = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupFraudProposal = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/rollapp/types/genesis.go b/x/rollapp/types/genesis.go index 39cc6b0a3..78dd754c2 100644 --- a/x/rollapp/types/genesis.go +++ b/x/rollapp/types/genesis.go @@ -85,14 +85,14 @@ func (gs GenesisState) Validate() error { appIndexMap[index] = struct{}{} } - // Check for duplicated index in vulnerable DRS versions - vulnerableDRSVersionIndexMap := make(map[uint32]struct{}) + // Check for duplicated index in obsolete DRS versions + obsoleteDRSVersionIndexMap := make(map[uint32]struct{}) - for _, elem := range gs.VulnerableDrsVersions { - if _, ok := vulnerableDRSVersionIndexMap[elem]; ok { - return errors.New("duplicated index for VulnerableDrsVersions") + for _, elem := range gs.ObsoleteDrsVersions { + if _, ok := obsoleteDRSVersionIndexMap[elem]; ok { + return errors.New("duplicated index for ObsoleteDrsVersions") } - vulnerableDRSVersionIndexMap[elem] = struct{}{} + obsoleteDRSVersionIndexMap[elem] = struct{}{} } return gs.Params.Validate() diff --git a/x/rollapp/types/genesis.pb.go b/x/rollapp/types/genesis.pb.go index 03cee006b..40bf4db4b 100644 --- a/x/rollapp/types/genesis.pb.go +++ b/x/rollapp/types/genesis.pb.go @@ -36,8 +36,8 @@ type GenesisState struct { AppList []App `protobuf:"bytes,8,rep,name=appList,proto3" json:"appList"` RegisteredDenoms []RollappRegisteredDenoms `protobuf:"bytes,9,rep,name=registeredDenoms,proto3" json:"registeredDenoms"` SequencerHeightPairs []SequencerHeightPair `protobuf:"bytes,10,rep,name=sequencerHeightPairs,proto3" json:"sequencerHeightPairs"` - // VulnerableDrsVersions is a list of DRS versions that are marked vulnerable - VulnerableDrsVersions []uint32 `protobuf:"varint,11,rep,packed,name=vulnerable_drs_versions,json=vulnerableDrsVersions,proto3" json:"vulnerable_drs_versions,omitempty"` + // ObsoleteDrsVersions is a list of DRS versions that are marked obsolete + ObsoleteDrsVersions []uint32 `protobuf:"varint,11,rep,packed,name=obsolete_drs_versions,json=obsoleteDrsVersions,proto3" json:"obsolete_drs_versions,omitempty"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -143,9 +143,9 @@ func (m *GenesisState) GetSequencerHeightPairs() []SequencerHeightPair { return nil } -func (m *GenesisState) GetVulnerableDrsVersions() []uint32 { +func (m *GenesisState) GetObsoleteDrsVersions() []uint32 { if m != nil { - return m.VulnerableDrsVersions + return m.ObsoleteDrsVersions } return nil } @@ -265,45 +265,44 @@ func init() { } var fileDescriptor_b76890aebc09aa04 = []byte{ - // 596 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0xdf, 0x6e, 0x12, 0x4d, - 0x18, 0xc6, 0xd9, 0xc2, 0x47, 0xcb, 0xf0, 0xd5, 0x98, 0xb1, 0xda, 0x0d, 0x69, 0x57, 0x82, 0x89, - 0x62, 0xb4, 0xbb, 0x49, 0x31, 0x7a, 0x66, 0x22, 0xe2, 0x1f, 0x62, 0xa3, 0x75, 0xab, 0x3d, 0xd0, - 0x03, 0xb2, 0xb0, 0x6f, 0x97, 0x89, 0xcb, 0xcc, 0xba, 0x33, 0x10, 0xe0, 0x2a, 0x3c, 0xf0, 0x56, - 0xbc, 0x87, 0x1e, 0xf6, 0xd0, 0x23, 0x63, 0xe0, 0x46, 0x0c, 0xb3, 0xb3, 0x5b, 0x6c, 0x0b, 0x4b, - 0xe2, 0xd1, 0x32, 0x33, 0xcf, 0xfb, 0x7b, 0x9e, 0x19, 0xde, 0xbc, 0xe8, 0xa1, 0x3b, 0xea, 0x01, - 0xe5, 0x84, 0xd1, 0xe1, 0x68, 0x6c, 0x25, 0x0b, 0x2b, 0x64, 0xbe, 0xef, 0x04, 0x81, 0xe5, 0x01, - 0x05, 0x4e, 0xb8, 0x19, 0x84, 0x4c, 0x30, 0x6c, 0xcc, 0xab, 0xcd, 0x64, 0x61, 0x2a, 0x75, 0x69, - 0xcb, 0x63, 0x1e, 0x93, 0x52, 0x6b, 0xf6, 0x2b, 0xaa, 0x2a, 0x3d, 0x48, 0xf1, 0x08, 0x9c, 0xd0, - 0xe9, 0x29, 0x8b, 0x52, 0x5a, 0x20, 0xf5, 0x55, 0x6a, 0x2b, 0x45, 0xcd, 0x85, 0x23, 0xa0, 0x45, - 0xe8, 0x49, 0x9c, 0x65, 0x2f, 0xa5, 0xc0, 0x27, 0x83, 0xd9, 0x8d, 0xe3, 0x34, 0xd5, 0x14, 0x79, - 0x92, 0xa4, 0xf2, 0x63, 0x03, 0xfd, 0xff, 0x2a, 0x7a, 0xac, 0xa3, 0x99, 0x29, 0x6e, 0xa0, 0x7c, - 0x74, 0x31, 0x5d, 0x2b, 0x6b, 0xd5, 0xe2, 0xfe, 0x5d, 0x73, 0xf9, 0xe3, 0x99, 0x87, 0x52, 0x5d, - 0xcf, 0x9d, 0xfe, 0xba, 0x9d, 0xb1, 0x55, 0x2d, 0x7e, 0x87, 0x8a, 0xea, 0xfc, 0x80, 0x70, 0xa1, - 0xaf, 0x95, 0xb3, 0xd5, 0xe2, 0xfe, 0xbd, 0x34, 0x94, 0x1d, 0x7d, 0x15, 0x6b, 0x9e, 0x80, 0x3f, - 0xa2, 0x4d, 0xf9, 0x28, 0x4d, 0x7a, 0xc2, 0x24, 0x32, 0x2b, 0x91, 0xf7, 0xd3, 0x90, 0x47, 0x71, - 0x91, 0x82, 0xfe, 0x4d, 0xc1, 0x01, 0xd2, 0x7d, 0x47, 0x00, 0x17, 0x89, 0xae, 0x49, 0x5d, 0x18, - 0x4a, 0x87, 0x9c, 0x74, 0x30, 0x57, 0x76, 0x90, 0x95, 0xca, 0x66, 0x21, 0x15, 0x8f, 0xd1, 0x6e, - 0x74, 0xf6, 0x92, 0x50, 0xc7, 0x27, 0x63, 0x70, 0x95, 0x28, 0xb6, 0xfd, 0xef, 0x1f, 0x6c, 0x97, - 0xa3, 0xf1, 0x77, 0x0d, 0x55, 0xda, 0x3e, 0xeb, 0x7c, 0x79, 0x0d, 0xc4, 0xeb, 0x8a, 0x0f, 0x4c, - 0x09, 0x1d, 0x41, 0x18, 0x7d, 0xdf, 0x87, 0x3e, 0xc8, 0x04, 0x79, 0x99, 0xe0, 0x69, 0x5a, 0x82, - 0xfa, 0x52, 0x92, 0x4a, 0xb4, 0x82, 0x1f, 0xfe, 0x8c, 0xae, 0xc5, 0xfd, 0xfb, 0x62, 0x00, 0x54, - 0x70, 0x7d, 0x5d, 0x26, 0xd8, 0x4b, 0x4b, 0x70, 0x30, 0x5f, 0xa5, 0x0c, 0x2f, 0xa0, 0xf0, 0x73, - 0xb4, 0x1e, 0x77, 0xe1, 0x86, 0xa4, 0xde, 0x49, 0xa3, 0x3e, 0x4b, 0x3a, 0x30, 0xae, 0xc4, 0x04, - 0x5d, 0x0f, 0xc1, 0x23, 0x5c, 0x40, 0x08, 0x6e, 0x03, 0x28, 0xeb, 0x71, 0xbd, 0x20, 0x69, 0x4f, - 0x56, 0xec, 0x69, 0xfb, 0x42, 0xb9, 0x72, 0xb8, 0x84, 0xc5, 0x3d, 0xb4, 0xc5, 0xe1, 0x6b, 0x1f, - 0x68, 0x07, 0xc2, 0xe8, 0xd9, 0x0e, 0x1d, 0x12, 0x72, 0x1d, 0x49, 0xbb, 0x5a, 0x6a, 0x5b, 0x5c, - 0xae, 0x55, 0x56, 0x57, 0x62, 0xf1, 0x63, 0xb4, 0x3d, 0xe8, 0xfb, 0x14, 0x42, 0xa7, 0xed, 0x43, - 0xcb, 0x0d, 0x79, 0x6b, 0x00, 0xe1, 0x8c, 0xc8, 0xf5, 0x62, 0x39, 0x5b, 0xdd, 0xb4, 0x6f, 0x9e, - 0x1f, 0x37, 0x42, 0x7e, 0xac, 0x0e, 0x2b, 0x6f, 0xd0, 0x8d, 0x2b, 0xac, 0xf0, 0x0e, 0x2a, 0x24, - 0x36, 0x72, 0x80, 0x14, 0xec, 0xf3, 0x0d, 0x7c, 0x0b, 0xe5, 0xbb, 0x52, 0xab, 0xaf, 0x95, 0xb5, - 0x6a, 0xce, 0x56, 0xab, 0xca, 0x31, 0xda, 0x5e, 0xf0, 0x4c, 0x78, 0x17, 0x21, 0x75, 0xb5, 0x16, - 0x71, 0x63, 0xa2, 0xda, 0x69, 0xba, 0x78, 0x07, 0xe5, 0xdd, 0xe8, 0xef, 0x98, 0x8d, 0x98, 0x42, - 0x3c, 0x85, 0xa2, 0xbd, 0xfa, 0xdb, 0xd3, 0x89, 0xa1, 0x9d, 0x4d, 0x0c, 0xed, 0xf7, 0xc4, 0xd0, - 0xbe, 0x4d, 0x8d, 0xcc, 0xd9, 0xd4, 0xc8, 0xfc, 0x9c, 0x1a, 0x99, 0x4f, 0x8f, 0x3c, 0x22, 0xba, - 0xfd, 0xb6, 0xd9, 0x61, 0xbd, 0x45, 0xb3, 0x78, 0x50, 0xb3, 0x86, 0xc9, 0xc0, 0x14, 0xa3, 0x00, - 0x78, 0x3b, 0x2f, 0x67, 0x66, 0xed, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc5, 0xf9, 0xb9, 0x53, - 0x7e, 0x06, 0x00, 0x00, + // 589 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0xcf, 0x6e, 0xd3, 0x4c, + 0x14, 0xc5, 0xe3, 0xb6, 0x5f, 0xda, 0x4c, 0xbe, 0x22, 0x34, 0x2d, 0x60, 0x45, 0xd4, 0x44, 0x41, + 0x82, 0x20, 0xa8, 0x2d, 0x25, 0x48, 0xec, 0x90, 0x08, 0xe1, 0x4f, 0x44, 0x05, 0xc1, 0x05, 0x16, + 0xb0, 0x88, 0x9c, 0xf8, 0xd6, 0x19, 0xe1, 0x78, 0x8c, 0x67, 0x12, 0x25, 0x79, 0x0a, 0x16, 0xbc, + 0x08, 0x6f, 0xd1, 0x65, 0x97, 0xac, 0x10, 0x4a, 0x5e, 0x04, 0x79, 0x3c, 0x36, 0xa1, 0x6d, 0x32, + 0x91, 0x58, 0x39, 0xe3, 0x39, 0xf7, 0x77, 0x8e, 0x6f, 0xae, 0x2e, 0x7a, 0xe0, 0x4e, 0x06, 0x10, + 0x30, 0x42, 0x83, 0xf1, 0x64, 0x6a, 0x65, 0x07, 0x2b, 0xa2, 0xbe, 0xef, 0x84, 0xa1, 0xe5, 0x41, + 0x00, 0x8c, 0x30, 0x33, 0x8c, 0x28, 0xa7, 0xd8, 0x58, 0x54, 0x9b, 0xd9, 0xc1, 0x94, 0xea, 0xd2, + 0xbe, 0x47, 0x3d, 0x2a, 0xa4, 0x56, 0xfc, 0x2b, 0xa9, 0x2a, 0xdd, 0x57, 0x78, 0x84, 0x4e, 0xe4, + 0x0c, 0xa4, 0x45, 0x49, 0x15, 0x48, 0x3e, 0xa5, 0xda, 0x52, 0xa8, 0x19, 0x77, 0x38, 0x74, 0x48, + 0x70, 0x92, 0x66, 0x39, 0x54, 0x14, 0xf8, 0x64, 0x14, 0x7f, 0x71, 0x9a, 0xa6, 0xaa, 0x90, 0x67, + 0x49, 0x2a, 0xdf, 0x77, 0xd0, 0xff, 0x2f, 0x92, 0x66, 0x1d, 0xc7, 0xa6, 0xb8, 0x89, 0xf2, 0xc9, + 0x87, 0xe9, 0x5a, 0x59, 0xab, 0x16, 0x6b, 0x77, 0xcc, 0xd5, 0xcd, 0x33, 0xdb, 0x42, 0xdd, 0xd8, + 0x3a, 0xfd, 0x79, 0x2b, 0x67, 0xcb, 0x5a, 0xfc, 0x06, 0x15, 0xe5, 0xfd, 0x11, 0x61, 0x5c, 0xdf, + 0x28, 0x6f, 0x56, 0x8b, 0xb5, 0xbb, 0x2a, 0x94, 0x9d, 0x3c, 0x25, 0x6b, 0x91, 0x80, 0xdf, 0xa3, + 0x5d, 0xd1, 0x94, 0x56, 0x70, 0x42, 0x05, 0x72, 0x53, 0x20, 0xef, 0xa9, 0x90, 0xc7, 0x69, 0x91, + 0x84, 0xfe, 0x4d, 0xc1, 0x21, 0xd2, 0x7d, 0x87, 0x03, 0xe3, 0x99, 0xae, 0x15, 0xb8, 0x30, 0x16, + 0x0e, 0x5b, 0xc2, 0xc1, 0x5c, 0xdb, 0x41, 0x54, 0x4a, 0x9b, 0xa5, 0x54, 0x3c, 0x45, 0x07, 0xc9, + 0xdd, 0x73, 0x12, 0x38, 0x3e, 0x99, 0x82, 0x2b, 0x45, 0xa9, 0xed, 0x7f, 0xff, 0x60, 0xbb, 0x1a, + 0x8d, 0xbf, 0x69, 0xa8, 0xd2, 0xf5, 0x69, 0xef, 0xf3, 0x4b, 0x20, 0x5e, 0x9f, 0xbf, 0xa3, 0x52, + 0xe8, 0x70, 0x42, 0x83, 0xb7, 0x43, 0x18, 0x82, 0x48, 0x90, 0x17, 0x09, 0x1e, 0xab, 0x12, 0x34, + 0x56, 0x92, 0x64, 0xa2, 0x35, 0xfc, 0xf0, 0x27, 0x74, 0x25, 0x9d, 0xdf, 0x67, 0x23, 0x08, 0x38, + 0xd3, 0xb7, 0x45, 0x82, 0x43, 0x55, 0x82, 0xa3, 0xc5, 0x2a, 0x69, 0x78, 0x0e, 0x85, 0x9f, 0xa2, + 0xed, 0x74, 0x0a, 0x77, 0x04, 0xf5, 0xb6, 0x8a, 0xfa, 0x24, 0x9b, 0xc0, 0xb4, 0x12, 0x13, 0x74, + 0x35, 0x02, 0x8f, 0x30, 0x0e, 0x11, 0xb8, 0x4d, 0x08, 0xe8, 0x80, 0xe9, 0x05, 0x41, 0x7b, 0xb4, + 0xe6, 0x4c, 0xdb, 0xe7, 0xca, 0xa5, 0xc3, 0x05, 0x2c, 0x1e, 0xa0, 0x7d, 0x06, 0x5f, 0x86, 0x10, + 0xf4, 0x20, 0x4a, 0xda, 0xd6, 0x76, 0x48, 0xc4, 0x74, 0x24, 0xec, 0xea, 0xca, 0xb1, 0xb8, 0x58, + 0x2b, 0xad, 0x2e, 0xc5, 0xe2, 0x1a, 0xba, 0x46, 0xbb, 0x8c, 0xfa, 0xc0, 0xa1, 0xe3, 0x46, 0xac, + 0x33, 0x82, 0x28, 0xe6, 0x31, 0xbd, 0x58, 0xde, 0xac, 0xee, 0xda, 0x7b, 0xe9, 0x65, 0x33, 0x62, + 0x1f, 0xe4, 0x55, 0xe5, 0x15, 0xda, 0xbb, 0xc4, 0x06, 0xdf, 0x44, 0x85, 0xcc, 0x42, 0x2c, 0x8f, + 0x82, 0xfd, 0xe7, 0x05, 0xbe, 0x8e, 0xf2, 0x7d, 0xa1, 0xd5, 0x37, 0xca, 0x5a, 0x75, 0xcb, 0x96, + 0xa7, 0x4a, 0x1b, 0xdd, 0x58, 0xd2, 0x22, 0x7c, 0x80, 0x90, 0xfc, 0xac, 0x0e, 0x71, 0x53, 0xa2, + 0x7c, 0xd3, 0x72, 0x63, 0xa2, 0x9b, 0xfc, 0x15, 0xf1, 0x7a, 0x29, 0xd8, 0xf2, 0xd4, 0x78, 0x7d, + 0x3a, 0x33, 0xb4, 0xb3, 0x99, 0xa1, 0xfd, 0x9a, 0x19, 0xda, 0xd7, 0xb9, 0x91, 0x3b, 0x9b, 0x1b, + 0xb9, 0x1f, 0x73, 0x23, 0xf7, 0xf1, 0xa1, 0x47, 0x78, 0x7f, 0xd8, 0x35, 0x7b, 0x74, 0xb0, 0x6c, + 0x03, 0x8f, 0xea, 0xd6, 0x38, 0x5b, 0x93, 0x7c, 0x12, 0x02, 0xeb, 0xe6, 0xc5, 0xa6, 0xac, 0xff, + 0x0e, 0x00, 0x00, 0xff, 0xff, 0xfd, 0x21, 0x55, 0x13, 0x74, 0x06, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -326,10 +325,10 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.VulnerableDrsVersions) > 0 { - dAtA2 := make([]byte, len(m.VulnerableDrsVersions)*10) + if len(m.ObsoleteDrsVersions) > 0 { + dAtA2 := make([]byte, len(m.ObsoleteDrsVersions)*10) var j1 int - for _, num := range m.VulnerableDrsVersions { + for _, num := range m.ObsoleteDrsVersions { for num >= 1<<7 { dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 @@ -630,9 +629,9 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } - if len(m.VulnerableDrsVersions) > 0 { + if len(m.ObsoleteDrsVersions) > 0 { l = 0 - for _, e := range m.VulnerableDrsVersions { + for _, e := range m.ObsoleteDrsVersions { l += sovGenesis(uint64(e)) } n += 1 + sovGenesis(uint64(l)) + l @@ -1066,7 +1065,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { break } } - m.VulnerableDrsVersions = append(m.VulnerableDrsVersions, v) + m.ObsoleteDrsVersions = append(m.ObsoleteDrsVersions, v) } else if wireType == 2 { var packedLen int for shift := uint(0); ; shift += 7 { @@ -1101,8 +1100,8 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } } elementCount = count - if elementCount != 0 && len(m.VulnerableDrsVersions) == 0 { - m.VulnerableDrsVersions = make([]uint32, 0, elementCount) + if elementCount != 0 && len(m.ObsoleteDrsVersions) == 0 { + m.ObsoleteDrsVersions = make([]uint32, 0, elementCount) } for iNdEx < postIndex { var v uint32 @@ -1120,10 +1119,10 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { break } } - m.VulnerableDrsVersions = append(m.VulnerableDrsVersions, v) + m.ObsoleteDrsVersions = append(m.ObsoleteDrsVersions, v) } } else { - return fmt.Errorf("proto: wrong wireType = %d for field VulnerableDrsVersions", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ObsoleteDrsVersions", wireType) } default: iNdEx = preIndex diff --git a/x/rollapp/types/genesis_test.go b/x/rollapp/types/genesis_test.go index 6df041e3d..1ad22b0cb 100644 --- a/x/rollapp/types/genesis_test.go +++ b/x/rollapp/types/genesis_test.go @@ -61,7 +61,7 @@ func TestGenesisState_Validate(t *testing.T) { CreationHeight: 1, }, }, - VulnerableDrsVersions: []uint32{1, 2}, + ObsoleteDrsVersions: []uint32{1, 2}, }, valid: true, }, @@ -143,14 +143,14 @@ func TestGenesisState_Validate(t *testing.T) { valid: false, }, { - desc: "duplicated VulnerableDrsVersions", + desc: "duplicated ObsoleteDrsVersions", genState: &types.GenesisState{ Params: types.DefaultParams(), RollappList: []types.Rollapp{}, StateInfoList: []types.StateInfo{}, LatestStateInfoIndexList: []types.StateInfoIndex{}, BlockHeightToFinalizationQueueList: []types.BlockHeightToFinalizationQueue{}, - VulnerableDrsVersions: []uint32{1, 1}, + ObsoleteDrsVersions: []uint32{1, 1}, }, valid: false, }, diff --git a/x/rollapp/types/hooks.go b/x/rollapp/types/hooks.go index f9eafb2b1..8893b5fd3 100644 --- a/x/rollapp/types/hooks.go +++ b/x/rollapp/types/hooks.go @@ -14,9 +14,10 @@ type RollappHooks interface { BeforeUpdateState(ctx sdk.Context, seqAddr, rollappId string, lastStateUpdateBySequencer bool) error // Must be called when a rollapp's state changes AfterUpdateState(ctx sdk.Context, rollappID string, stateInfo *StateInfo) error // Must be called when a rollapp's state changes AfterStateFinalized(ctx sdk.Context, rollappID string, stateInfo *StateInfo) error // Must be called when a rollapp's state changes - FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error RollappCreated(ctx sdk.Context, rollappID, alias string, creator sdk.AccAddress) error AfterTransfersEnabled(ctx sdk.Context, rollappID, rollappIBCDenom string) error + + OnHardFork(ctx sdk.Context, rollappID string, height uint64) error } var _ RollappHooks = MultiRollappHooks{} @@ -59,9 +60,9 @@ func (h MultiRollappHooks) AfterStateFinalized(ctx sdk.Context, rollappID string return nil } -func (h MultiRollappHooks) FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { +func (h MultiRollappHooks) OnHardFork(ctx sdk.Context, rollappID string, newRevisionHeight uint64) error { for i := range h { - err := h[i].FraudSubmitted(ctx, rollappID, height, seqAddr) + err := h[i].OnHardFork(ctx, rollappID, newRevisionHeight) if err != nil { return err } @@ -102,7 +103,7 @@ func (StubRollappCreatedHooks) BeforeUpdateState(sdk.Context, string, string, bo func (StubRollappCreatedHooks) AfterUpdateState(sdk.Context, string, *StateInfo) error { return nil } -func (StubRollappCreatedHooks) FraudSubmitted(sdk.Context, string, uint64, string) error { return nil } +func (StubRollappCreatedHooks) OnHardFork(sdk.Context, string, uint64) error { return nil } func (StubRollappCreatedHooks) AfterStateFinalized(sdk.Context, string, *StateInfo) error { return nil } diff --git a/x/rollapp/types/keys.go b/x/rollapp/types/keys.go index 4a3e11639..271b71e3b 100644 --- a/x/rollapp/types/keys.go +++ b/x/rollapp/types/keys.go @@ -24,7 +24,7 @@ func KeyPrefix(p string) []byte { } const ( - VulnerableDRSVersionsKeyPrefix = "vulnerableDRSVersions/value/" + ObsoleteDRSVersionsKeyPrefix = "obsoleteDRSVersions/value/" // KeyRegisteredDenomPrefix is the prefix to retrieve all RegisteredDenom KeyRegisteredDenomPrefix = "RegisteredDenom/value/" ) diff --git a/x/rollapp/types/message_fraud_proposal.go b/x/rollapp/types/message_fraud_proposal.go new file mode 100644 index 000000000..906ae9587 --- /dev/null +++ b/x/rollapp/types/message_fraud_proposal.go @@ -0,0 +1,50 @@ +package types + +import ( + "errors" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" +) + +var _ sdk.Msg = &MsgRollappFraudProposal{} + +// ValidateBasic performs basic validation for the MsgRollappFraudProposal. +func (m *MsgRollappFraudProposal) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Authority) + if err != nil { + return errorsmod.Wrapf( + errors.Join(gerrc.ErrInvalidArgument, err), + "authority is not a valid bech32 address: %s", m.Authority, + ) + } + if m.Rewardee != "" { + if _, err := sdk.AccAddressFromBech32(m.Rewardee); err != nil { + return errorsmod.Wrapf( + errors.Join(gerrc.ErrInvalidArgument, err), + "rewardee is not a valid bech32 address: %s", m.Authority, + ) + } + } + + return nil +} + +// Returns acc address if rewardee field is not empty +func (m *MsgRollappFraudProposal) MustRewardee() *sdk.AccAddress { + if m.Rewardee == "" { + return nil + } + rewardee, _ := sdk.AccAddressFromBech32(m.Rewardee) + return &rewardee +} + +// GetSigners returns the required signers for the MsgRollappFraudProposal. +func (m *MsgRollappFraudProposal) GetSigners() []sdk.AccAddress { + authority, err := sdk.AccAddressFromBech32(m.Authority) + if err != nil { + panic(err) + } + return []sdk.AccAddress{authority} +} diff --git a/x/rollapp/types/message_mark_vunerable_rollapps.go b/x/rollapp/types/message_mark_obsolete_rollapps.go similarity index 59% rename from x/rollapp/types/message_mark_vunerable_rollapps.go rename to x/rollapp/types/message_mark_obsolete_rollapps.go index 2739e808d..f314b6358 100644 --- a/x/rollapp/types/message_mark_vunerable_rollapps.go +++ b/x/rollapp/types/message_mark_obsolete_rollapps.go @@ -10,15 +10,15 @@ import ( ) const ( - TypeMsgMarkVulnerableRollapps = "mark_vulnerable_rollapps" + TypeMsgMarkObsoleteRollapps = "mark_obsolete_rollapps" ) var ( - _ sdk.Msg = new(MsgMarkVulnerableRollapps) - _ legacytx.LegacyMsg = new(MsgMarkVulnerableRollapps) + _ sdk.Msg = new(MsgMarkObsoleteRollapps) + _ legacytx.LegacyMsg = new(MsgMarkObsoleteRollapps) ) -func (m MsgMarkVulnerableRollapps) ValidateBasic() error { +func (m MsgMarkObsoleteRollapps) ValidateBasic() error { _, err := sdk.AccAddressFromBech32(m.Authority) if err != nil { return errors.Join(gerrc.ErrInvalidArgument, errorsmod.Wrap(err, "authority must be a valid bech32 address")) @@ -31,20 +31,20 @@ func (m MsgMarkVulnerableRollapps) ValidateBasic() error { return nil } -func (m MsgMarkVulnerableRollapps) GetSigners() []sdk.AccAddress { +func (m MsgMarkObsoleteRollapps) GetSigners() []sdk.AccAddress { signer, _ := sdk.AccAddressFromBech32(m.Authority) return []sdk.AccAddress{signer} } -func (m MsgMarkVulnerableRollapps) Type() string { - return TypeMsgMarkVulnerableRollapps +func (m MsgMarkObsoleteRollapps) Type() string { + return TypeMsgMarkObsoleteRollapps } -func (m MsgMarkVulnerableRollapps) Route() string { +func (m MsgMarkObsoleteRollapps) Route() string { return RouterKey } -func (m MsgMarkVulnerableRollapps) GetSignBytes() []byte { +func (m MsgMarkObsoleteRollapps) GetSignBytes() []byte { bz := ModuleCdc.MustMarshalJSON(&m) return sdk.MustSortJSON(bz) } diff --git a/x/rollapp/types/proposal.pb.go b/x/rollapp/types/proposal.pb.go deleted file mode 100644 index 6efdccbe9..000000000 --- a/x/rollapp/types/proposal.pb.go +++ /dev/null @@ -1,567 +0,0 @@ -// Code generated by protoc-gen-gogo. DO NOT EDIT. -// source: dymensionxyz/dymension/rollapp/proposal.proto - -package types - -import ( - fmt "fmt" - _ "github.com/cosmos/gogoproto/gogoproto" - proto "github.com/cosmos/gogoproto/proto" - io "io" - math "math" - math_bits "math/bits" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package - -type SubmitFraudProposal struct { - Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - // The rollapp id - RollappId string `protobuf:"bytes,3,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` - // The ibc client id of the rollapp - IbcClientId string `protobuf:"bytes,4,opt,name=ibc_client_id,json=ibcClientId,proto3" json:"ibc_client_id,omitempty"` - // The height of the fraudelent block - FraudelentHeight uint64 `protobuf:"varint,5,opt,name=fraudelent_height,json=fraudelentHeight,proto3" json:"fraudelent_height,omitempty"` - // The address of the fraudelent sequencer - FraudelentSequencerAddress string `protobuf:"bytes,6,opt,name=fraudelent_sequencer_address,json=fraudelentSequencerAddress,proto3" json:"fraudelent_sequencer_address,omitempty"` -} - -func (m *SubmitFraudProposal) Reset() { *m = SubmitFraudProposal{} } -func (*SubmitFraudProposal) ProtoMessage() {} -func (*SubmitFraudProposal) Descriptor() ([]byte, []int) { - return fileDescriptor_23c44e927b26bbf5, []int{0} -} -func (m *SubmitFraudProposal) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *SubmitFraudProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_SubmitFraudProposal.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *SubmitFraudProposal) XXX_Merge(src proto.Message) { - xxx_messageInfo_SubmitFraudProposal.Merge(m, src) -} -func (m *SubmitFraudProposal) XXX_Size() int { - return m.Size() -} -func (m *SubmitFraudProposal) XXX_DiscardUnknown() { - xxx_messageInfo_SubmitFraudProposal.DiscardUnknown(m) -} - -var xxx_messageInfo_SubmitFraudProposal proto.InternalMessageInfo - -func init() { - proto.RegisterType((*SubmitFraudProposal)(nil), "dymensionxyz.dymension.rollapp.SubmitFraudProposal") -} - -func init() { - proto.RegisterFile("dymensionxyz/dymension/rollapp/proposal.proto", fileDescriptor_23c44e927b26bbf5) -} - -var fileDescriptor_23c44e927b26bbf5 = []byte{ - // 330 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0xbf, 0x4e, 0xeb, 0x30, - 0x18, 0xc5, 0xe3, 0xde, 0xb6, 0x52, 0x7d, 0x41, 0x02, 0xd3, 0x21, 0xaa, 0xc0, 0xad, 0x3a, 0x55, - 0x42, 0x24, 0x43, 0x99, 0x98, 0xf8, 0x23, 0x21, 0xba, 0x20, 0xd4, 0x6e, 0x2c, 0x55, 0x12, 0x9b, - 0xd4, 0x92, 0x1b, 0x1b, 0xdb, 0x41, 0x2d, 0x4f, 0xc0, 0x82, 0xc4, 0xc8, 0xd8, 0xc7, 0x61, 0xec, - 0xc8, 0x88, 0xda, 0x85, 0xc7, 0x40, 0x71, 0x42, 0x9b, 0x85, 0xcd, 0xe7, 0x7c, 0x3f, 0x1f, 0x5b, - 0xdf, 0x81, 0x27, 0x64, 0x3e, 0xa5, 0x89, 0x66, 0x22, 0x99, 0xcd, 0x9f, 0xfd, 0x8d, 0xf0, 0x95, - 0xe0, 0x3c, 0x90, 0xd2, 0x97, 0x4a, 0x48, 0xa1, 0x03, 0xee, 0x49, 0x25, 0x8c, 0x40, 0xb8, 0x8c, - 0x7b, 0x1b, 0xe1, 0x15, 0x78, 0xab, 0x19, 0x8b, 0x58, 0x58, 0xd4, 0xcf, 0x4e, 0xf9, 0xad, 0xee, - 0x6b, 0x05, 0x1e, 0x8c, 0xd2, 0x70, 0xca, 0xcc, 0xb5, 0x0a, 0x52, 0x72, 0x57, 0x64, 0xa2, 0x26, - 0xac, 0x19, 0x66, 0x38, 0x75, 0x41, 0x07, 0xf4, 0x1a, 0xc3, 0x5c, 0xa0, 0x0e, 0xfc, 0x4f, 0xa8, - 0x8e, 0x14, 0x93, 0x86, 0x89, 0xc4, 0xad, 0xd8, 0x59, 0xd9, 0x42, 0x47, 0x10, 0x16, 0x0f, 0x8e, - 0x19, 0x71, 0xff, 0x59, 0xa0, 0x51, 0x38, 0x03, 0x82, 0xba, 0x70, 0x97, 0x85, 0xd1, 0x38, 0xe2, - 0x8c, 0x26, 0x26, 0x23, 0xaa, 0x79, 0x04, 0x0b, 0xa3, 0x2b, 0xeb, 0x0d, 0x08, 0x3a, 0x86, 0xfb, - 0x0f, 0xd9, 0x5f, 0x28, 0xcf, 0x98, 0x09, 0x65, 0xf1, 0xc4, 0xb8, 0xb5, 0x0e, 0xe8, 0x55, 0x87, - 0x7b, 0xdb, 0xc1, 0x8d, 0xf5, 0xd1, 0x39, 0x3c, 0x2c, 0xc1, 0x9a, 0x3e, 0xa6, 0x34, 0x89, 0xa8, - 0x1a, 0x07, 0x84, 0x28, 0xaa, 0xb5, 0x5b, 0xb7, 0xf9, 0xad, 0x2d, 0x33, 0xfa, 0x45, 0x2e, 0x72, - 0xe2, 0x6c, 0xe7, 0x65, 0xd1, 0x76, 0xde, 0x17, 0x6d, 0xe7, 0x7b, 0xd1, 0x06, 0x97, 0xb7, 0x1f, - 0x2b, 0x0c, 0x96, 0x2b, 0x0c, 0xbe, 0x56, 0x18, 0xbc, 0xad, 0xb1, 0xb3, 0x5c, 0x63, 0xe7, 0x73, - 0x8d, 0x9d, 0xfb, 0xd3, 0x98, 0x99, 0x49, 0x1a, 0x7a, 0x91, 0x98, 0xfa, 0x7f, 0x34, 0xf3, 0xd4, - 0xf7, 0x67, 0x9b, 0x7a, 0xcc, 0x5c, 0x52, 0x1d, 0xd6, 0xed, 0x9a, 0xfb, 0x3f, 0x01, 0x00, 0x00, - 0xff, 0xff, 0x04, 0x60, 0x11, 0xe4, 0xcd, 0x01, 0x00, 0x00, -} - -func (this *SubmitFraudProposal) Equal(that interface{}) bool { - if that == nil { - return this == nil - } - - that1, ok := that.(*SubmitFraudProposal) - if !ok { - that2, ok := that.(SubmitFraudProposal) - if ok { - that1 = &that2 - } else { - return false - } - } - if that1 == nil { - return this == nil - } else if this == nil { - return false - } - if this.Title != that1.Title { - return false - } - if this.Description != that1.Description { - return false - } - if this.RollappId != that1.RollappId { - return false - } - if this.IbcClientId != that1.IbcClientId { - return false - } - if this.FraudelentHeight != that1.FraudelentHeight { - return false - } - if this.FraudelentSequencerAddress != that1.FraudelentSequencerAddress { - return false - } - return true -} -func (m *SubmitFraudProposal) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *SubmitFraudProposal) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *SubmitFraudProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.FraudelentSequencerAddress) > 0 { - i -= len(m.FraudelentSequencerAddress) - copy(dAtA[i:], m.FraudelentSequencerAddress) - i = encodeVarintProposal(dAtA, i, uint64(len(m.FraudelentSequencerAddress))) - i-- - dAtA[i] = 0x32 - } - if m.FraudelentHeight != 0 { - i = encodeVarintProposal(dAtA, i, uint64(m.FraudelentHeight)) - i-- - dAtA[i] = 0x28 - } - if len(m.IbcClientId) > 0 { - i -= len(m.IbcClientId) - copy(dAtA[i:], m.IbcClientId) - i = encodeVarintProposal(dAtA, i, uint64(len(m.IbcClientId))) - i-- - dAtA[i] = 0x22 - } - if len(m.RollappId) > 0 { - i -= len(m.RollappId) - copy(dAtA[i:], m.RollappId) - i = encodeVarintProposal(dAtA, i, uint64(len(m.RollappId))) - i-- - dAtA[i] = 0x1a - } - if len(m.Description) > 0 { - i -= len(m.Description) - copy(dAtA[i:], m.Description) - i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) - i-- - dAtA[i] = 0x12 - } - if len(m.Title) > 0 { - i -= len(m.Title) - copy(dAtA[i:], m.Title) - i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func encodeVarintProposal(dAtA []byte, offset int, v uint64) int { - offset -= sovProposal(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ - } - dAtA[offset] = uint8(v) - return base -} -func (m *SubmitFraudProposal) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Title) - if l > 0 { - n += 1 + l + sovProposal(uint64(l)) - } - l = len(m.Description) - if l > 0 { - n += 1 + l + sovProposal(uint64(l)) - } - l = len(m.RollappId) - if l > 0 { - n += 1 + l + sovProposal(uint64(l)) - } - l = len(m.IbcClientId) - if l > 0 { - n += 1 + l + sovProposal(uint64(l)) - } - if m.FraudelentHeight != 0 { - n += 1 + sovProposal(uint64(m.FraudelentHeight)) - } - l = len(m.FraudelentSequencerAddress) - if l > 0 { - n += 1 + l + sovProposal(uint64(l)) - } - return n -} - -func sovProposal(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozProposal(x uint64) (n int) { - return sovProposal(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *SubmitFraudProposal) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProposal - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: SubmitFraudProposal: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: SubmitFraudProposal: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProposal - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthProposal - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthProposal - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Title = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProposal - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthProposal - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthProposal - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Description = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RollappId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProposal - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthProposal - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthProposal - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.RollappId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IbcClientId", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProposal - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthProposal - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthProposal - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.IbcClientId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field FraudelentHeight", wireType) - } - m.FraudelentHeight = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProposal - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.FraudelentHeight |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 6: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field FraudelentSequencerAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowProposal - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthProposal - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthProposal - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.FraudelentSequencerAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipProposal(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthProposal - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func skipProposal(dAtA []byte) (n int, err error) { - l := len(dAtA) - iNdEx := 0 - depth := 0 - for iNdEx < l { - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowProposal - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - wireType := int(wire & 0x7) - switch wireType { - case 0: - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowProposal - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - iNdEx++ - if dAtA[iNdEx-1] < 0x80 { - break - } - } - case 1: - iNdEx += 8 - case 2: - var length int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowProposal - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - length |= (int(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - if length < 0 { - return 0, ErrInvalidLengthProposal - } - iNdEx += length - case 3: - depth++ - case 4: - if depth == 0 { - return 0, ErrUnexpectedEndOfGroupProposal - } - depth-- - case 5: - iNdEx += 4 - default: - return 0, fmt.Errorf("proto: illegal wireType %d", wireType) - } - if iNdEx < 0 { - return 0, ErrInvalidLengthProposal - } - if depth == 0 { - return iNdEx, nil - } - } - return 0, io.ErrUnexpectedEOF -} - -var ( - ErrInvalidLengthProposal = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowProposal = fmt.Errorf("proto: integer overflow") - ErrUnexpectedEndOfGroupProposal = fmt.Errorf("proto: unexpected end of group") -) diff --git a/x/rollapp/types/proposal_submit_fraud.go b/x/rollapp/types/proposal_submit_fraud.go deleted file mode 100644 index 35cfae5f9..000000000 --- a/x/rollapp/types/proposal_submit_fraud.go +++ /dev/null @@ -1,74 +0,0 @@ -package types - -import ( - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" -) - -const ( - // ProposalTypeSubmitFraud defines the type for a SubmitFraudProposal - ProposalTypeSubmitFraud = "SubmitFraud" -) - -// Assert SubmitFraudProposal implements govtypes.Content at compile-time -var _ govtypes.Content = &SubmitFraudProposal{} - -func init() { - govtypes.RegisterProposalType(ProposalTypeSubmitFraud) -} - -// NewSubmitFraudProposal creates a new submit fraud proposal. -// -//nolint:interfacer -func NewSubmitFraudProposal(title, description, rollappId string, height uint64, seqaddr, clientId string) *SubmitFraudProposal { - return &SubmitFraudProposal{ - Title: title, - Description: description, - RollappId: rollappId, - IbcClientId: clientId, - FraudelentHeight: height, - FraudelentSequencerAddress: seqaddr, - } -} - -// GetTitle returns the title of a submit fraud proposal. -func (sfp *SubmitFraudProposal) GetTitle() string { return sfp.Title } - -// GetDescription returns the description of a submit fraud proposal. -func (sfp *SubmitFraudProposal) GetDescription() string { return sfp.Description } - -// ProposalRoute returns the routing key of a submit fraud proposal. -func (sfp *SubmitFraudProposal) ProposalRoute() string { return RouterKey } - -// ProposalType returns the type of a submit fraud proposal. -func (sfp *SubmitFraudProposal) ProposalType() string { return ProposalTypeSubmitFraud } - -// ValidateBasic runs basic stateless validity checks -func (sfp *SubmitFraudProposal) ValidateBasic() error { - err := govtypes.ValidateAbstract(sfp) - if err != nil { - return err - } - - if sfp.RollappId == "" { - return ErrInvalidRollappID - } - - if sfp.IbcClientId == "" { - return ErrInvalidClientState - } - - if sfp.FraudelentHeight == 0 { - return ErrInvalidHeight - } - - if sfp.FraudelentSequencerAddress == "" { - return ErrWrongProposerAddr - } - - return nil -} - -// String implements the Stringer interface. -func (sfp SubmitFraudProposal) String() string { - return sfp.Description -} diff --git a/x/rollapp/types/rollapp.go b/x/rollapp/types/rollapp.go index c9a7ccffa..6b8bbc217 100644 --- a/x/rollapp/types/rollapp.go +++ b/x/rollapp/types/rollapp.go @@ -46,6 +46,8 @@ func NewRollapp( GenesisState: RollappGenesisState{ TransfersEnabled: transfersEnabled, }, + RevisionNumber: 0, + RevisionStartHeight: 0, } } @@ -99,10 +101,6 @@ func (r Rollapp) GenesisInfoFieldsAreSet() bool { return r.GenesisInfo.AllSet() } -func (r Rollapp) IsVulnerable() bool { - return r.Frozen -} - func validateInitialSequencer(initialSequencer string) error { if initialSequencer == "" || initialSequencer == "*" { return nil diff --git a/x/rollapp/types/rollapp.pb.go b/x/rollapp/types/rollapp.pb.go index df1cb0d12..663aae685 100644 --- a/x/rollapp/types/rollapp.pb.go +++ b/x/rollapp/types/rollapp.pb.go @@ -123,8 +123,6 @@ type Rollapp struct { GenesisState RollappGenesisState `protobuf:"bytes,7,opt,name=genesis_state,json=genesisState,proto3" json:"genesis_state"` // channel_id will be set to the canonical IBC channel of the rollapp. ChannelId string `protobuf:"bytes,8,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` - // frozen is a boolean that indicates if the rollapp is frozen. - Frozen bool `protobuf:"varint,9,opt,name=frozen,proto3" json:"frozen,omitempty"` // metadata is the rollapp metadata Metadata *RollappMetadata `protobuf:"bytes,11,opt,name=metadata,proto3" json:"metadata,omitempty"` // genesis_info keeps immutable rollapp fields @@ -149,6 +147,10 @@ type Rollapp struct { // The LastStateUpdateHeight HUB height when the last state update was // received LastStateUpdateHeight int64 `protobuf:"varint,18,opt,name=last_state_update_height,json=lastStateUpdateHeight,proto3" json:"last_state_update_height,omitempty"` + // The revision number of the rollapp. starts always with 0 revision + RevisionNumber uint64 `protobuf:"varint,19,opt,name=revision_number,json=revisionNumber,proto3" json:"revision_number,omitempty"` + // The first height of the rollapp when the revision started + RevisionStartHeight uint64 `protobuf:"varint,20,opt,name=revision_start_height,json=revisionStartHeight,proto3" json:"revision_start_height,omitempty"` } func (m *Rollapp) Reset() { *m = Rollapp{} } @@ -212,13 +214,6 @@ func (m *Rollapp) GetChannelId() string { return "" } -func (m *Rollapp) GetFrozen() bool { - if m != nil { - return m.Frozen - } - return false -} - func (m *Rollapp) GetMetadata() *RollappMetadata { if m != nil { return m.Metadata @@ -275,6 +270,20 @@ func (m *Rollapp) GetLastStateUpdateHeight() int64 { return 0 } +func (m *Rollapp) GetRevisionNumber() uint64 { + if m != nil { + return m.RevisionNumber + } + return 0 +} + +func (m *Rollapp) GetRevisionStartHeight() uint64 { + if m != nil { + return m.RevisionStartHeight + } + return 0 +} + // Rollapp summary is a compact representation of Rollapp type RollappSummary struct { // The unique identifier of the rollapp chain. @@ -368,53 +377,55 @@ func init() { } var fileDescriptor_d4ef2bec3aea5528 = []byte{ - // 731 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x4f, 0x4f, 0xdb, 0x48, - 0x14, 0x8f, 0x13, 0x93, 0x38, 0x93, 0x00, 0x66, 0x80, 0x5d, 0x6f, 0xb4, 0x84, 0x28, 0xa7, 0x48, - 0xb0, 0xb6, 0xf8, 0x23, 0xed, 0x79, 0x91, 0x58, 0x08, 0x6d, 0x7a, 0x70, 0x80, 0x4a, 0x1c, 0x6a, - 0x39, 0xf1, 0xc4, 0x19, 0xc9, 0x9e, 0x71, 0x3d, 0x93, 0x94, 0xf0, 0x29, 0xf8, 0x58, 0x1c, 0x51, - 0x4f, 0x3d, 0xb5, 0x15, 0x7c, 0x8c, 0x5e, 0x2a, 0x8f, 0xc7, 0x21, 0x2d, 0xd0, 0xa0, 0x9e, 0xc6, - 0xef, 0xfd, 0xde, 0x7b, 0xf3, 0xfb, 0xbd, 0x79, 0xcf, 0x60, 0xdb, 0x9b, 0x84, 0x88, 0x30, 0x4c, - 0xc9, 0xe5, 0xe4, 0xca, 0x9a, 0x1a, 0x56, 0x4c, 0x83, 0xc0, 0x8d, 0xa2, 0xec, 0x34, 0xa3, 0x98, - 0x72, 0x0a, 0xeb, 0xb3, 0xd1, 0xe6, 0xd4, 0x30, 0x65, 0x54, 0x6d, 0xcd, 0xa7, 0x3e, 0x15, 0xa1, - 0x56, 0xf2, 0x95, 0x66, 0xd5, 0x36, 0x7d, 0x4a, 0xfd, 0x00, 0x59, 0xc2, 0xea, 0x8d, 0x06, 0x16, - 0xc7, 0x21, 0x62, 0xdc, 0x0d, 0x65, 0xd9, 0xda, 0x9f, 0x7d, 0xca, 0x42, 0xca, 0xac, 0x90, 0xf9, - 0xd6, 0x78, 0x27, 0x39, 0x24, 0x60, 0xcd, 0x61, 0xc7, 0xb8, 0xcb, 0x91, 0x83, 0xc9, 0x20, 0xbb, - 0xea, 0x9f, 0x39, 0x09, 0x21, 0xe2, 0xae, 0xe7, 0x72, 0x57, 0x86, 0xef, 0xcc, 0x09, 0xf7, 0x11, - 0x41, 0x0c, 0xb3, 0x99, 0x1b, 0x9a, 0xc7, 0x60, 0xd5, 0x4e, 0xd1, 0xa3, 0x14, 0xec, 0x26, 0x1c, - 0xe0, 0x16, 0x58, 0xe1, 0xb1, 0x4b, 0xd8, 0x00, 0xc5, 0xcc, 0x41, 0xc4, 0xed, 0x05, 0xc8, 0x33, - 0xf2, 0x0d, 0xa5, 0xa5, 0xd9, 0xfa, 0x14, 0x38, 0x4c, 0xfd, 0x27, 0xaa, 0xa6, 0xe8, 0xf9, 0xe6, - 0xb7, 0x05, 0x50, 0x92, 0xa5, 0xe0, 0x06, 0x00, 0xf2, 0x4e, 0x07, 0x7b, 0x86, 0xd2, 0x50, 0x5a, - 0x65, 0xbb, 0x2c, 0x3d, 0x6d, 0x0f, 0xae, 0x81, 0x05, 0xfa, 0x81, 0xa0, 0x58, 0x54, 0x2c, 0xdb, - 0xa9, 0x01, 0xdf, 0x81, 0xc5, 0x8c, 0xa0, 0x68, 0x84, 0x51, 0x6a, 0x28, 0xad, 0xca, 0xee, 0x9e, - 0xf9, 0xeb, 0x57, 0x32, 0x9f, 0xe0, 0x7f, 0xa0, 0xde, 0x7c, 0xde, 0xcc, 0xd9, 0x55, 0x7f, 0x56, - 0xd3, 0x06, 0x00, 0xfd, 0xa1, 0x4b, 0x08, 0x0a, 0x12, 0x52, 0x5a, 0x4a, 0x4a, 0x7a, 0xda, 0x1e, - 0xfc, 0x03, 0x14, 0x07, 0x31, 0xbd, 0x42, 0xc4, 0x28, 0x0b, 0x9d, 0xd2, 0x82, 0xaf, 0x80, 0x96, - 0xb5, 0xd9, 0xa8, 0x08, 0x46, 0xd6, 0x0b, 0x19, 0x75, 0x64, 0x9a, 0x3d, 0x2d, 0x00, 0x4f, 0x41, - 0x75, 0xf6, 0x11, 0x8c, 0xaa, 0x28, 0xb8, 0x35, 0xaf, 0xa0, 0xd4, 0xd6, 0x26, 0x03, 0x2a, 0xa5, - 0x55, 0xfc, 0x07, 0x57, 0xf2, 0x5a, 0x98, 0x60, 0x8e, 0xdd, 0xc0, 0x61, 0xe8, 0xfd, 0x08, 0x91, - 0x3e, 0x8a, 0x8d, 0x45, 0x21, 0x50, 0x97, 0x40, 0x37, 0xf3, 0xc3, 0x23, 0x50, 0x1a, 0x87, 0x0e, - 0x9f, 0x44, 0xc8, 0x58, 0x6a, 0x28, 0xad, 0xa5, 0x5d, 0xf3, 0x85, 0x72, 0xcc, 0xf3, 0xce, 0xe9, - 0x24, 0x42, 0x76, 0x71, 0x1c, 0x26, 0x27, 0xac, 0x01, 0x2d, 0x70, 0x47, 0xa4, 0x3f, 0x44, 0x9e, - 0xb1, 0x2c, 0x5a, 0x36, 0xb5, 0xe1, 0x31, 0x58, 0x8e, 0x62, 0xe4, 0xa4, 0xb6, 0x93, 0x2c, 0x88, - 0xa1, 0x0b, 0xa9, 0x35, 0x33, 0xdd, 0x1e, 0x33, 0xdb, 0x1e, 0xf3, 0x34, 0xdb, 0x9e, 0x03, 0xf5, - 0xfa, 0xcb, 0xa6, 0x62, 0x2f, 0x46, 0x31, 0x7a, 0x2d, 0xf2, 0x12, 0x04, 0xee, 0x82, 0xf5, 0x00, - 0x8f, 0x13, 0xb1, 0xcc, 0x41, 0x63, 0x44, 0xb8, 0x33, 0x44, 0xd8, 0x1f, 0x72, 0x63, 0xa5, 0xa1, - 0xb4, 0x0a, 0xf6, 0x6a, 0x06, 0x1e, 0x26, 0xd8, 0xb1, 0x80, 0xe0, 0xbf, 0xc0, 0x08, 0x5c, 0xc6, - 0xd3, 0x31, 0x72, 0x46, 0x91, 0x97, 0x1c, 0x32, 0x0d, 0x8a, 0xb4, 0xf5, 0x04, 0x17, 0x63, 0x71, - 0x26, 0xd0, 0x34, 0xb1, 0xb9, 0x0d, 0x8a, 0xa9, 0x48, 0xb8, 0x0c, 0x2a, 0x67, 0x84, 0x45, 0xa8, - 0x8f, 0x07, 0x18, 0x79, 0x7a, 0x0e, 0x96, 0x40, 0xe1, 0xf0, 0xbc, 0xa3, 0x2b, 0x50, 0x03, 0xea, - 0xdb, 0xff, 0xba, 0x1d, 0x3d, 0x7f, 0xa2, 0x6a, 0x05, 0xbd, 0x74, 0xa2, 0x6a, 0x40, 0xaf, 0x34, - 0x3f, 0xe6, 0xc1, 0x92, 0xec, 0x53, 0x77, 0x14, 0x86, 0x6e, 0x3c, 0x81, 0x7f, 0x83, 0x87, 0x91, - 0x7f, 0xbc, 0x03, 0x17, 0x40, 0x0f, 0x5c, 0x8e, 0x24, 0x8b, 0x36, 0xf1, 0xd0, 0xa5, 0x58, 0x87, - 0xca, 0xfc, 0xf7, 0x90, 0x19, 0x03, 0x2a, 0xb2, 0xec, 0x47, 0x75, 0x60, 0x00, 0xfe, 0x4a, 0x7d, - 0xff, 0x63, 0xe2, 0x06, 0xf8, 0x0a, 0x79, 0x33, 0x97, 0x14, 0x7e, 0xeb, 0x92, 0xe7, 0x0b, 0xc2, - 0x26, 0xa8, 0xa6, 0x60, 0xda, 0x44, 0x43, 0x6d, 0x28, 0x2d, 0xd5, 0xfe, 0xc1, 0x07, 0xf7, 0xc1, - 0xfa, 0x4f, 0x05, 0x64, 0xf0, 0x82, 0x08, 0x7e, 0x1a, 0x3c, 0x78, 0x73, 0x73, 0x57, 0x57, 0x6e, - 0xef, 0xea, 0xca, 0xd7, 0xbb, 0xba, 0x72, 0x7d, 0x5f, 0xcf, 0xdd, 0xde, 0xd7, 0x73, 0x9f, 0xee, - 0xeb, 0xb9, 0x8b, 0x7d, 0x1f, 0xf3, 0xe1, 0xa8, 0x67, 0xf6, 0x69, 0xf8, 0xdc, 0x4f, 0x75, 0xbc, - 0x67, 0x5d, 0x4e, 0xff, 0x7c, 0xc9, 0xb8, 0xb3, 0x5e, 0x51, 0x0c, 0xdd, 0xde, 0xf7, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x6c, 0x74, 0x7e, 0xf2, 0x26, 0x06, 0x00, 0x00, + // 763 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0x41, 0x6f, 0xe2, 0x46, + 0x14, 0xc6, 0xe0, 0x05, 0x33, 0x10, 0xf0, 0x0e, 0x89, 0xea, 0xa2, 0x2e, 0x41, 0x5c, 0x8a, 0xb4, + 0x5b, 0x5b, 0x9b, 0xac, 0xd4, 0x73, 0x23, 0xa5, 0x1b, 0x68, 0xd9, 0x83, 0xc9, 0x6e, 0xa5, 0x3d, + 0xd4, 0x1a, 0xf0, 0x60, 0x46, 0xb2, 0xc7, 0xae, 0x67, 0xa0, 0x61, 0x7f, 0x45, 0x7e, 0x55, 0x95, + 0x63, 0xd4, 0x53, 0x4f, 0x6d, 0x95, 0xfc, 0x91, 0x6a, 0xc6, 0x63, 0x87, 0x36, 0x49, 0x89, 0xf6, + 0x34, 0x7e, 0xef, 0x7b, 0xef, 0x7b, 0xef, 0x7b, 0x33, 0xcf, 0xe0, 0x95, 0xbf, 0x89, 0x30, 0x65, + 0x24, 0xa6, 0x17, 0x9b, 0x4f, 0x4e, 0x61, 0x38, 0x69, 0x1c, 0x86, 0x28, 0x49, 0xf2, 0xd3, 0x4e, + 0xd2, 0x98, 0xc7, 0xb0, 0xb7, 0x1d, 0x6d, 0x17, 0x86, 0xad, 0xa2, 0xba, 0xfb, 0x41, 0x1c, 0xc4, + 0x32, 0xd4, 0x11, 0x5f, 0x59, 0x56, 0xf7, 0x30, 0x88, 0xe3, 0x20, 0xc4, 0x8e, 0xb4, 0x66, 0xab, + 0x85, 0xc3, 0x49, 0x84, 0x19, 0x47, 0x91, 0xa2, 0xed, 0x7e, 0x31, 0x8f, 0x59, 0x14, 0x33, 0x27, + 0x62, 0x81, 0xb3, 0x7e, 0x2d, 0x0e, 0x05, 0x38, 0x3b, 0xba, 0x63, 0x1c, 0x71, 0xec, 0x11, 0xba, + 0xc8, 0x4b, 0x7d, 0xb3, 0x23, 0x21, 0xc2, 0x1c, 0xf9, 0x88, 0x23, 0x15, 0xfe, 0x7a, 0x47, 0x78, + 0x80, 0x29, 0x66, 0x84, 0x6d, 0x55, 0x18, 0x9c, 0x81, 0x8e, 0x9b, 0xa1, 0x6f, 0x33, 0x70, 0x2a, + 0x7a, 0x80, 0x2f, 0xc1, 0x73, 0x9e, 0x22, 0xca, 0x16, 0x38, 0x65, 0x1e, 0xa6, 0x68, 0x16, 0x62, + 0xdf, 0x2a, 0xf7, 0xb5, 0xa1, 0xe1, 0x9a, 0x05, 0x70, 0x9a, 0xf9, 0xc7, 0xba, 0xa1, 0x99, 0xe5, + 0xc1, 0x6f, 0x55, 0x50, 0x53, 0x54, 0xf0, 0x05, 0x00, 0xaa, 0xa6, 0x47, 0x7c, 0x4b, 0xeb, 0x6b, + 0xc3, 0xba, 0x5b, 0x57, 0x9e, 0x91, 0x0f, 0xf7, 0xc1, 0xb3, 0xf8, 0x57, 0x8a, 0x53, 0xc9, 0x58, + 0x77, 0x33, 0x03, 0xfe, 0x0c, 0xf6, 0xf2, 0x06, 0xe5, 0x20, 0xac, 0x5a, 0x5f, 0x1b, 0x36, 0x8e, + 0x8e, 0xed, 0xff, 0xbf, 0x25, 0xfb, 0x81, 0xfe, 0x4f, 0xf4, 0xab, 0x3f, 0x0f, 0x4b, 0x6e, 0x33, + 0xd8, 0xd6, 0xf4, 0x02, 0x80, 0xf9, 0x12, 0x51, 0x8a, 0x43, 0xd1, 0x94, 0x91, 0x35, 0xa5, 0x3c, + 0x23, 0x1f, 0xfe, 0x00, 0x8c, 0x7c, 0x9c, 0x56, 0x43, 0x56, 0x76, 0x9e, 0x58, 0x79, 0xa2, 0xd2, + 0xdc, 0x82, 0x00, 0x9e, 0x83, 0xe6, 0xf6, 0xb0, 0xad, 0xa6, 0x24, 0x7c, 0xb9, 0x8b, 0x50, 0x69, + 0x18, 0xd1, 0x45, 0xac, 0x24, 0x34, 0x82, 0x3b, 0x97, 0xb8, 0x15, 0x42, 0x09, 0x27, 0x28, 0xf4, + 0x18, 0xfe, 0x65, 0x85, 0xe9, 0x1c, 0xa7, 0xd6, 0x9e, 0x14, 0x62, 0x2a, 0x60, 0x9a, 0xfb, 0xe1, + 0x5b, 0x50, 0x5b, 0x47, 0x1e, 0xdf, 0x24, 0xd8, 0x6a, 0xf5, 0xb5, 0x61, 0xeb, 0xc8, 0x7e, 0xa2, + 0x1c, 0xfb, 0xc3, 0xe4, 0x7c, 0x93, 0x60, 0xb7, 0xba, 0x8e, 0xc4, 0x09, 0xbb, 0xc0, 0x08, 0xd1, + 0x8a, 0xce, 0x97, 0xd8, 0xb7, 0xda, 0xf2, 0x09, 0x14, 0x36, 0x3c, 0x03, 0xed, 0x24, 0xc5, 0x5e, + 0x66, 0x7b, 0x62, 0x11, 0x2c, 0x53, 0x4a, 0xed, 0xda, 0xd9, 0x96, 0xd8, 0xf9, 0x96, 0xd8, 0xe7, + 0xf9, 0x96, 0x9c, 0xe8, 0x97, 0x7f, 0x1d, 0x6a, 0xee, 0x5e, 0x92, 0xe2, 0x1f, 0x65, 0x9e, 0x40, + 0xe0, 0x11, 0x38, 0x08, 0xc9, 0x5a, 0x88, 0x65, 0x1e, 0x5e, 0x63, 0xca, 0xbd, 0x25, 0x26, 0xc1, + 0x92, 0x5b, 0xcf, 0xfb, 0xda, 0xb0, 0xe2, 0x76, 0x72, 0xf0, 0x54, 0x60, 0x67, 0x12, 0x82, 0xdf, + 0x02, 0x2b, 0x44, 0x8c, 0x67, 0xcf, 0xc5, 0x5b, 0x25, 0xbe, 0x38, 0x54, 0x1a, 0x94, 0x69, 0x07, + 0x02, 0x97, 0xd7, 0xff, 0x5e, 0xa2, 0x2a, 0xf1, 0x6b, 0xd0, 0x4e, 0xf1, 0x9a, 0x08, 0xf5, 0x1e, + 0x5d, 0x45, 0x33, 0x9c, 0x5a, 0x9d, 0xbe, 0x36, 0xd4, 0xdd, 0x56, 0xee, 0x7e, 0x27, 0xbd, 0xa2, + 0xab, 0x22, 0x90, 0x71, 0x94, 0x16, 0x5d, 0xed, 0xcb, 0xf0, 0x4e, 0x0e, 0x4e, 0x05, 0x96, 0x91, + 0x0f, 0x5e, 0x81, 0x6a, 0x36, 0x41, 0xd8, 0x06, 0x8d, 0xf7, 0x94, 0x25, 0x78, 0x4e, 0x16, 0x04, + 0xfb, 0x66, 0x09, 0xd6, 0x40, 0xe5, 0xf4, 0xc3, 0xc4, 0xd4, 0xa0, 0x01, 0xf4, 0x9f, 0xbe, 0x9b, + 0x4e, 0xcc, 0xf2, 0x58, 0x37, 0x2a, 0x66, 0x6d, 0xac, 0x1b, 0x75, 0x13, 0x8c, 0x75, 0x03, 0x98, + 0x8d, 0xc1, 0xef, 0x65, 0xd0, 0x52, 0x57, 0x31, 0x5d, 0x45, 0x11, 0x4a, 0x37, 0xf0, 0x2b, 0x70, + 0xb7, 0x3d, 0xf7, 0xd7, 0xe9, 0x23, 0x30, 0x43, 0xc4, 0xb1, 0x12, 0x3a, 0xa2, 0x3e, 0xbe, 0x90, + 0x9b, 0xd5, 0xd8, 0x7d, 0xe5, 0x2a, 0x63, 0x11, 0xcb, 0x2c, 0xf7, 0x1e, 0x0f, 0x0c, 0xc1, 0x97, + 0x99, 0xef, 0x7b, 0x42, 0x51, 0x48, 0x3e, 0x61, 0x7f, 0xab, 0x48, 0xe5, 0xb3, 0x8a, 0x3c, 0x4e, + 0x08, 0x07, 0xa0, 0x99, 0x81, 0xd9, 0x28, 0x2d, 0x5d, 0x4e, 0xf9, 0x5f, 0x3e, 0xf8, 0x06, 0x1c, + 0xfc, 0x87, 0x40, 0x05, 0x3f, 0x93, 0xc1, 0x0f, 0x83, 0x27, 0xef, 0xae, 0x6e, 0x7a, 0xda, 0xf5, + 0x4d, 0x4f, 0xfb, 0xfb, 0xa6, 0xa7, 0x5d, 0xde, 0xf6, 0x4a, 0xd7, 0xb7, 0xbd, 0xd2, 0x1f, 0xb7, + 0xbd, 0xd2, 0xc7, 0x37, 0x01, 0xe1, 0xcb, 0xd5, 0xcc, 0x9e, 0xc7, 0xd1, 0x63, 0xff, 0xe7, 0xf5, + 0xb1, 0x73, 0x51, 0xfc, 0x44, 0xc5, 0x46, 0xb1, 0x59, 0x55, 0xbe, 0xeb, 0xe3, 0x7f, 0x02, 0x00, + 0x00, 0xff, 0xff, 0x5c, 0xc6, 0x07, 0x2b, 0x71, 0x06, 0x00, 0x00, } func (m *RollappGenesisState) Marshal() (dAtA []byte, err error) { @@ -470,6 +481,20 @@ func (m *Rollapp) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.RevisionStartHeight != 0 { + i = encodeVarintRollapp(dAtA, i, uint64(m.RevisionStartHeight)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xa0 + } + if m.RevisionNumber != 0 { + i = encodeVarintRollapp(dAtA, i, uint64(m.RevisionNumber)) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x98 + } if m.LastStateUpdateHeight != 0 { i = encodeVarintRollapp(dAtA, i, uint64(m.LastStateUpdateHeight)) i-- @@ -540,16 +565,6 @@ func (m *Rollapp) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x5a } - if m.Frozen { - i-- - if m.Frozen { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x48 - } if len(m.ChannelId) > 0 { i -= len(m.ChannelId) copy(dAtA[i:], m.ChannelId) @@ -691,9 +706,6 @@ func (m *Rollapp) Size() (n int) { if l > 0 { n += 1 + l + sovRollapp(uint64(l)) } - if m.Frozen { - n += 2 - } if m.Metadata != nil { l = m.Metadata.Size() n += 1 + l + sovRollapp(uint64(l)) @@ -720,6 +732,12 @@ func (m *Rollapp) Size() (n int) { if m.LastStateUpdateHeight != 0 { n += 2 + sovRollapp(uint64(m.LastStateUpdateHeight)) } + if m.RevisionNumber != 0 { + n += 2 + sovRollapp(uint64(m.RevisionNumber)) + } + if m.RevisionStartHeight != 0 { + n += 2 + sovRollapp(uint64(m.RevisionStartHeight)) + } return n } @@ -984,26 +1002,6 @@ func (m *Rollapp) Unmarshal(dAtA []byte) error { } m.ChannelId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Frozen", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowRollapp - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Frozen = bool(v != 0) case 11: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) @@ -1218,6 +1216,44 @@ func (m *Rollapp) Unmarshal(dAtA []byte) error { break } } + case 19: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RevisionNumber", wireType) + } + m.RevisionNumber = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollapp + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RevisionNumber |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 20: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RevisionStartHeight", wireType) + } + m.RevisionStartHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowRollapp + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RevisionStartHeight |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipRollapp(dAtA[iNdEx:]) diff --git a/x/rollapp/types/state_info.go b/x/rollapp/types/state_info.go index b4909796d..535a28a25 100644 --- a/x/rollapp/types/state_info.go +++ b/x/rollapp/types/state_info.go @@ -46,7 +46,10 @@ func (s *StateInfo) GetIndex() StateInfoIndex { } func (s *StateInfo) GetLatestHeight() uint64 { - return s.StartHeight + s.NumBlocks - 1 + if s.StartHeight+s.NumBlocks > 0 { + return s.StartHeight + s.NumBlocks - 1 + } + return 0 } func (s *StateInfo) ContainsHeight(height uint64) bool { diff --git a/x/rollapp/types/tx.pb.go b/x/rollapp/types/tx.pb.go index aaab4fbd5..0d578e088 100644 --- a/x/rollapp/types/tx.pb.go +++ b/x/rollapp/types/tx.pb.go @@ -306,6 +306,8 @@ type MsgUpdateState struct { BDs BlockDescriptors `protobuf:"bytes,7,opt,name=BDs,proto3" json:"BDs"` // last is true if this is the last batch of the sequencer Last bool `protobuf:"varint,8,opt,name=last,proto3" json:"last,omitempty"` + // rollapp_revision is the revision of the rollapp chain. increases after hard fork + RollappRevision uint64 `protobuf:"varint,9,opt,name=rollapp_revision,json=rollappRevision,proto3" json:"rollapp_revision,omitempty"` } func (m *MsgUpdateState) Reset() { *m = MsgUpdateState{} } @@ -390,6 +392,13 @@ func (m *MsgUpdateState) GetLast() bool { return false } +func (m *MsgUpdateState) GetRollappRevision() uint64 { + if m != nil { + return m.RollappRevision + } + return 0 +} + type MsgUpdateStateResponse struct { } @@ -907,27 +916,27 @@ func (m *MsgRemoveAppResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgRemoveAppResponse proto.InternalMessageInfo -// MsgMarkVulnerableRollapps marks specified versions as vulnerable as well as +// MsgMarkObsoleteRollapps marks specified versions as obsolete as well as // all corresponding rollapps. Must be called by the governance. -type MsgMarkVulnerableRollapps struct { +type MsgMarkObsoleteRollapps struct { // Authority is the authority address. Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` - // DrsVersions is a list of DRS versions that will be marked vulnerable. + // DrsVersions is a list of DRS versions that will be marked obsolete. DrsVersions []uint32 `protobuf:"varint,2,rep,packed,name=drs_versions,json=drsVersions,proto3" json:"drs_versions,omitempty"` } -func (m *MsgMarkVulnerableRollapps) Reset() { *m = MsgMarkVulnerableRollapps{} } -func (m *MsgMarkVulnerableRollapps) String() string { return proto.CompactTextString(m) } -func (*MsgMarkVulnerableRollapps) ProtoMessage() {} -func (*MsgMarkVulnerableRollapps) Descriptor() ([]byte, []int) { +func (m *MsgMarkObsoleteRollapps) Reset() { *m = MsgMarkObsoleteRollapps{} } +func (m *MsgMarkObsoleteRollapps) String() string { return proto.CompactTextString(m) } +func (*MsgMarkObsoleteRollapps) ProtoMessage() {} +func (*MsgMarkObsoleteRollapps) Descriptor() ([]byte, []int) { return fileDescriptor_1a86300fb8647ecb, []int{14} } -func (m *MsgMarkVulnerableRollapps) XXX_Unmarshal(b []byte) error { +func (m *MsgMarkObsoleteRollapps) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgMarkVulnerableRollapps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgMarkObsoleteRollapps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgMarkVulnerableRollapps.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgMarkObsoleteRollapps.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -937,47 +946,47 @@ func (m *MsgMarkVulnerableRollapps) XXX_Marshal(b []byte, deterministic bool) ([ return b[:n], nil } } -func (m *MsgMarkVulnerableRollapps) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgMarkVulnerableRollapps.Merge(m, src) +func (m *MsgMarkObsoleteRollapps) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMarkObsoleteRollapps.Merge(m, src) } -func (m *MsgMarkVulnerableRollapps) XXX_Size() int { +func (m *MsgMarkObsoleteRollapps) XXX_Size() int { return m.Size() } -func (m *MsgMarkVulnerableRollapps) XXX_DiscardUnknown() { - xxx_messageInfo_MsgMarkVulnerableRollapps.DiscardUnknown(m) +func (m *MsgMarkObsoleteRollapps) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMarkObsoleteRollapps.DiscardUnknown(m) } -var xxx_messageInfo_MsgMarkVulnerableRollapps proto.InternalMessageInfo +var xxx_messageInfo_MsgMarkObsoleteRollapps proto.InternalMessageInfo -func (m *MsgMarkVulnerableRollapps) GetAuthority() string { +func (m *MsgMarkObsoleteRollapps) GetAuthority() string { if m != nil { return m.Authority } return "" } -func (m *MsgMarkVulnerableRollapps) GetDrsVersions() []uint32 { +func (m *MsgMarkObsoleteRollapps) GetDrsVersions() []uint32 { if m != nil { return m.DrsVersions } return nil } -type MsgMarkVulnerableRollappsResponse struct { +type MsgMarkObsoleteRollappsResponse struct { } -func (m *MsgMarkVulnerableRollappsResponse) Reset() { *m = MsgMarkVulnerableRollappsResponse{} } -func (m *MsgMarkVulnerableRollappsResponse) String() string { return proto.CompactTextString(m) } -func (*MsgMarkVulnerableRollappsResponse) ProtoMessage() {} -func (*MsgMarkVulnerableRollappsResponse) Descriptor() ([]byte, []int) { +func (m *MsgMarkObsoleteRollappsResponse) Reset() { *m = MsgMarkObsoleteRollappsResponse{} } +func (m *MsgMarkObsoleteRollappsResponse) String() string { return proto.CompactTextString(m) } +func (*MsgMarkObsoleteRollappsResponse) ProtoMessage() {} +func (*MsgMarkObsoleteRollappsResponse) Descriptor() ([]byte, []int) { return fileDescriptor_1a86300fb8647ecb, []int{15} } -func (m *MsgMarkVulnerableRollappsResponse) XXX_Unmarshal(b []byte) error { +func (m *MsgMarkObsoleteRollappsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *MsgMarkVulnerableRollappsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *MsgMarkObsoleteRollappsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_MsgMarkVulnerableRollappsResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_MsgMarkObsoleteRollappsResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -987,17 +996,17 @@ func (m *MsgMarkVulnerableRollappsResponse) XXX_Marshal(b []byte, deterministic return b[:n], nil } } -func (m *MsgMarkVulnerableRollappsResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MsgMarkVulnerableRollappsResponse.Merge(m, src) +func (m *MsgMarkObsoleteRollappsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgMarkObsoleteRollappsResponse.Merge(m, src) } -func (m *MsgMarkVulnerableRollappsResponse) XXX_Size() int { +func (m *MsgMarkObsoleteRollappsResponse) XXX_Size() int { return m.Size() } -func (m *MsgMarkVulnerableRollappsResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MsgMarkVulnerableRollappsResponse.DiscardUnknown(m) +func (m *MsgMarkObsoleteRollappsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgMarkObsoleteRollappsResponse.DiscardUnknown(m) } -var xxx_messageInfo_MsgMarkVulnerableRollappsResponse proto.InternalMessageInfo +var xxx_messageInfo_MsgMarkObsoleteRollappsResponse proto.InternalMessageInfo func init() { proto.RegisterType((*MsgCreateRollapp)(nil), "dymensionxyz.dymension.rollapp.MsgCreateRollapp") @@ -1014,8 +1023,8 @@ func init() { proto.RegisterType((*MsgUpdateAppResponse)(nil), "dymensionxyz.dymension.rollapp.MsgUpdateAppResponse") proto.RegisterType((*MsgRemoveApp)(nil), "dymensionxyz.dymension.rollapp.MsgRemoveApp") proto.RegisterType((*MsgRemoveAppResponse)(nil), "dymensionxyz.dymension.rollapp.MsgRemoveAppResponse") - proto.RegisterType((*MsgMarkVulnerableRollapps)(nil), "dymensionxyz.dymension.rollapp.MsgMarkVulnerableRollapps") - proto.RegisterType((*MsgMarkVulnerableRollappsResponse)(nil), "dymensionxyz.dymension.rollapp.MsgMarkVulnerableRollappsResponse") + proto.RegisterType((*MsgMarkObsoleteRollapps)(nil), "dymensionxyz.dymension.rollapp.MsgMarkObsoleteRollapps") + proto.RegisterType((*MsgMarkObsoleteRollappsResponse)(nil), "dymensionxyz.dymension.rollapp.MsgMarkObsoleteRollappsResponse") } func init() { @@ -1023,73 +1032,74 @@ func init() { } var fileDescriptor_1a86300fb8647ecb = []byte{ - // 1044 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0x4f, 0x6f, 0xe3, 0x44, - 0x14, 0xaf, 0x93, 0x34, 0x4d, 0x5e, 0xd2, 0xd2, 0x1d, 0xaa, 0x62, 0xb2, 0x4b, 0xc8, 0xa6, 0x42, - 0x04, 0x76, 0x49, 0x68, 0xb7, 0x20, 0x28, 0x5c, 0xda, 0xad, 0xb4, 0xbb, 0xa0, 0xb0, 0xe0, 0x2d, - 0x3d, 0x70, 0x89, 0xdc, 0x78, 0xea, 0x58, 0x6b, 0x7b, 0xcc, 0xcc, 0x24, 0x6d, 0xe0, 0x86, 0x84, - 0x38, 0x20, 0x21, 0xc4, 0x81, 0x13, 0x1f, 0x82, 0x03, 0x9f, 0x01, 0xed, 0x71, 0x8f, 0x70, 0x41, - 0xa8, 0x3d, 0xf0, 0x35, 0x90, 0xc7, 0xe3, 0x49, 0xda, 0xfc, 0xb1, 0x5b, 0x38, 0x79, 0xe6, 0xf9, - 0xf7, 0x7b, 0x7f, 0x7e, 0x6f, 0xe6, 0x59, 0x86, 0xd7, 0xad, 0xa1, 0x87, 0x7d, 0xe6, 0x10, 0xff, - 0x74, 0xf8, 0x55, 0x4b, 0x6d, 0x5a, 0x94, 0xb8, 0xae, 0x19, 0x04, 0x2d, 0x7e, 0xda, 0x0c, 0x28, - 0xe1, 0x04, 0x55, 0xc7, 0x81, 0x4d, 0xb5, 0x69, 0x4a, 0x60, 0xe5, 0xa5, 0x2e, 0x61, 0x1e, 0x61, - 0x2d, 0x8f, 0xd9, 0xad, 0xc1, 0x66, 0xf8, 0x88, 0x88, 0x95, 0x77, 0x12, 0x22, 0x1c, 0xb9, 0xa4, - 0xfb, 0xb4, 0x63, 0x61, 0xd6, 0xa5, 0x4e, 0xc0, 0x09, 0x95, 0xb4, 0xbb, 0x09, 0x34, 0xf9, 0x94, - 0xe8, 0xb7, 0x12, 0xd0, 0x1e, 0xe6, 0xa6, 0x65, 0x72, 0x53, 0xc2, 0x37, 0x13, 0xe0, 0x36, 0xf6, - 0x31, 0x73, 0x58, 0xc7, 0xf1, 0x8f, 0x89, 0xa4, 0xac, 0xd9, 0xc4, 0x26, 0x62, 0xd9, 0x0a, 0x57, - 0x91, 0xb5, 0xfe, 0x43, 0x16, 0x56, 0xdb, 0xcc, 0xbe, 0x4f, 0xb1, 0xc9, 0xb1, 0x11, 0xb1, 0x91, - 0x0e, 0x4b, 0xdd, 0xd0, 0x40, 0xa8, 0xae, 0xd5, 0xb4, 0x46, 0xd1, 0x88, 0xb7, 0xe8, 0x15, 0x00, - 0x19, 0xa2, 0xe3, 0x58, 0x7a, 0x46, 0xbc, 0x2c, 0x4a, 0xcb, 0x23, 0x0b, 0xdd, 0x81, 0x1b, 0x8e, - 0xef, 0x70, 0xc7, 0x74, 0x3b, 0x0c, 0x7f, 0xd9, 0xc7, 0x7e, 0x17, 0x53, 0xbd, 0x24, 0x50, 0xab, - 0xf2, 0xc5, 0x93, 0xd8, 0x8e, 0xd6, 0x60, 0xd1, 0x74, 0x1d, 0x93, 0xe9, 0x65, 0x01, 0x88, 0x36, - 0xe8, 0x63, 0x28, 0xc4, 0xb5, 0xea, 0xcb, 0x35, 0xad, 0x51, 0xda, 0x6a, 0x35, 0xe7, 0x77, 0xae, - 0x29, 0xd3, 0x6e, 0x4b, 0x9a, 0xa1, 0x1c, 0xa0, 0x03, 0x28, 0x8f, 0x2b, 0xa1, 0xaf, 0x08, 0x87, - 0x77, 0x92, 0x1c, 0x3e, 0x88, 0x38, 0x8f, 0xfc, 0x63, 0xb2, 0x97, 0x7b, 0xf6, 0xd7, 0xab, 0x9a, - 0x51, 0xb2, 0x47, 0x26, 0xf4, 0x00, 0x96, 0x06, 0x5e, 0x87, 0x0f, 0x03, 0xac, 0xbf, 0x50, 0xd3, - 0x1a, 0x2b, 0x5b, 0xcd, 0x94, 0x19, 0x36, 0x0f, 0xdb, 0x07, 0xc3, 0x00, 0x1b, 0xf9, 0x81, 0x17, - 0x3e, 0x77, 0xca, 0xdf, 0xfc, 0xf3, 0xeb, 0x9b, 0xb1, 0xb6, 0x1f, 0xe5, 0x0a, 0xd9, 0xd5, 0x52, - 0xbd, 0x02, 0xfa, 0xe5, 0x7e, 0x18, 0x98, 0x05, 0xc4, 0x67, 0xb8, 0xfe, 0x5b, 0x06, 0x6e, 0xb6, - 0x99, 0xfd, 0x79, 0x60, 0x8d, 0x5e, 0x86, 0x19, 0x51, 0xcf, 0xe4, 0x0e, 0xf1, 0x43, 0x45, 0xc9, - 0x89, 0x8f, 0xe3, 0xae, 0x45, 0x9b, 0x6b, 0xf5, 0x2c, 0x3b, 0xa3, 0x67, 0x9f, 0x8d, 0x75, 0x67, - 0xf1, 0x5a, 0xdd, 0x91, 0x82, 0xce, 0xee, 0x51, 0xfe, 0xff, 0xe8, 0xd1, 0x0e, 0x84, 0xd2, 0x46, - 0x02, 0xd4, 0x5f, 0x83, 0x8d, 0x39, 0xaa, 0x29, 0x75, 0x7f, 0xca, 0xc0, 0x8a, 0xc2, 0x3d, 0xe1, - 0x26, 0xc7, 0x73, 0x2e, 0xc2, 0x2d, 0x18, 0x49, 0x38, 0xa9, 0x69, 0x0d, 0x4a, 0x8c, 0x9b, 0x94, - 0x3f, 0xc4, 0x8e, 0xdd, 0xe3, 0x42, 0xcd, 0x9c, 0x31, 0x6e, 0x0a, 0xf9, 0x7e, 0xdf, 0xdb, 0x0b, - 0x47, 0x07, 0xd3, 0x73, 0xe2, 0xfd, 0xc8, 0x80, 0xd6, 0x21, 0xbf, 0xbf, 0xfb, 0xa9, 0xc9, 0x7b, - 0x42, 0xe4, 0xa2, 0x21, 0x77, 0xe8, 0x21, 0x64, 0xf7, 0xf6, 0x99, 0xbe, 0x24, 0x24, 0x7a, 0x3b, - 0x49, 0x22, 0xe1, 0x6c, 0x5f, 0xcd, 0x25, 0x26, 0x74, 0x5a, 0x30, 0x42, 0x17, 0x08, 0x41, 0xce, - 0x35, 0x19, 0xd7, 0x0b, 0x35, 0xad, 0x51, 0x30, 0xc4, 0x7a, 0xe2, 0x38, 0xe6, 0x57, 0x97, 0xea, - 0x3a, 0xac, 0x5f, 0xd4, 0x44, 0xc9, 0xf5, 0xbd, 0x06, 0x6b, 0x6d, 0x66, 0x1f, 0x50, 0xd3, 0x67, - 0xc7, 0x98, 0x3e, 0x0e, 0xa5, 0x66, 0x3d, 0x27, 0x40, 0x1b, 0xb0, 0xdc, 0xed, 0x53, 0x8a, 0x7d, - 0xde, 0x19, 0x3f, 0x8d, 0x65, 0x69, 0x14, 0x40, 0x74, 0x13, 0x8a, 0x3e, 0x3e, 0x91, 0x80, 0x48, - 0xbf, 0x82, 0x8f, 0x4f, 0x1e, 0x4f, 0x39, 0xb1, 0xd9, 0x4b, 0xea, 0xee, 0xa0, 0x30, 0xcf, 0x8b, - 0x31, 0xea, 0x55, 0xb8, 0x35, 0x2d, 0x19, 0x95, 0xed, 0xef, 0x1a, 0x14, 0xdb, 0xcc, 0xde, 0xb5, - 0xac, 0xdd, 0xb9, 0x03, 0x0e, 0x41, 0xce, 0x37, 0x3d, 0x2c, 0x53, 0x12, 0xeb, 0x84, 0x74, 0xc2, - 0x66, 0xc7, 0xc3, 0xdf, 0x21, 0xbe, 0x68, 0x66, 0xd1, 0x18, 0x37, 0x85, 0xf7, 0xd2, 0xf1, 0x4c, - 0x1b, 0xcb, 0x6e, 0x46, 0x1b, 0xb4, 0x0a, 0xd9, 0x3e, 0x75, 0xc5, 0x79, 0x2f, 0x1a, 0xe1, 0x52, - 0xdc, 0x5f, 0x6a, 0x61, 0x2a, 0x1a, 0xbc, 0x68, 0x44, 0x9b, 0x8b, 0x6d, 0xa9, 0xbf, 0x08, 0x37, - 0x54, 0x1d, 0xaa, 0xba, 0x3f, 0x35, 0x28, 0xab, 0x36, 0xcd, 0x2f, 0x70, 0x05, 0x32, 0x72, 0x0a, - 0xe4, 0x8c, 0x8c, 0x63, 0xa9, 0x82, 0xb3, 0x33, 0x0b, 0xce, 0x25, 0x14, 0xbc, 0x38, 0xa7, 0xe0, - 0xfc, 0x94, 0x82, 0x97, 0xa6, 0x14, 0x5c, 0x98, 0x5d, 0xf0, 0xba, 0x38, 0x66, 0xaa, 0x34, 0x55, - 0x33, 0x16, 0x25, 0x1b, 0xd8, 0x23, 0x83, 0x2b, 0x96, 0x9c, 0x70, 0xbc, 0xa6, 0x85, 0x57, 0x61, - 0x54, 0x78, 0x17, 0x5e, 0x6e, 0x33, 0xbb, 0x6d, 0xd2, 0xa7, 0x87, 0x7d, 0xd7, 0xc7, 0xd4, 0x3c, - 0x72, 0xe3, 0xe1, 0xc2, 0xc2, 0xdb, 0x6d, 0xf6, 0x79, 0x8f, 0x50, 0x87, 0x0f, 0x65, 0x36, 0x23, - 0x03, 0xba, 0x0d, 0x65, 0x8b, 0xb2, 0xce, 0x00, 0xd3, 0xf0, 0xba, 0x32, 0x3d, 0x53, 0xcb, 0x36, - 0x96, 0x8d, 0x92, 0x45, 0xd9, 0xa1, 0x34, 0xed, 0xac, 0x84, 0x39, 0x8c, 0x28, 0xf5, 0x0d, 0xb8, - 0x3d, 0x33, 0x5a, 0x9c, 0xd2, 0xd6, 0xb7, 0x05, 0xc8, 0xb6, 0x99, 0x8d, 0xbe, 0x86, 0xe5, 0x8b, - 0xdf, 0xf3, 0xc4, 0x49, 0x71, 0xf9, 0x8b, 0x53, 0x79, 0xef, 0xaa, 0x8c, 0x38, 0x09, 0xf4, 0x8b, - 0x06, 0xfa, 0xcc, 0x0f, 0xd4, 0x07, 0x29, 0xdc, 0xce, 0x22, 0x57, 0xee, 0xff, 0x07, 0xb2, 0x4a, - 0xaf, 0x0f, 0xa5, 0xf1, 0x01, 0xdf, 0x4c, 0xed, 0x53, 0xe0, 0x2b, 0xef, 0x5e, 0x0d, 0xaf, 0xc2, - 0x7e, 0xa7, 0xc1, 0x8d, 0xc9, 0x49, 0xb9, 0x9d, 0xc2, 0xdb, 0x04, 0xab, 0xf2, 0xe1, 0x75, 0x58, - 0x2a, 0x93, 0x63, 0xc8, 0xcb, 0x21, 0xf8, 0x46, 0x0a, 0x3f, 0x11, 0xb4, 0xb2, 0x99, 0x1a, 0xaa, - 0xe2, 0x10, 0x28, 0x8e, 0xc6, 0xd1, 0xdd, 0xd4, 0xb2, 0x85, 0xd1, 0xb6, 0xaf, 0x82, 0x1e, 0x0f, - 0x38, 0x1a, 0x06, 0x69, 0x02, 0x2a, 0x74, 0xaa, 0x80, 0x13, 0x13, 0x00, 0xfd, 0xac, 0xc1, 0xfa, - 0x8c, 0xfb, 0xff, 0x7e, 0x0a, 0x87, 0xd3, 0xa9, 0x95, 0xdd, 0x6b, 0x53, 0xe3, 0xc4, 0xf6, 0x3e, - 0x79, 0x76, 0x56, 0xd5, 0x9e, 0x9f, 0x55, 0xb5, 0xbf, 0xcf, 0xaa, 0xda, 0x8f, 0xe7, 0xd5, 0x85, - 0xe7, 0xe7, 0xd5, 0x85, 0x3f, 0xce, 0xab, 0x0b, 0x5f, 0x6c, 0xdb, 0x0e, 0xef, 0xf5, 0x8f, 0x9a, - 0x5d, 0xe2, 0xb5, 0x66, 0xfc, 0x41, 0x0c, 0xee, 0xb5, 0x4e, 0x47, 0x3f, 0x4f, 0xc3, 0x00, 0xb3, - 0xa3, 0xbc, 0xf8, 0x55, 0xb8, 0xf7, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x17, 0x38, 0x06, 0xac, - 0x6b, 0x0d, 0x00, 0x00, + // 1062 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcf, 0x6f, 0x1b, 0xc5, + 0x17, 0xcf, 0xda, 0x8e, 0x7f, 0x3c, 0x3b, 0xa9, 0x33, 0xdf, 0x28, 0x5d, 0xb9, 0xfd, 0xba, 0xae, + 0x2b, 0x44, 0x4a, 0x8b, 0x4d, 0xd2, 0xf0, 0x43, 0x01, 0x09, 0x25, 0x8d, 0xd4, 0x16, 0x64, 0x02, + 0xdb, 0xd0, 0x03, 0x17, 0x6b, 0xe3, 0x9d, 0x6c, 0x96, 0x7a, 0x77, 0xcc, 0xcc, 0xd8, 0x89, 0xe1, + 0xc6, 0x85, 0x03, 0x12, 0xea, 0x1f, 0xc0, 0x1f, 0xc1, 0x81, 0x2b, 0x57, 0xd4, 0x63, 0x8f, 0x70, + 0x41, 0x28, 0x39, 0xf0, 0x67, 0x80, 0x66, 0x76, 0x76, 0xec, 0x24, 0xb6, 0x77, 0x13, 0x38, 0xed, + 0xcc, 0x9b, 0xcf, 0xfb, 0xf5, 0x79, 0x6f, 0xde, 0x68, 0xe1, 0x75, 0x67, 0xe8, 0xe3, 0x80, 0x79, + 0x24, 0x38, 0x1e, 0x7e, 0xdd, 0xd4, 0x9b, 0x26, 0x25, 0xdd, 0xae, 0xdd, 0xeb, 0x35, 0xf9, 0x71, + 0xa3, 0x47, 0x09, 0x27, 0xa8, 0x3a, 0x0e, 0x6c, 0xe8, 0x4d, 0x43, 0x01, 0x2b, 0xd7, 0x3b, 0x84, + 0xf9, 0x84, 0x35, 0x7d, 0xe6, 0x36, 0x07, 0x6b, 0xe2, 0x13, 0x2a, 0x56, 0xde, 0x8e, 0xf1, 0xb0, + 0xdf, 0x25, 0x9d, 0xe7, 0x6d, 0x07, 0xb3, 0x0e, 0xf5, 0x7a, 0x9c, 0x50, 0xa5, 0x76, 0x3f, 0x46, + 0x4d, 0x7d, 0x15, 0xfa, 0xcd, 0x18, 0xb4, 0x8f, 0xb9, 0xed, 0xd8, 0xdc, 0x56, 0xf0, 0xb5, 0x18, + 0xb8, 0x8b, 0x03, 0xcc, 0x3c, 0xd6, 0xf6, 0x82, 0x03, 0xa2, 0x54, 0x96, 0x5d, 0xe2, 0x12, 0xb9, + 0x6c, 0x8a, 0x55, 0x28, 0xad, 0xff, 0x90, 0x86, 0x72, 0x8b, 0xb9, 0x0f, 0x29, 0xb6, 0x39, 0xb6, + 0x42, 0x6d, 0x64, 0x42, 0xae, 0x23, 0x04, 0x84, 0x9a, 0x46, 0xcd, 0x58, 0x2d, 0x58, 0xd1, 0x16, + 0xfd, 0x1f, 0x40, 0xb9, 0x68, 0x7b, 0x8e, 0x99, 0x92, 0x87, 0x05, 0x25, 0x79, 0xe2, 0xa0, 0x7b, + 0xb0, 0xe4, 0x05, 0x1e, 0xf7, 0xec, 0x6e, 0x9b, 0xe1, 0xaf, 0xfa, 0x38, 0xe8, 0x60, 0x6a, 0x16, + 0x25, 0xaa, 0xac, 0x0e, 0x9e, 0x46, 0x72, 0xb4, 0x0c, 0xf3, 0x76, 0xd7, 0xb3, 0x99, 0x59, 0x92, + 0x80, 0x70, 0x83, 0x3e, 0x86, 0x7c, 0x94, 0xab, 0xb9, 0x50, 0x33, 0x56, 0x8b, 0xeb, 0xcd, 0xc6, + 0xec, 0xca, 0x35, 0x54, 0xd8, 0x2d, 0xa5, 0x66, 0x69, 0x03, 0x68, 0x0f, 0x4a, 0xe3, 0x4c, 0x98, + 0x8b, 0xd2, 0xe0, 0xbd, 0x38, 0x83, 0x8f, 0x42, 0x9d, 0x27, 0xc1, 0x01, 0xd9, 0xce, 0xbc, 0xfc, + 0xe3, 0x96, 0x61, 0x15, 0xdd, 0x91, 0x08, 0x3d, 0x82, 0xdc, 0xc0, 0x6f, 0xf3, 0x61, 0x0f, 0x9b, + 0xd7, 0x6a, 0xc6, 0xea, 0xe2, 0x7a, 0x23, 0x61, 0x84, 0x8d, 0x67, 0xad, 0xbd, 0x61, 0x0f, 0x5b, + 0xd9, 0x81, 0x2f, 0xbe, 0x9b, 0xa5, 0x6f, 0xff, 0xfa, 0xe9, 0x8d, 0x88, 0xdb, 0x8f, 0x32, 0xf9, + 0x74, 0xb9, 0x58, 0xaf, 0x80, 0x79, 0xbe, 0x1e, 0x16, 0x66, 0x3d, 0x12, 0x30, 0x5c, 0xff, 0x39, + 0x05, 0x37, 0x5a, 0xcc, 0xfd, 0xbc, 0xe7, 0x8c, 0x0e, 0x45, 0x44, 0xd4, 0xb7, 0xb9, 0x47, 0x02, + 0xc1, 0x28, 0x39, 0x0a, 0x70, 0x54, 0xb5, 0x70, 0x73, 0xa5, 0x9a, 0xa5, 0xa7, 0xd4, 0xec, 0xb3, + 0xb1, 0xea, 0xcc, 0x5f, 0xa9, 0x3a, 0x8a, 0xd0, 0xe9, 0x35, 0xca, 0xfe, 0x17, 0x35, 0xda, 0x04, + 0x41, 0x6d, 0x48, 0x40, 0xfd, 0x35, 0xb8, 0x33, 0x83, 0x35, 0xcd, 0xee, 0x2f, 0x29, 0x58, 0xd4, + 0xb8, 0xa7, 0xdc, 0xe6, 0x78, 0xc6, 0x45, 0xb8, 0x09, 0x23, 0x0a, 0x2f, 0x72, 0x5a, 0x83, 0x22, + 0xe3, 0x36, 0xe5, 0x8f, 0xb1, 0xe7, 0x1e, 0x72, 0xc9, 0x66, 0xc6, 0x1a, 0x17, 0x09, 0xfd, 0xa0, + 0xef, 0x6f, 0x8b, 0xd1, 0xc1, 0xcc, 0x8c, 0x3c, 0x1f, 0x09, 0xd0, 0x0a, 0x64, 0x77, 0xb6, 0x3e, + 0xb5, 0xf9, 0xa1, 0x24, 0xb9, 0x60, 0xa9, 0x1d, 0x7a, 0x0c, 0xe9, 0xed, 0x1d, 0x66, 0xe6, 0x24, + 0x45, 0x6f, 0xc5, 0x51, 0x24, 0x8d, 0xed, 0xe8, 0xb9, 0xc4, 0x24, 0x4f, 0x73, 0x96, 0x30, 0x81, + 0x10, 0x64, 0xba, 0x36, 0xe3, 0x66, 0xbe, 0x66, 0xac, 0xe6, 0x2d, 0xb9, 0x46, 0x77, 0xa1, 0x1c, + 0x35, 0x0a, 0xc5, 0x03, 0x4f, 0xd8, 0x32, 0x0b, 0x32, 0xb4, 0x6b, 0x34, 0xea, 0xc4, 0x50, 0x7c, + 0xa1, 0x73, 0xb3, 0xe5, 0x5c, 0xdd, 0x84, 0x95, 0xb3, 0xf4, 0x69, 0x66, 0xbf, 0x37, 0x60, 0xb9, + 0xc5, 0xdc, 0x3d, 0x6a, 0x07, 0xec, 0x00, 0xd3, 0x5d, 0x51, 0x15, 0x76, 0xe8, 0xf5, 0xd0, 0x1d, + 0x58, 0xe8, 0xf4, 0x29, 0xc5, 0x01, 0x6f, 0x8f, 0x37, 0x6e, 0x49, 0x09, 0x25, 0x10, 0xdd, 0x80, + 0x42, 0x80, 0x8f, 0x14, 0x20, 0xa4, 0x3a, 0x1f, 0xe0, 0xa3, 0xdd, 0x09, 0xcd, 0x9d, 0x3e, 0x57, + 0x88, 0x4d, 0x24, 0xe2, 0x3c, 0xeb, 0xa3, 0x5e, 0x85, 0x9b, 0x93, 0x82, 0xd1, 0xd1, 0xfe, 0x6a, + 0x40, 0xa1, 0xc5, 0xdc, 0x2d, 0xc7, 0xd9, 0x9a, 0x39, 0x0b, 0x11, 0x64, 0x02, 0xdb, 0xc7, 0x2a, + 0x24, 0xb9, 0x8e, 0x09, 0x47, 0xf4, 0x45, 0xf4, 0x4e, 0x08, 0x72, 0x33, 0xf2, 0x7c, 0x5c, 0x24, + 0xae, 0xb0, 0xe7, 0xdb, 0x2e, 0x56, 0x85, 0x0f, 0x37, 0xa8, 0x0c, 0xe9, 0x3e, 0xed, 0xca, 0xab, + 0x51, 0xb0, 0xc4, 0x52, 0x5e, 0x75, 0xea, 0x60, 0x2a, 0x7b, 0x61, 0xde, 0x0a, 0x37, 0x67, 0xcb, + 0x52, 0xff, 0x1f, 0x2c, 0xe9, 0x3c, 0x74, 0x76, 0xbf, 0x1b, 0x50, 0xd2, 0x65, 0x9a, 0x9d, 0xe0, + 0x22, 0xa4, 0xd4, 0xc0, 0xc8, 0x58, 0x29, 0xcf, 0xd1, 0x09, 0xa7, 0xa7, 0x26, 0x9c, 0x89, 0x49, + 0x78, 0x7e, 0x46, 0xc2, 0xd9, 0x09, 0x09, 0xe7, 0x26, 0x24, 0x9c, 0x9f, 0x9e, 0xf0, 0x8a, 0x6c, + 0x33, 0x9d, 0x9a, 0xce, 0x19, 0xcb, 0x94, 0x2d, 0xec, 0x93, 0xc1, 0x25, 0x53, 0x8e, 0x69, 0xaf, + 0x49, 0xee, 0xb5, 0x1b, 0xed, 0xfe, 0x4b, 0xb8, 0xde, 0x62, 0x6e, 0xcb, 0xa6, 0xcf, 0x77, 0xf7, + 0x19, 0xe9, 0x62, 0x3d, 0x85, 0x98, 0x18, 0x03, 0x76, 0x9f, 0x1f, 0x12, 0xea, 0xf1, 0xa1, 0x8a, + 0x65, 0x24, 0x40, 0xb7, 0xa1, 0xe4, 0x50, 0xd6, 0x1e, 0x60, 0x2a, 0x2e, 0x1d, 0x33, 0x53, 0xb5, + 0xf4, 0xea, 0x82, 0x55, 0x74, 0x28, 0x7b, 0xa6, 0x44, 0x9b, 0x8b, 0x22, 0x82, 0x91, 0x4a, 0xfd, + 0x36, 0xdc, 0x9a, 0xe2, 0x2b, 0x0a, 0x67, 0xfd, 0xef, 0x1c, 0xa4, 0x5b, 0xcc, 0x45, 0xdf, 0xc0, + 0xc2, 0xd9, 0x67, 0x3f, 0x76, 0xa0, 0x9c, 0x7f, 0x98, 0x2a, 0xef, 0x5d, 0x56, 0x23, 0x0a, 0x02, + 0xfd, 0x68, 0x80, 0x39, 0xf5, 0x1d, 0x7b, 0x3f, 0x81, 0xd9, 0x69, 0xca, 0x95, 0x87, 0xff, 0x42, + 0x59, 0x87, 0xd7, 0x87, 0xe2, 0xf8, 0x3b, 0xd0, 0x48, 0x6c, 0x53, 0xe2, 0x2b, 0xef, 0x5c, 0x0e, + 0xaf, 0xdd, 0x7e, 0x67, 0xc0, 0xd2, 0xc5, 0x29, 0xb9, 0x91, 0xc0, 0xda, 0x05, 0xad, 0xca, 0x07, + 0x57, 0xd1, 0xd2, 0x91, 0x1c, 0x40, 0x56, 0x0d, 0xc0, 0xbb, 0x09, 0xec, 0x84, 0xd0, 0xca, 0x5a, + 0x62, 0xa8, 0xf6, 0x43, 0xa0, 0x30, 0x1a, 0x45, 0xf7, 0x13, 0xd3, 0x26, 0xbc, 0x6d, 0x5c, 0x06, + 0x3d, 0xee, 0x70, 0x34, 0x08, 0x92, 0x38, 0xd4, 0xe8, 0x44, 0x0e, 0x2f, 0xdc, 0x7e, 0xf4, 0x42, + 0x3c, 0x7e, 0x93, 0xee, 0xfe, 0xbb, 0x09, 0xcc, 0x4d, 0x52, 0xac, 0x7c, 0x78, 0x45, 0xc5, 0x28, + 0xa4, 0xed, 0x4f, 0x5e, 0x9e, 0x54, 0x8d, 0x57, 0x27, 0x55, 0xe3, 0xcf, 0x93, 0xaa, 0xf1, 0xe2, + 0xb4, 0x3a, 0xf7, 0xea, 0xb4, 0x3a, 0xf7, 0xdb, 0x69, 0x75, 0xee, 0x8b, 0x0d, 0xd7, 0xe3, 0x87, + 0xfd, 0xfd, 0x46, 0x87, 0xf8, 0xcd, 0x29, 0xbf, 0x18, 0x83, 0x07, 0xcd, 0xe3, 0xd1, 0xdf, 0xd5, + 0xb0, 0x87, 0xd9, 0x7e, 0x56, 0xfe, 0x4b, 0x3c, 0xf8, 0x27, 0x00, 0x00, 0xff, 0xff, 0xcd, 0x65, + 0x36, 0xd6, 0x8c, 0x0d, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -1111,7 +1121,7 @@ type MsgClient interface { AddApp(ctx context.Context, in *MsgAddApp, opts ...grpc.CallOption) (*MsgAddAppResponse, error) UpdateApp(ctx context.Context, in *MsgUpdateApp, opts ...grpc.CallOption) (*MsgUpdateAppResponse, error) RemoveApp(ctx context.Context, in *MsgRemoveApp, opts ...grpc.CallOption) (*MsgRemoveAppResponse, error) - MarkVulnerableRollapps(ctx context.Context, in *MsgMarkVulnerableRollapps, opts ...grpc.CallOption) (*MsgMarkVulnerableRollappsResponse, error) + MarkObsoleteRollapps(ctx context.Context, in *MsgMarkObsoleteRollapps, opts ...grpc.CallOption) (*MsgMarkObsoleteRollappsResponse, error) } type msgClient struct { @@ -1185,9 +1195,9 @@ func (c *msgClient) RemoveApp(ctx context.Context, in *MsgRemoveApp, opts ...grp return out, nil } -func (c *msgClient) MarkVulnerableRollapps(ctx context.Context, in *MsgMarkVulnerableRollapps, opts ...grpc.CallOption) (*MsgMarkVulnerableRollappsResponse, error) { - out := new(MsgMarkVulnerableRollappsResponse) - err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.rollapp.Msg/MarkVulnerableRollapps", in, out, opts...) +func (c *msgClient) MarkObsoleteRollapps(ctx context.Context, in *MsgMarkObsoleteRollapps, opts ...grpc.CallOption) (*MsgMarkObsoleteRollappsResponse, error) { + out := new(MsgMarkObsoleteRollappsResponse) + err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.rollapp.Msg/MarkObsoleteRollapps", in, out, opts...) if err != nil { return nil, err } @@ -1203,7 +1213,7 @@ type MsgServer interface { AddApp(context.Context, *MsgAddApp) (*MsgAddAppResponse, error) UpdateApp(context.Context, *MsgUpdateApp) (*MsgUpdateAppResponse, error) RemoveApp(context.Context, *MsgRemoveApp) (*MsgRemoveAppResponse, error) - MarkVulnerableRollapps(context.Context, *MsgMarkVulnerableRollapps) (*MsgMarkVulnerableRollappsResponse, error) + MarkObsoleteRollapps(context.Context, *MsgMarkObsoleteRollapps) (*MsgMarkObsoleteRollappsResponse, error) } // UnimplementedMsgServer can be embedded to have forward compatible implementations. @@ -1231,8 +1241,8 @@ func (*UnimplementedMsgServer) UpdateApp(ctx context.Context, req *MsgUpdateApp) func (*UnimplementedMsgServer) RemoveApp(ctx context.Context, req *MsgRemoveApp) (*MsgRemoveAppResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method RemoveApp not implemented") } -func (*UnimplementedMsgServer) MarkVulnerableRollapps(ctx context.Context, req *MsgMarkVulnerableRollapps) (*MsgMarkVulnerableRollappsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method MarkVulnerableRollapps not implemented") +func (*UnimplementedMsgServer) MarkObsoleteRollapps(ctx context.Context, req *MsgMarkObsoleteRollapps) (*MsgMarkObsoleteRollappsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method MarkObsoleteRollapps not implemented") } func RegisterMsgServer(s grpc1.Server, srv MsgServer) { @@ -1365,20 +1375,20 @@ func _Msg_RemoveApp_Handler(srv interface{}, ctx context.Context, dec func(inter return interceptor(ctx, in, info, handler) } -func _Msg_MarkVulnerableRollapps_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(MsgMarkVulnerableRollapps) +func _Msg_MarkObsoleteRollapps_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgMarkObsoleteRollapps) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).MarkVulnerableRollapps(ctx, in) + return srv.(MsgServer).MarkObsoleteRollapps(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/dymensionxyz.dymension.rollapp.Msg/MarkVulnerableRollapps", + FullMethod: "/dymensionxyz.dymension.rollapp.Msg/MarkObsoleteRollapps", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).MarkVulnerableRollapps(ctx, req.(*MsgMarkVulnerableRollapps)) + return srv.(MsgServer).MarkObsoleteRollapps(ctx, req.(*MsgMarkObsoleteRollapps)) } return interceptor(ctx, in, info, handler) } @@ -1416,8 +1426,8 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ Handler: _Msg_RemoveApp_Handler, }, { - MethodName: "MarkVulnerableRollapps", - Handler: _Msg_MarkVulnerableRollapps_Handler, + MethodName: "MarkObsoleteRollapps", + Handler: _Msg_MarkObsoleteRollapps_Handler, }, }, Streams: []grpc.StreamDesc{}, @@ -1638,6 +1648,11 @@ func (m *MsgUpdateState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.RollappRevision != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.RollappRevision)) + i-- + dAtA[i] = 0x48 + } if m.Last { i-- if m.Last { @@ -2038,7 +2053,7 @@ func (m *MsgRemoveAppResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MsgMarkVulnerableRollapps) Marshal() (dAtA []byte, err error) { +func (m *MsgMarkObsoleteRollapps) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -2048,12 +2063,12 @@ func (m *MsgMarkVulnerableRollapps) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgMarkVulnerableRollapps) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgMarkObsoleteRollapps) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgMarkVulnerableRollapps) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgMarkObsoleteRollapps) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -2086,7 +2101,7 @@ func (m *MsgMarkVulnerableRollapps) MarshalToSizedBuffer(dAtA []byte) (int, erro return len(dAtA) - i, nil } -func (m *MsgMarkVulnerableRollappsResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgMarkObsoleteRollappsResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -2096,12 +2111,12 @@ func (m *MsgMarkVulnerableRollappsResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgMarkVulnerableRollappsResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgMarkObsoleteRollappsResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgMarkVulnerableRollappsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgMarkObsoleteRollappsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -2232,6 +2247,9 @@ func (m *MsgUpdateState) Size() (n int) { if m.Last { n += 2 } + if m.RollappRevision != 0 { + n += 1 + sovTx(uint64(m.RollappRevision)) + } return n } @@ -2396,7 +2414,7 @@ func (m *MsgRemoveAppResponse) Size() (n int) { return n } -func (m *MsgMarkVulnerableRollapps) Size() (n int) { +func (m *MsgMarkObsoleteRollapps) Size() (n int) { if m == nil { return 0 } @@ -2416,7 +2434,7 @@ func (m *MsgMarkVulnerableRollapps) Size() (n int) { return n } -func (m *MsgMarkVulnerableRollappsResponse) Size() (n int) { +func (m *MsgMarkObsoleteRollappsResponse) Size() (n int) { if m == nil { return 0 } @@ -3234,6 +3252,25 @@ func (m *MsgUpdateState) Unmarshal(dAtA []byte) error { } } m.Last = bool(v != 0) + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RollappRevision", wireType) + } + m.RollappRevision = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.RollappRevision |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -4325,7 +4362,7 @@ func (m *MsgRemoveAppResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgMarkVulnerableRollapps) Unmarshal(dAtA []byte) error { +func (m *MsgMarkObsoleteRollapps) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4348,10 +4385,10 @@ func (m *MsgMarkVulnerableRollapps) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgMarkVulnerableRollapps: wiretype end group for non-group") + return fmt.Errorf("proto: MsgMarkObsoleteRollapps: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgMarkVulnerableRollapps: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgMarkObsoleteRollapps: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -4483,7 +4520,7 @@ func (m *MsgMarkVulnerableRollapps) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgMarkVulnerableRollappsResponse) Unmarshal(dAtA []byte) error { +func (m *MsgMarkObsoleteRollappsResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -4506,10 +4543,10 @@ func (m *MsgMarkVulnerableRollappsResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgMarkVulnerableRollappsResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgMarkObsoleteRollappsResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgMarkVulnerableRollappsResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgMarkObsoleteRollappsResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { default: diff --git a/x/sequencer/keeper/bond.go b/x/sequencer/keeper/bond.go index e8731f757..8c7c3b96d 100644 --- a/x/sequencer/keeper/bond.go +++ b/x/sequencer/keeper/bond.go @@ -4,7 +4,6 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/dymension/v3/x/sequencer/types" - "github.com/dymensionxyz/gerr-cosmos/gerrc" "github.com/dymensionxyz/sdk-utils/utils/ucoin" ) @@ -41,17 +40,13 @@ func (k Keeper) TryUnbond(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coin) e return errorsmod.Wrap(err, "refund") } if seq.Tokens.IsZero() { - return errorsmod.Wrap(k.unbond(ctx, seq), "unbond") + k.unbond(ctx, seq) } return nil } // set unbonded status and clear proposer/successor if necessary -func (k Keeper) unbond(ctx sdk.Context, seq *types.Sequencer) error { - if k.IsSuccessor(ctx, *seq) { - return gerrc.ErrInternal.Wrap(`unbond next proposer: it shouldnt be possible because -they cannot do frauds and they cannot unbond gracefully`) - } +func (k Keeper) unbond(ctx sdk.Context, seq *types.Sequencer) { seq.Status = types.Unbonded ctx.EventManager().EmitEvent( @@ -60,10 +55,4 @@ they cannot do frauds and they cannot unbond gracefully`) sdk.NewAttribute(types.AttributeKeySequencer, seq.Address), ), ) - if k.IsProposer(ctx, *seq) { - k.SetProposer(ctx, seq.RollappId, types.SentinelSeqAddr) - // we assume the current successor will not be happy if the proposer suddenly unbonds - k.SetSuccessor(ctx, seq.RollappId, types.SentinelSeqAddr) - } - return nil } diff --git a/x/sequencer/keeper/fraud.go b/x/sequencer/keeper/fraud.go index 54982cef8..2cfd7d258 100644 --- a/x/sequencer/keeper/fraud.go +++ b/x/sequencer/keeper/fraud.go @@ -12,39 +12,47 @@ import ( // TryKickProposer tries to remove the incumbent proposer. It requires the incumbent // proposer to be below a threshold of bond. The caller must also be bonded and opted in. func (k Keeper) TryKickProposer(ctx sdk.Context, kicker types.Sequencer) error { - if !kicker.IsPotentialProposer() { - return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "not ready to propose") - } - ra := kicker.RollappId proposer := k.GetProposer(ctx, ra) - if k.Kickable(ctx, proposer) { - if err := k.unbond(ctx, &proposer); err != nil { - return errorsmod.Wrap(err, "unbond") - } - k.SetSequencer(ctx, proposer) - if err := k.optOutAllSequencers(ctx, ra, kicker.Address); err != nil { - return errorsmod.Wrap(err, "opt out all seqs") - } - k.hooks.AfterKickProposer(ctx, proposer) - - if err := uevent.EmitTypedEvent(ctx, &types.EventKickedProposer{ - Rollapp: ra, - Kicker: kicker.Address, - Proposer: proposer.Address, - }); err != nil { - return err - } + if !k.Kickable(ctx, proposer) { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "not kickable") + } + + // clear the proposer + k.SetProposer(ctx, ra, types.SentinelSeqAddr) + + // TODO: refund/burn if needed + k.unbond(ctx, &proposer) + k.SetSequencer(ctx, proposer) + + // This will call hard fork on the rollapp, which will also optOut all sequencers + err := k.hooks.AfterKickProposer(ctx, proposer) + if err != nil { + return errorsmod.Wrap(err, "kick proposer callbacks") + } + + // optIn the kicker + if err := kicker.SetOptedIn(ctx, true); err != nil { + return errorsmod.Wrap(err, "set opted in") } + k.SetSequencer(ctx, kicker) // this will choose kicker as next proposer, since he is the only opted in and bonded // sequencer remaining. - if err := k.ChooseProposer(ctx, ra); err != nil { + if err := k.RecoverFromSentinel(ctx, ra); err != nil { return errorsmod.Wrap(err, "choose proposer") } + if err := uevent.EmitTypedEvent(ctx, &types.EventKickedProposer{ + Rollapp: ra, + Kicker: kicker.Address, + Proposer: proposer.Address, + }); err != nil { + return err + } + return nil } @@ -66,23 +74,30 @@ func (k Keeper) SlashLiveness(ctx sdk.Context, rollappID string) error { return err } -func (k Keeper) HandleFraud(ctx sdk.Context, seq types.Sequencer, rewardee *sdk.AccAddress) error { - var err error +// Takes an optional rewardee addr who will receive some bounty +func (k Keeper) PunishSequencer(ctx sdk.Context, seqAddr string, rewardee *sdk.AccAddress) error { + var ( + rewardMul = sdk.ZeroDec() + addr = []byte(nil) + ) + + seq, err := k.RealSequencer(ctx, seqAddr) + if err != nil { + return err + } + if rewardee != nil { - rewardMul := sdk.MustNewDecFromStr("0.5") // TODO: parameterise - err = k.slash(ctx, &seq, seq.TokensCoin(), rewardMul, *rewardee) - } else { - err = k.slash(ctx, &seq, seq.TokensCoin(), sdk.ZeroDec(), nil) + rewardMul = sdk.MustNewDecFromStr("0.5") // TODO: parameterise + addr = *rewardee } + + err = k.slash(ctx, &seq, seq.TokensCoin(), rewardMul, addr) if err != nil { return errorsmod.Wrap(err, "slash") } - err = errorsmod.Wrap(k.unbond(ctx, &seq), "unbond") + k.SetSequencer(ctx, seq) - if err := k.optOutAllSequencers(ctx, seq.RollappId); err != nil { - return errorsmod.Wrap(err, "opt out all seqs") - } - return err + return nil } func (k Keeper) slash(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coin, rewardMul sdk.Dec, rewardee sdk.AccAddress) error { diff --git a/x/sequencer/keeper/fraud_test.go b/x/sequencer/keeper/fraud_test.go index 53cfd521c..62009bfde 100644 --- a/x/sequencer/keeper/fraud_test.go +++ b/x/sequencer/keeper/fraud_test.go @@ -31,29 +31,31 @@ func (s *SequencerTestSuite) TestSlashLivenessFlow() { s.Require().True(ok) } -// check the basic properties and that funds are allocated to the right place -func (s *SequencerTestSuite) TestFraud() { +// TestPunishSequencer tests the punish sequencer flow +// tokens are slashed and distributed to rewardee +func (s *SequencerTestSuite) TestPunishSequencer() { ra := s.createRollapp() - s.Run("unbonded and not proposer anymore", func() { + s.Run("kickable after punish", func() { s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) seq := s.seq(alice) s.k().SetProposer(s.Ctx, ra.RollappId, seq.Address) - err := s.k().HandleFraud(s.Ctx, seq, nil) + s.Require().False(s.k().Kickable(s.Ctx, seq)) + + err := s.k().PunishSequencer(s.Ctx, seq.Address, nil) s.Require().NoError(err) seq = s.seq(alice) - s.Require().False(s.k().IsProposer(s.Ctx, seq)) - s.Require().True(s.k().IsProposer(s.Ctx, s.k().SentinelSequencer(s.Ctx))) - s.Require().False(seq.Bonded()) + // assert alice is now kickable + s.Require().True(s.k().Kickable(s.Ctx, seq)) }) s.Run("without rewardee", func() { s.createSequencerWithBond(s.Ctx, ra.RollappId, bob, bond) seq := s.seq(bob) s.k().SetProposer(s.Ctx, ra.RollappId, seq.Address) - err := s.k().HandleFraud(s.Ctx, seq, nil) + err := s.k().PunishSequencer(s.Ctx, seq.Address, nil) s.Require().NoError(err) seq = s.seq(bob) @@ -68,7 +70,7 @@ func (s *SequencerTestSuite) TestFraud() { rewardeeBalBefore := s.App.BankKeeper.GetAllBalances(s.Ctx, rewardee) s.k().SetProposer(s.Ctx, ra.RollappId, seq.Address) - err := s.k().HandleFraud(s.Ctx, seq, &rewardee) + err := s.k().PunishSequencer(s.Ctx, seq.Address, &rewardee) s.Require().NoError(err) seq = s.seq(charlie) @@ -76,7 +78,7 @@ func (s *SequencerTestSuite) TestFraud() { s.Require().True(seq.TokensCoin().IsZero()) s.Require().True(mod.Equal(seq.TokensCoin())) rewardeeBalAfter := s.App.BankKeeper.GetAllBalances(s.Ctx, rewardee) - s.Require().False(rewardeeBalAfter.IsEqual(rewardeeBalBefore)) + s.Require().True(rewardeeBalAfter.IsAllGT(rewardeeBalBefore)) }) } @@ -110,8 +112,10 @@ func (s *SequencerTestSuite) TestFraudFullFlowDuringRotation() { s.Require().True(s.k().IsSuccessor(s.Ctx, s.seq(bob))) // instead of submitting last, proposer does a fraud - err = s.k().HandleFraud(s.Ctx, s.seq(alice), nil) + err = s.k().RollappHooks().OnHardFork(s.Ctx, ra.RollappId, 0) s.Require().NoError(err) + + // assert all are opted out s.Require().False(s.k().IsProposer(s.Ctx, s.seq(alice))) s.Require().False(s.k().IsProposer(s.Ctx, s.seq(bob))) s.Require().False(s.k().IsSuccessor(s.Ctx, s.seq(bob))) diff --git a/x/sequencer/keeper/hook_listener.go b/x/sequencer/keeper/hook_listener.go index 5d2a8d35f..4dc208ddb 100644 --- a/x/sequencer/keeper/hook_listener.go +++ b/x/sequencer/keeper/hook_listener.go @@ -33,3 +33,19 @@ func (hook rollappHook) BeforeUpdateState(ctx sdk.Context, seqAddr, rollappId st return nil } + +// OnHardFork implements the RollappHooks interface +// unbonds all rollapp sequencers +// slashing / jailing is handled by the caller, outside of this function +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappID string, _ uint64) error { + err := hook.k.optOutAllSequencers(ctx, rollappID) + if err != nil { + return errorsmod.Wrap(err, "opt out all sequencers") + } + + // clear current proposer and successor + hook.k.SetProposer(ctx, rollappID, types.SentinelSeqAddr) + hook.k.SetSuccessor(ctx, rollappID, types.SentinelSeqAddr) + + return nil +} diff --git a/x/sequencer/keeper/msg_server_bond.go b/x/sequencer/keeper/msg_server_bond.go index 936c3bfc3..d718f14c4 100644 --- a/x/sequencer/keeper/msg_server_bond.go +++ b/x/sequencer/keeper/msg_server_bond.go @@ -17,17 +17,16 @@ func (k msgServer) IncreaseBond(goCtx context.Context, msg *types.MsgIncreaseBon if err != nil { return nil, err } - defer func() { - k.SetSequencer(ctx, seq) - }() if err := k.validBondDenom(ctx, msg.AddAmount); err != nil { return nil, err } + // charge the user and modify the sequencer object if err := k.sendToModule(ctx, &seq, msg.AddAmount); err != nil { return nil, err } + k.SetSequencer(ctx, seq) // emit a typed event which includes the added amount and the active bond amount return &types.MsgIncreaseBondResponse{}, uevent.EmitTypedEvent(ctx, @@ -46,13 +45,11 @@ func (k msgServer) DecreaseBond(goCtx context.Context, msg *types.MsgDecreaseBon if err != nil { return nil, err } - defer func() { - k.SetSequencer(ctx, seq) - }() if err := k.TryUnbond(ctx, &seq, msg.GetDecreaseAmount()); err != nil { return nil, errorsmod.Wrap(err, "try unbond") } + k.SetSequencer(ctx, seq) return &types.MsgDecreaseBondResponse{}, nil } @@ -63,36 +60,41 @@ func (k msgServer) Unbond(goCtx context.Context, msg *types.MsgUnbond) (*types.M if err != nil { return nil, err } - defer func() { - k.SetSequencer(ctx, seq) - }() + + // not allowed to unbond immediately, need to serve a notice to allow the rollapp community to organise + // Also, if they already requested to unbond, we don't want to start another notice period, regardless + // of if their notice already elapsed or not. + if k.AwaitingLastProposerBlock(ctx, seq.RollappId) && (k.IsProposer(ctx, seq) || k.IsSuccessor(ctx, seq)) { + return nil, gerrc.ErrFailedPrecondition.Wrap("cannot unbond while rotation in progress") + } // ensures they will not get chosen as their own successor! if err := seq.SetOptedIn(ctx, false); err != nil { return nil, err } - err = k.TryUnbond(ctx, &seq, seq.TokensCoin()) - if errorsmod.IsOf(err, types.ErrUnbondProposerOrSuccessor) { - // not allowed to unbond immediately, need to serve a notice to allow the rollapp community to organise - // Also, if they already requested to unbond, we don't want to start another notice period, regardless - // of if their notice already elapsed or not. - if k.IsSuccessor(ctx, seq) { - return nil, gerrc.ErrFailedPrecondition.Wrap("successor cannot unbond or start notice") - } - // now we know they are proposer - // avoid starting another notice unnecessarily - if !k.RotationInProgress(ctx, seq.RollappId) { - k.StartNoticePeriod(ctx, &seq) + + // now we know they are proposer + // avoid starting another notice unnecessarily + if k.IsProposer(ctx, seq) { + if seq.NoticeInProgress(ctx.BlockTime()) { + return nil, gerrc.ErrFailedPrecondition.Wrap("notice period in progress") } + + k.StartNoticePeriod(ctx, &seq) + k.SetSequencer(ctx, seq) return &types.MsgUnbondResponse{ CompletionTime: &types.MsgUnbondResponse_NoticePeriodCompletionTime{ NoticePeriodCompletionTime: &seq.NoticePeriodTime, }, }, nil + } + + err = k.TryUnbond(ctx, &seq, seq.TokensCoin()) if err != nil { return nil, errorsmod.Wrap(err, "try unbond") } + k.SetSequencer(ctx, seq) return &types.MsgUnbondResponse{}, nil } diff --git a/x/sequencer/keeper/msg_server_create.go b/x/sequencer/keeper/msg_server_create.go index 65900b0a6..b9a3c5ec6 100644 --- a/x/sequencer/keeper/msg_server_create.go +++ b/x/sequencer/keeper/msg_server_create.go @@ -106,8 +106,11 @@ func (k msgServer) CreateSequencer(goCtx context.Context, msg *types.MsgCreateSe return nil, err } - if err := k.ChooseProposer(ctx, msg.RollappId); err != nil { - return nil, err + proposer := k.GetProposer(ctx, msg.RollappId) + if proposer.Sentinel() { + if err := k.RecoverFromSentinel(ctx, msg.RollappId); err != nil { + return nil, err + } } ctx.EventManager().EmitEvent( diff --git a/x/sequencer/keeper/msg_server_kick_proposer.go b/x/sequencer/keeper/msg_server_kick_proposer.go index 3f49ea04d..af7fe3aa9 100644 --- a/x/sequencer/keeper/msg_server_kick_proposer.go +++ b/x/sequencer/keeper/msg_server_kick_proposer.go @@ -3,19 +3,21 @@ package keeper import ( "context" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" ) func (k msgServer) KickProposer(goCtx context.Context, msg *types.MsgKickProposer) (*types.MsgKickProposerResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - seq, err := k.RealSequencer(ctx, msg.GetCreator()) - if err != nil { - return nil, err + kicker := k.GetSequencer(ctx, msg.GetCreator()) + if !kicker.IsPotentialProposer() { + return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "kicker is not a potential proposer") } - if err := k.Keeper.TryKickProposer(ctx, seq); err != nil { + if err := k.Keeper.TryKickProposer(ctx, kicker); err != nil { return nil, err } diff --git a/x/sequencer/keeper/msg_server_kick_proposer_test.go b/x/sequencer/keeper/msg_server_kick_proposer_test.go index fd447efa1..0a904cbe3 100644 --- a/x/sequencer/keeper/msg_server_kick_proposer_test.go +++ b/x/sequencer/keeper/msg_server_kick_proposer_test.go @@ -7,14 +7,18 @@ import ( ) func (s *SequencerTestSuite) TestKickProposerBasicFlow() { + s.App.RollappKeeper.SetHooks(nil) ra := s.createRollapp() seqAlice := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) s.Require().True(s.k().IsProposer(s.Ctx, seqAlice)) + _, err := s.PostStateUpdate(s.Ctx, ra.RollappId, seqAlice.Address, 1, 10) + s.Require().NoError(err) + // bob tries to kick alice but he doesn't have a sequencer m := &types.MsgKickProposer{Creator: pkAddr(bob)} - _, err := s.msgServer.KickProposer(s.Ctx, m) - utest.IsErr(s.Require(), err, gerrc.ErrNotFound) + _, err = s.msgServer.KickProposer(s.Ctx, m) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) // bob creates a sequencer seqBob := s.createSequencerWithBond(s.Ctx, ra.RollappId, bob, bond) @@ -30,7 +34,7 @@ func (s *SequencerTestSuite) TestKickProposerBasicFlow() { seqBob.Status = types.Bonded s.k().SetSequencer(s.Ctx, seqBob) _, err = s.msgServer.KickProposer(s.Ctx, m) - s.Require().NoError(err) + s.Require().Error(err) s.Require().True(s.k().IsProposer(s.Ctx, seqAlice)) s.Require().False(s.k().IsProposer(s.Ctx, seqBob)) diff --git a/x/sequencer/keeper/msg_server_update.go b/x/sequencer/keeper/msg_server_update.go index 3c1c02aec..6c2cb2a5c 100644 --- a/x/sequencer/keeper/msg_server_update.go +++ b/x/sequencer/keeper/msg_server_update.go @@ -4,7 +4,6 @@ import ( "context" "fmt" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/sdk-utils/utils/uevent" @@ -56,8 +55,11 @@ func (k msgServer) UpdateOptInStatus(goCtx context.Context, k.SetSequencer(ctx, seq) // maybe set as proposer if one is needed - if err := k.ChooseProposer(ctx, seq.RollappId); err != nil { - return nil, errorsmod.Wrap(err, "choose proposer") + proposer := k.GetProposer(ctx, seq.RollappId) + if proposer.Sentinel() { + if err := k.RecoverFromSentinel(ctx, seq.RollappId); err != nil { + return nil, err + } } return &types.MsgUpdateOptInStatus{}, nil } diff --git a/x/sequencer/keeper/proposer.go b/x/sequencer/keeper/proposer.go index 22e26d05c..d561fe0d9 100644 --- a/x/sequencer/keeper/proposer.go +++ b/x/sequencer/keeper/proposer.go @@ -37,90 +37,38 @@ func (k Keeper) RollappPotentialProposers(ctx sdk.Context, rollappId string) []t return append(seqs, k.SentinelSequencer(ctx)) } -// ChooseProposer will assign a proposer to the rollapp. It won't replace the incumbent proposer -// if they are not sentinel. Otherwise it will prioritise a non sentinel successor. Finally, it -// choose one based on an algorithm. -// The result can be the sentinel sequencer. -func (k Keeper) ChooseProposer(ctx sdk.Context, rollapp string) error { +// RecoverFromSentinel will assign a new proposer to the rollapp. +// It will choose a new proposer from the list of potential proposers. +// The rollapp must be halted and with potential proposer available. +func (k Keeper) RecoverFromSentinel(ctx sdk.Context, rollapp string) error { proposer := k.GetProposer(ctx, rollapp) - before := proposer if !proposer.Sentinel() { - if !proposer.Bonded() { - return gerrc.ErrInternal.Wrap("proposer is unbonded - invariant broken") - } - // a valid proposer is already set so there's no need to do anything - return nil - } - successor := k.GetSuccessor(ctx, rollapp) - k.SetProposer(ctx, rollapp, successor.Address) - k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) - if k.GetProposer(ctx, rollapp).Sentinel() { - seqs := k.RollappPotentialProposers(ctx, rollapp) - proposer, err := ProposerChoiceAlgo(seqs) - if err != nil { - return err - } - k.SetProposer(ctx, rollapp, proposer.Address) - } - - after := k.GetProposer(ctx, rollapp) - if before.Address != after.Address { - k.hooks.AfterChooseNewProposer(ctx, rollapp, before, after) - - if err := uevent.EmitTypedEvent(ctx, &types.EventProposerChange{ - Rollapp: rollapp, - Before: before.Address, - After: after.Address, - }); err != nil { - return err - } + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "proposer is not sentinel") } - return nil -} -// ChooseSuccessor will assign a successor. It won't replace an existing one. -// It will prioritise non sentinel -func (k Keeper) chooseSuccessor(ctx sdk.Context, rollapp string) error { - successor := k.GetSuccessor(ctx, rollapp) - if !successor.Sentinel() { - // a valid successor is already set so there's no need to do anything - return nil - } - proposer := k.GetProposer(ctx, rollapp) - if proposer.Sentinel() { - return nil - } - seqs := k.RollappPotentialProposers(ctx, rollapp) - successor, err := ProposerChoiceAlgo(seqs) + successor, err := ProposerChoiceAlgo(k.RollappPotentialProposers(ctx, rollapp)) if err != nil { return err } - k.SetSuccessor(ctx, rollapp, successor.Address) - return nil -} + if successor.Sentinel() { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "no valid proposer found") + } + k.SetProposer(ctx, rollapp, successor.Address) -// ProposerChoiceAlgo : choose the one with most bond -// Requires sentinel to be passed in, as last resort. -func ProposerChoiceAlgo(seqs []types.Sequencer) (types.Sequencer, error) { - if len(seqs) == 0 { - return types.Sequencer{}, gerrc.ErrInternal.Wrap("seqs must at least include sentinel") + err = k.hooks.AfterRecoveryFromHalt(ctx, rollapp, successor) + if err != nil { + return errorsmod.Wrap(err, "recovery from halt callbacks") + } + if err := uevent.EmitTypedEvent(ctx, &types.EventProposerChange{ + Rollapp: rollapp, + Before: types.SentinelSeqAddr, + After: successor.Address, + }); err != nil { + return err } - // slices package is recommended over sort package - slices.SortStableFunc(seqs, func(a, b types.Sequencer) int { - ca := a.TokensCoin() - cb := b.TokensCoin() - if ca.IsEqual(cb) { - return 0 - } - // flipped to sort decreasing - if ca.IsLT(cb) { - return 1 - } - return -1 - }) - return seqs[0], nil + return nil } func (k Keeper) IsProposer(ctx sdk.Context, seq types.Sequencer) bool { diff --git a/x/sequencer/keeper/rotation.go b/x/sequencer/keeper/rotation.go index caff15214..07fc3061f 100644 --- a/x/sequencer/keeper/rotation.go +++ b/x/sequencer/keeper/rotation.go @@ -1,6 +1,7 @@ package keeper import ( + "slices" "strings" "time" @@ -45,7 +46,7 @@ func (k Keeper) ChooseSuccessorForFinishedNotices(ctx sdk.Context, now time.Time } for _, seq := range seqs { k.removeFromNoticeQueue(ctx, seq) - if err := k.chooseSuccessor(ctx, seq.RollappId); err != nil { + if err := k.setSuccessorForRotatingRollapp(ctx, seq.RollappId); err != nil { return errorsmod.Wrap(err, "choose successor") } successor := k.GetSuccessor(ctx, seq.RollappId) @@ -80,17 +81,62 @@ func (k Keeper) OnProposerLastBlock(ctx sdk.Context, proposer types.Sequencer) e return errorsmod.Wrap(gerrc.ErrFault, "sequencer has submitted last block without finishing notice period") } - k.SetProposer(ctx, proposer.RollappId, types.SentinelSeqAddr) - if err := k.ChooseProposer(ctx, proposer.RollappId); err != nil { - return errorsmod.Wrap(err, "choose proposer") + rollapp := proposer.RollappId + + successor := k.GetSuccessor(ctx, rollapp) + k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) // clear successor + k.SetProposer(ctx, rollapp, successor.Address) + + // if proposer is sentinel, prepare new revision for the rollapp + if successor.Sentinel() { + err := k.rollappKeeper.HardForkToLatest(ctx, rollapp) + if err != nil { + return errorsmod.Wrap(err, "hard fork to latest") + } } - after := k.GetProposer(ctx, proposer.RollappId) + ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeProposerRotated, sdk.NewAttribute(types.AttributeKeyRollappId, proposer.RollappId), - sdk.NewAttribute(types.AttributeKeySequencer, after.Address), + sdk.NewAttribute(types.AttributeKeySequencer, successor.Address), ), ) return nil } + +// setSuccessorForRotatingRollapp will assign a successor to the rollapp. +// It will prioritize non sentinel +// called when a proposer has finished their notice period. +func (k Keeper) setSuccessorForRotatingRollapp(ctx sdk.Context, rollapp string) error { + seqs := k.RollappPotentialProposers(ctx, rollapp) + successor, err := ProposerChoiceAlgo(seqs) + if err != nil { + return err + } + k.SetSuccessor(ctx, rollapp, successor.Address) + return nil +} + +// ProposerChoiceAlgo : choose the one with most bond +// Requires sentinel to be passed in, as last resort. +func ProposerChoiceAlgo(seqs []types.Sequencer) (types.Sequencer, error) { + if len(seqs) == 0 { + return types.Sequencer{}, gerrc.ErrInternal.Wrap("seqs must at least include sentinel") + } + // slices package is recommended over sort package + slices.SortStableFunc(seqs, func(a, b types.Sequencer) int { + ca := a.TokensCoin() + cb := b.TokensCoin() + if ca.IsEqual(cb) { + return 0 + } + + // flipped to sort decreasing + if ca.IsLT(cb) { + return 1 + } + return -1 + }) + return seqs[0], nil +} diff --git a/x/sequencer/keeper/rotation_test.go b/x/sequencer/keeper/rotation_test.go index 0468e864b..da1cc1c7e 100644 --- a/x/sequencer/keeper/rotation_test.go +++ b/x/sequencer/keeper/rotation_test.go @@ -49,12 +49,16 @@ func (s *SequencerTestSuite) TestRotationHappyFlow() { // A wants to rotate but there is no B to take over. Proposer should be sentinel afterwards. func (s *SequencerTestSuite) TestRotationNoSuccessor() { + s.App.RollappKeeper.SetHooks(nil) // init ra := s.createRollapp() s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) s.Require().True(s.k().IsProposer(s.Ctx, s.seq(alice))) s.Require().True(s.k().IsSuccessor(s.Ctx, s.k().SentinelSequencer(s.Ctx))) + _, err := s.PostStateUpdate(s.Ctx, ra.RollappId, s.seq(alice).Address, 1, 10) + s.Require().NoError(err) + // proposer tries to unbond mUnbond := &types.MsgUnbond{Creator: pkAddr(alice)} res, err := s.msgServer.Unbond(s.Ctx, mUnbond) diff --git a/x/sequencer/module.go b/x/sequencer/module.go index 3092c7a94..923bdf939 100644 --- a/x/sequencer/module.go +++ b/x/sequencer/module.go @@ -15,6 +15,7 @@ import ( "github.com/grpc-ecosystem/grpc-gateway/runtime" "github.com/spf13/cobra" + simulationtypes "github.com/dymensionxyz/dymension/v3/simulation/types" "github.com/dymensionxyz/dymension/v3/x/sequencer/client/cli" "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" "github.com/dymensionxyz/dymension/v3/x/sequencer/types" @@ -99,20 +100,19 @@ type AppModule struct { AppModuleBasic keeper *keeper.Keeper - accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper + accountKeeper simulationtypes.AccountKeeper + bankKeeper simulationtypes.BankKeeper } func NewAppModule( cdc codec.Codec, keeper *keeper.Keeper, - accountKeeper types.AccountKeeper, - bankKeeper types.BankKeeper, + accountKeeper simulationtypes.AccountKeeper, + bankKeeper simulationtypes.BankKeeper, ) AppModule { return AppModule{ AppModuleBasic: NewAppModuleBasic(cdc), keeper: keeper, - accountKeeper: accountKeeper, bankKeeper: bankKeeper, } } diff --git a/x/sequencer/simulation/create_sequencer.go b/x/sequencer/simulation/create_sequencer.go index 10a3b752f..5d378f5b0 100644 --- a/x/sequencer/simulation/create_sequencer.go +++ b/x/sequencer/simulation/create_sequencer.go @@ -13,10 +13,7 @@ import ( "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) -func SimulateMsgCreateSequencer( - ak types.AccountKeeper, - bk types.BankKeeper, -) simtypes.Operation { +func SimulateMsgCreateSequencer(ak simulationtypes.AccountKeeper, bk simulationtypes.BankKeeper) simtypes.Operation { return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { // choose creator and rollappId diff --git a/x/sequencer/types/expected_keepers.go b/x/sequencer/types/expected_keepers.go index cf7047f26..cf304c8a2 100644 --- a/x/sequencer/types/expected_keepers.go +++ b/x/sequencer/types/expected_keepers.go @@ -13,7 +13,7 @@ type RollappKeeper interface { MustGetRollapp(ctx sdk.Context, rollappId string) rollapptypes.Rollapp GetAllRollapps(ctx sdk.Context) (list []rollapptypes.Rollapp) SetRollappAsLaunched(ctx sdk.Context, rollapp *rollapptypes.Rollapp) error - GetParams(ctx sdk.Context) rollapptypes.Params + HardForkToLatest(ctx sdk.Context, rollappId string) error } // AccountKeeper defines the expected account keeper used for simulations (noalias) diff --git a/x/sequencer/types/hooks.go b/x/sequencer/types/hooks.go index 7a139eb10..f4e616dda 100644 --- a/x/sequencer/types/hooks.go +++ b/x/sequencer/types/hooks.go @@ -3,18 +3,20 @@ package types import sdk "github.com/cosmos/cosmos-sdk/types" type Hooks interface { - AfterChooseNewProposer(ctx sdk.Context, rollapp string, before, after Sequencer) - AfterKickProposer(ctx sdk.Context, kicked Sequencer) + AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, newProposer Sequencer) error + AfterKickProposer(ctx sdk.Context, kicked Sequencer) error } var _ Hooks = NoOpHooks{} type NoOpHooks struct{} -func (n NoOpHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, before, after Sequencer) { +func (n NoOpHooks) AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, newProposer Sequencer) error { + return nil } -func (n NoOpHooks) AfterKickProposer(ctx sdk.Context, kicked Sequencer) { +func (n NoOpHooks) AfterKickProposer(ctx sdk.Context, kicked Sequencer) error { + return nil } var _ Hooks = MultiHooks{} @@ -25,14 +27,22 @@ func NewMultiHooks(hooks ...Hooks) MultiHooks { return MultiHooks(hooks) } -func (m MultiHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, before, after Sequencer) { +func (m MultiHooks) AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, newProposer Sequencer) error { for _, h := range m { - h.AfterChooseNewProposer(ctx, rollapp, before, after) + err := h.AfterRecoveryFromHalt(ctx, rollapp, newProposer) + if err != nil { + return err + } } + return nil } -func (m MultiHooks) AfterKickProposer(ctx sdk.Context, kicked Sequencer) { +func (m MultiHooks) AfterKickProposer(ctx sdk.Context, kicked Sequencer) error { for _, h := range m { - h.AfterKickProposer(ctx, kicked) + err := h.AfterKickProposer(ctx, kicked) + if err != nil { + return err + } } + return nil }