From c658ec519694dfed1230289043fed8f7f41007b1 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Tue, 22 Oct 2024 13:54:30 +0300 Subject: [PATCH 01/68] initial renames according to adr --- testutil/keeper/lightclient.go | 2 +- x/delayedack/keeper/invariants_test.go | 2 +- x/delayedack/rollapp_hooks.go | 2 +- x/dymns/keeper/hooks.go | 2 +- x/lightclient/ante/ibc_msgs_test.go | 2 +- x/lightclient/keeper/hook_listener.go | 2 +- x/lightclient/types/expected_keepers.go | 2 +- x/rollapp/keeper/fraud_handler.go | 196 +++++++++++++++++- x/rollapp/keeper/fraud_handler_test.go | 30 +-- .../msg_server_mark_vulnerable_rollapps.go | 1 + x/rollapp/keeper/rollapp.go | 75 +------ x/rollapp/proposal_handler.go | 2 +- x/rollapp/types/hooks.go | 10 +- x/sequencer/keeper/hook_listener.go | 4 +- x/sequencer/keeper/hooks_test.go | 2 +- 15 files changed, 226 insertions(+), 108 deletions(-) diff --git a/testutil/keeper/lightclient.go b/testutil/keeper/lightclient.go index a20a86126..f2ab7ff8c 100644 --- a/testutil/keeper/lightclient.go +++ b/testutil/keeper/lightclient.go @@ -180,6 +180,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, clientId string, fraudHeight uint64, seqAddr string) error { return nil } diff --git a/x/delayedack/keeper/invariants_test.go b/x/delayedack/keeper/invariants_test.go index 3b5c63abf..1be72ebf9 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -282,7 +282,7 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { // if frozenRollapp true, we should freeze the rollapp and revert pending states if tc.frozenRollapp { - err := suite.App.RollappKeeper.HandleFraud(ctx, rollapp, "", 11, proposer) + err := suite.App.RollappKeeper.HardFork(ctx, rollapp, "", 11, proposer) suite.Require().NoError(err) } diff --git a/x/delayedack/rollapp_hooks.go b/x/delayedack/rollapp_hooks.go index a56360edb..f3905154e 100644 --- a/x/delayedack/rollapp_hooks.go +++ b/x/delayedack/rollapp_hooks.go @@ -8,6 +8,6 @@ import ( var _ rollapptypes.RollappHooks = &IBCMiddleware{} -func (w IBCMiddleware) FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { +func (w IBCMiddleware) OnHardFork(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { return w.HandleFraud(ctx, rollappID, w.IBCModule) } diff --git a/x/dymns/keeper/hooks.go b/x/dymns/keeper/hooks.go index cfb1db8e7..7fb8810e6 100644 --- a/x/dymns/keeper/hooks.go +++ b/x/dymns/keeper/hooks.go @@ -73,7 +73,7 @@ func (h rollappHooks) AfterStateFinalized(_ sdk.Context, _ string, _ *rollapptyp return nil } -func (h rollappHooks) FraudSubmitted(_ sdk.Context, _ string, _ uint64, _ string) error { +func (h rollappHooks) OnHardFork(_ sdk.Context, _ string, _ uint64, _ string) error { return nil } diff --git a/x/lightclient/ante/ibc_msgs_test.go b/x/lightclient/ante/ibc_msgs_test.go index eb8ae92e7..e6713a31a 100644 --- a/x/lightclient/ante/ibc_msgs_test.go +++ b/x/lightclient/ante/ibc_msgs_test.go @@ -53,7 +53,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, clientId string, fraudHeight uint64, seqAddr string) error { return nil } diff --git a/x/lightclient/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index 315419831..b70e25653 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -95,7 +95,7 @@ func (hook rollappHook) checkStateForHeight(ctx sdk.Context, rollappId string, b if err != nil { return err } - err = hook.k.rollappKeeper.HandleFraud(ctx, rollappId, canonicalClient, bd.GetHeight(), sequencerAddress) + err = hook.k.rollappKeeper.HardFork(ctx, rollappId, canonicalClient, bd.GetHeight(), sequencerAddress) if err != nil { return err } diff --git a/x/lightclient/types/expected_keepers.go b/x/lightclient/types/expected_keepers.go index 7acfd4090..43d7b4820 100644 --- a/x/lightclient/types/expected_keepers.go +++ b/x/lightclient/types/expected_keepers.go @@ -23,7 +23,7 @@ type RollappKeeperExpected interface { FindStateInfoByHeight(ctx sdk.Context, rollappId string, height uint64) (*rollapptypes.StateInfo, error) GetStateInfo(ctx sdk.Context, rollappId string, index uint64) (val rollapptypes.StateInfo, found bool) SetRollapp(ctx sdk.Context, rollapp rollapptypes.Rollapp) - HandleFraud(ctx sdk.Context, rollappID, clientId string, fraudHeight uint64, seqAddr string) error + HardFork(ctx sdk.Context, rollappID, clientId string, fraudHeight uint64, seqAddr string) error } type IBCClientKeeperExpected interface { diff --git a/x/rollapp/keeper/fraud_handler.go b/x/rollapp/keeper/fraud_handler.go index 3ae6f5897..d5a7fe554 100644 --- a/x/rollapp/keeper/fraud_handler.go +++ b/x/rollapp/keeper/fraud_handler.go @@ -13,11 +13,13 @@ import ( common "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" ) -// 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) +// HardFork handles the fraud evidence submitted by the user. +func (k Keeper) HardFork(ctx sdk.Context, rollappID, clientID string, fraudHeight uint64, seqAddr string) error { + // validate the request + err := k.validateForkRequest(ctx, rollappID, clientID, fraudHeight, seqAddr) if err != nil { return err } @@ -50,11 +52,14 @@ func (k Keeper) HandleFraud(ctx sdk.Context, rollappID, clientID string, fraudHe } // slash the sequencer, clean delayed packets - err = k.hooks.FraudSubmitted(ctx, rollappID, fraudHeight, seqAddr) + err = k.hooks.OnHardFork(ctx, rollappID, fraudHeight, seqAddr) if err != nil { return err } + // get current sequencer; might be sentinel. + currentSequencer := k.sequencersKeeper.GetCurrentRollapSequencer(ctx, rollappID) + ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeFraud, @@ -68,6 +73,96 @@ func (k Keeper) HandleFraud(ctx sdk.Context, rollappID, clientID string, fraudHe return nil } +// validateForkRequest validates the request for a hard fork. +func (k Keeper) validateForkRequest(ctx sdk.Context, rollappID, clientID string, fraudHeight uint64, seqAddr string) error { + // check the rollapp exists + _, found := k.GetRollapp(ctx, rollappID) + if !found { + return errorsmod.Wrapf(types.ErrUnknownRollappID, "rollapp with ID %s not found", rollappID) + } + + // check the clientID is correct + err := k.verifyClientID(ctx, rollappID, clientID) + if err != nil { + return errors.Join(types.ErrWrongClientId, err) + } + + // check the sequencer is the same as the one in the state info + stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, fraudHeight) + if err != nil { + return err + } + if stateInfo.Sequencer != seqAddr { + return errorsmod.Wrapf(types.ErrWrongProposerAddr, "sequencer address %s does not match the one in the state info", seqAddr) + } + + /* + 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) + } + */ + + return nil +} + +// 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 + } + + /* + // remove state updates + k.removeStateUpdatesUntil(ctx, rollappID, height+1) + + // update revision number + k.modifyRollappForRollback(ctx, &rollapp, mustUpgrade) + */ + + rollapp.Frozen = true + + k.RevertPendingStates(ctx, rollappID) + + 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 +} + // freeze IBC client state func (k Keeper) freezeClientState(ctx sdk.Context, clientId string) error { clientState, ok := k.ibcClientKeeper.GetClientState(ctx, clientId) @@ -114,3 +209,96 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string) { } } } + +// 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 + } +} + +/* + +// removes state updates until the one specified and included +func (k Keeper) removeStateUpdatesUntil(ctx, rollappID, height) { + batch, found := k.getBatchID(ctx, rollappID, height) + // if batch not found we revert nothing, no rollbacks fundamentally. + if !found { + return + } + + lastBatch := k.lastBatch(ctx, rollappID) + // remove batches until the rollback one + for cursor := batch.Id; cursor <= lastBatch.Id; cursor++ { + k.removeBatch(ctx, rollappID, cursor) + } + // remove block descriptors until the one we need to rollback to. + for { + bd := batch.BDs.Pop() + if bd.Height < height { + break + } + } + if batch.BDs.len() == 0 { + // no more blocks in the faulty batch means remove it + k.removeBatch(ctx, rollappID, batch.Id) + } else { + // this means we need to truncate the batch + // which also becomes the last batch. + k.setBatch(ctx, rollappID, batch) + } +} + + + +func (k Keeper) modifyRollappForRollback(ctx, *rollapp, mustUpgrade) { + rollapp.RevisionNumber += 1 + rollapp.LastHubUpdate = ctx.Height() // marks the last update done by the hub + // other things are needed for liveness slashing, refer to the spec: https://www.notion.so/dymension/sequencer-jailing-slashing-3455fe70923143cbbfd8f96d71deb583 + rollapp.LivenessHeight = TODO // dependent on liveness slashing + + if mustUpgrade { + lastStateUpdate := k.GetLastStateUpda + rollapp.FaultyDRS = lastStateUpdate.BDs[last].DrsVersion + } +} + +*/ diff --git a/x/rollapp/keeper/fraud_handler_test.go b/x/rollapp/keeper/fraud_handler_test.go index c73d1fbd2..cabef7bcc 100644 --- a/x/rollapp/keeper/fraud_handler_test.go +++ b/x/rollapp/keeper/fraud_handler_test.go @@ -11,7 +11,7 @@ import ( // - reverted states // - cleared queue -func (suite *RollappTestSuite) TestHandleFraud() { +func (suite *RollappTestSuite) TestHardFork() { var err error ctx := &suite.Ctx @@ -52,14 +52,14 @@ func (suite *RollappTestSuite) TestHandleFraud() { // assert before fraud submission suite.assertBeforeFraud(rollapp, fraudHeight) - err = keeper.HandleFraud(*ctx, rollapp, "", fraudHeight, proposer) + err = keeper.HardFork(*ctx, rollapp, "", fraudHeight, proposer) suite.Require().Nil(err) suite.assertFraudHandled(rollapp) } // Fail - Invalid rollapp -func (suite *RollappTestSuite) TestHandleFraud_InvalidRollapp() { +func (suite *RollappTestSuite) TestHardFork_InvalidRollapp() { ctx := &suite.Ctx keeper := suite.App.RollappKeeper @@ -67,12 +67,12 @@ func (suite *RollappTestSuite) TestHandleFraud_InvalidRollapp() { _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) suite.Require().Nil(err) - err = keeper.HandleFraud(*ctx, "invalidRollapp", "", 2, proposer) + err = keeper.HardFork(*ctx, "invalidRollapp", "", 2, proposer) suite.Require().NotNil(err) } // Fail - Wrong height -func (suite *RollappTestSuite) TestHandleFraud_WrongHeight() { +func (suite *RollappTestSuite) TestHardFork_WrongHeight() { ctx := &suite.Ctx keeper := suite.App.RollappKeeper @@ -80,12 +80,12 @@ func (suite *RollappTestSuite) TestHandleFraud_WrongHeight() { _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) suite.Require().Nil(err) - err = keeper.HandleFraud(*ctx, rollapp, "", 100, proposer) + err = keeper.HardFork(*ctx, rollapp, "", 100, proposer) suite.Require().NotNil(err) } // Fail - Wrong sequencer address -func (suite *RollappTestSuite) TestHandleFraud_WrongSequencer() { +func (suite *RollappTestSuite) TestHardFork_WrongSequencer() { ctx := &suite.Ctx keeper := suite.App.RollappKeeper @@ -93,12 +93,12 @@ func (suite *RollappTestSuite) TestHandleFraud_WrongSequencer() { _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) suite.Require().Nil(err) - err = keeper.HandleFraud(*ctx, rollapp, "", 2, "wrongSequencer") + err = keeper.HardFork(*ctx, rollapp, "", 2, "wrongSequencer") suite.Require().NotNil(err) } // Fail - Wrong channel-ID -func (suite *RollappTestSuite) TestHandleFraud_WrongChannelID() { +func (suite *RollappTestSuite) TestHardFork_WrongChannelID() { ctx := &suite.Ctx keeper := suite.App.RollappKeeper @@ -106,12 +106,12 @@ func (suite *RollappTestSuite) TestHandleFraud_WrongChannelID() { _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) suite.Require().Nil(err) - err = keeper.HandleFraud(*ctx, rollapp, "wrongChannelID", 2, proposer) + err = keeper.HardFork(*ctx, rollapp, "wrongChannelID", 2, proposer) suite.Require().NotNil(err) } // Fail - Disputing already reverted state -func (suite *RollappTestSuite) TestHandleFraud_AlreadyReverted() { +func (suite *RollappTestSuite) TestHardFork_AlreadyReverted() { var err error ctx := &suite.Ctx keeper := suite.App.RollappKeeper @@ -132,15 +132,15 @@ func (suite *RollappTestSuite) TestHandleFraud_AlreadyReverted() { suite.Ctx = suite.Ctx.WithBlockHeight(suite.Ctx.BlockHeader().Height + 1) } - err = keeper.HandleFraud(*ctx, rollapp, "", 11, proposer) + err = keeper.HardFork(*ctx, rollapp, "", 11, proposer) suite.Require().Nil(err) - err = keeper.HandleFraud(*ctx, rollapp, "", 1, proposer) + err = keeper.HardFork(*ctx, rollapp, "", 1, proposer) suite.Require().NotNil(err) } // Fail - Disputing already finalized state -func (suite *RollappTestSuite) TestHandleFraud_AlreadyFinalized() { +func (suite *RollappTestSuite) TestHardFork_AlreadyFinalized() { ctx := &suite.Ctx keeper := suite.App.RollappKeeper @@ -155,7 +155,7 @@ func (suite *RollappTestSuite) TestHandleFraud_AlreadyFinalized() { suite.Require().Nil(err) suite.Require().Equal(common.Status_FINALIZED, stateInfo.Status) - err = keeper.HandleFraud(*ctx, rollapp, "", 2, proposer) + err = keeper.HardFork(*ctx, rollapp, "", 2, proposer) suite.Require().NotNil(err) } diff --git a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go index 3fc4120e6..3e8da8fa0 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go +++ b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go @@ -75,6 +75,7 @@ func (k Keeper) MarkVulnerableRollapps(ctx sdk.Context, drsVersions []string) (i if vulnerable { err := k.MarkRollappAsVulnerable(ctx, rollapp.RollappId) if err != nil { + // FIXME: should continue to other rollapps if one fails return 0, fmt.Errorf("freeze rollapp: %w", err) } vulnerableNum++ diff --git a/x/rollapp/keeper/rollapp.go b/x/rollapp/keeper/rollapp.go index d6e413037..b0548cf9c 100644 --- a/x/rollapp/keeper/rollapp.go +++ b/x/rollapp/keeper/rollapp.go @@ -246,80 +246,7 @@ func (k Keeper) IsRollappStarted(ctx sdk.Context, rollappId string) bool { } 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 - - k.RevertPendingStates(ctx, rollappID) - - 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 - } + return k.HardFork(ctx, rollappId, "vulnerability", 0, "") // FIXME: use a proper hard fork version } func (k Keeper) FilterRollapps(ctx sdk.Context, f func(types.Rollapp) bool) []types.Rollapp { diff --git a/x/rollapp/proposal_handler.go b/x/rollapp/proposal_handler.go index e0659d56f..691f5032c 100644 --- a/x/rollapp/proposal_handler.go +++ b/x/rollapp/proposal_handler.go @@ -23,7 +23,7 @@ func NewRollappProposalHandler(k *keeper.Keeper) govtypes.Handler { } func HandleSubmitFraudProposal(ctx sdk.Context, k *keeper.Keeper, p *types.SubmitFraudProposal) error { - err := k.HandleFraud(ctx, p.RollappId, p.IbcClientId, p.FraudelentHeight, p.FraudelentSequencerAddress) + err := k.HardFork(ctx, p.RollappId, p.IbcClientId, p.FraudelentHeight, p.FraudelentSequencerAddress) if err != nil { return err } diff --git a/x/rollapp/types/hooks.go b/x/rollapp/types/hooks.go index f9eafb2b1..9a59a5b72 100644 --- a/x/rollapp/types/hooks.go +++ b/x/rollapp/types/hooks.go @@ -14,9 +14,11 @@ 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, seqAddr string) error + // OnHardFork(ctx, rollappID string, newValidHeight uint64, revisionNumber uint64) error } var _ RollappHooks = MultiRollappHooks{} @@ -59,9 +61,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, height uint64, seqAddr string) error { for i := range h { - err := h[i].FraudSubmitted(ctx, rollappID, height, seqAddr) + err := h[i].OnHardFork(ctx, rollappID, height, seqAddr) if err != nil { return err } @@ -102,7 +104,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, string) error { return nil } func (StubRollappCreatedHooks) AfterStateFinalized(sdk.Context, string, *StateInfo) error { return nil } diff --git a/x/sequencer/keeper/hook_listener.go b/x/sequencer/keeper/hook_listener.go index 3df807374..224b4d89a 100644 --- a/x/sequencer/keeper/hook_listener.go +++ b/x/sequencer/keeper/hook_listener.go @@ -48,9 +48,9 @@ func (hook rollappHook) BeforeUpdateState(ctx sdk.Context, seqAddr, rollappId st return nil } -// FraudSubmitted implements the RollappHooks interface +// OnHardFork implements the RollappHooks interface // It slashes the sequencer and unbonds all other bonded sequencers -func (hook rollappHook) FraudSubmitted(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { err := hook.k.JailSequencerOnFraud(ctx, seqAddr) if err != nil { return err diff --git a/x/sequencer/keeper/hooks_test.go b/x/sequencer/keeper/hooks_test.go index 50bc4918b..f1c266435 100644 --- a/x/sequencer/keeper/hooks_test.go +++ b/x/sequencer/keeper/hooks_test.go @@ -40,7 +40,7 @@ func (suite *SequencerTestSuite) TestFraudSubmittedHook() { bds := keeper.GetMatureDecreasingBondIDs(suite.Ctx, resp.GetCompletionTime()) suite.Require().Len(bds, 1) - err = keeper.RollappHooks().FraudSubmitted(suite.Ctx, rollappId, 0, proposer) + err = keeper.RollappHooks().OnHardFork(suite.Ctx, rollappId, 0, proposer) suite.Require().NoError(err) // check if proposer is slashed From 777dc3242052c8f1b4943512b67d23075b38e6ef Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Tue, 22 Oct 2024 16:36:58 +0300 Subject: [PATCH 02/68] reverting states --- testutil/keeper/lightclient.go | 2 +- x/delayedack/keeper/invariants_test.go | 2 +- x/delayedack/rollapp_hooks.go | 2 +- x/dymns/keeper/hooks.go | 2 +- x/lightclient/ante/ibc_msgs_test.go | 2 +- x/lightclient/keeper/hook_listener.go | 5 +- x/lightclient/types/expected_keepers.go | 2 +- x/rollapp/keeper/fraud_handler.go | 309 ++++++---------------- x/rollapp/keeper/grpc_query_state_info.go | 16 +- x/rollapp/keeper/rollapp.go | 2 +- x/rollapp/proposal_handler.go | 4 +- x/rollapp/types/hooks.go | 8 +- x/sequencer/keeper/hook_listener.go | 24 +- x/sequencer/keeper/hooks_test.go | 2 +- 14 files changed, 117 insertions(+), 265 deletions(-) diff --git a/testutil/keeper/lightclient.go b/testutil/keeper/lightclient.go index f2ab7ff8c..6c56767b3 100644 --- a/testutil/keeper/lightclient.go +++ b/testutil/keeper/lightclient.go @@ -180,6 +180,6 @@ func (m *MockRollappKeeper) GetStateInfo(ctx sdk.Context, rollappId string, inde func (m *MockRollappKeeper) SetRollapp(ctx sdk.Context, rollapp rollapptypes.Rollapp) { } -func (m *MockRollappKeeper) HardFork(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/x/delayedack/keeper/invariants_test.go b/x/delayedack/keeper/invariants_test.go index 1be72ebf9..dae550a6e 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -282,7 +282,7 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { // if frozenRollapp true, we should freeze the rollapp and revert pending states if tc.frozenRollapp { - err := suite.App.RollappKeeper.HardFork(ctx, rollapp, "", 11, proposer) + err := suite.App.RollappKeeper.HardFork(ctx, rollapp, 11) suite.Require().NoError(err) } diff --git a/x/delayedack/rollapp_hooks.go b/x/delayedack/rollapp_hooks.go index f3905154e..7a4a12a7a 100644 --- a/x/delayedack/rollapp_hooks.go +++ b/x/delayedack/rollapp_hooks.go @@ -8,6 +8,6 @@ import ( var _ rollapptypes.RollappHooks = &IBCMiddleware{} -func (w IBCMiddleware) OnHardFork(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { +func (w IBCMiddleware) OnHardFork(ctx sdk.Context, rollappID string, height uint64) error { return w.HandleFraud(ctx, rollappID, w.IBCModule) } diff --git a/x/dymns/keeper/hooks.go b/x/dymns/keeper/hooks.go index 7fb8810e6..e384f9bb8 100644 --- a/x/dymns/keeper/hooks.go +++ b/x/dymns/keeper/hooks.go @@ -73,7 +73,7 @@ func (h rollappHooks) AfterStateFinalized(_ sdk.Context, _ string, _ *rollapptyp return nil } -func (h rollappHooks) OnHardFork(_ sdk.Context, _ string, _ uint64, _ string) error { +func (h rollappHooks) OnHardFork(_ sdk.Context, _ string, _ uint64) error { return nil } diff --git a/x/lightclient/ante/ibc_msgs_test.go b/x/lightclient/ante/ibc_msgs_test.go index e6713a31a..d296f9ff7 100644 --- a/x/lightclient/ante/ibc_msgs_test.go +++ b/x/lightclient/ante/ibc_msgs_test.go @@ -53,7 +53,7 @@ func (m *MockRollappKeeper) GetStateInfo(ctx sdk.Context, rollappId string, inde return val, found } -func (m *MockRollappKeeper) HardFork(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/x/lightclient/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index b70e25653..5ea68f667 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -95,7 +95,10 @@ func (hook rollappHook) checkStateForHeight(ctx sdk.Context, rollappId string, b if err != nil { return err } - err = hook.k.rollappKeeper.HardFork(ctx, rollappId, canonicalClient, bd.GetHeight(), sequencerAddress) + // FIXME: punish the sequencer + hook.k.sequencerKeeper.JailSequencer(ctx, sequencerAddress) + + err = hook.k.rollappKeeper.HardFork(ctx, rollappId, bd.GetHeight()) if err != nil { return err } diff --git a/x/lightclient/types/expected_keepers.go b/x/lightclient/types/expected_keepers.go index 43d7b4820..63f5b4184 100644 --- a/x/lightclient/types/expected_keepers.go +++ b/x/lightclient/types/expected_keepers.go @@ -23,7 +23,7 @@ type RollappKeeperExpected interface { FindStateInfoByHeight(ctx sdk.Context, rollappId string, height uint64) (*rollapptypes.StateInfo, error) GetStateInfo(ctx sdk.Context, rollappId string, index uint64) (val rollapptypes.StateInfo, found bool) SetRollapp(ctx sdk.Context, rollapp rollapptypes.Rollapp) - HardFork(ctx sdk.Context, rollappID, clientId string, fraudHeight uint64, seqAddr string) error + HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error } type IBCClientKeeperExpected interface { diff --git a/x/rollapp/keeper/fraud_handler.go b/x/rollapp/keeper/fraud_handler.go index d5a7fe554..d32adbe1e 100644 --- a/x/rollapp/keeper/fraud_handler.go +++ b/x/rollapp/keeper/fraud_handler.go @@ -1,190 +1,81 @@ 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" "github.com/dymensionxyz/gerr-cosmos/gerrc" ) // HardFork handles the fraud evidence submitted by the user. -func (k Keeper) HardFork(ctx sdk.Context, rollappID, clientID string, fraudHeight uint64, seqAddr string) error { - // validate the request - err := k.validateForkRequest(ctx, rollappID, clientID, fraudHeight, seqAddr) - 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) +func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error { + rollapp, found := k.GetRollapp(ctx, rollappID) + if !found { + return gerrc.ErrNotFound } - // check that the clientID is correct - err = k.verifyClientID(ctx, rollappID, clientID) + err := k.RevertPendingStates(ctx, rollappID, fraudHeight) if err != nil { - return errors.Join(types.ErrWrongClientId, err) + return errorsmod.Wrap(err, "revert pending states") } - // freeze the rollapp and revert all pending states - err = k.FreezeRollapp(ctx, rollappID) - if err != nil { - return fmt.Errorf("freeze rollapp: %w", err) - } + // update revision number + // rollapp.RevisionNumber += 1 + // fixme: set liveness height + + rollapp.Frozen = true + k.SetRollapp(ctx, rollapp) // slash the sequencer, clean delayed packets - err = k.hooks.OnHardFork(ctx, rollappID, fraudHeight, seqAddr) + err = k.hooks.OnHardFork(ctx, rollappID, fraudHeight) if err != nil { return err } - // get current sequencer; might be sentinel. - currentSequencer := k.sequencersKeeper.GetCurrentRollapSequencer(ctx, rollappID) - 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 } -// validateForkRequest validates the request for a hard fork. -func (k Keeper) validateForkRequest(ctx sdk.Context, rollappID, clientID string, fraudHeight uint64, seqAddr string) error { - // check the rollapp exists - _, found := k.GetRollapp(ctx, rollappID) - if !found { - return errorsmod.Wrapf(types.ErrUnknownRollappID, "rollapp with ID %s not found", rollappID) - } - - // check the clientID is correct - err := k.verifyClientID(ctx, rollappID, clientID) - if err != nil { - return errors.Join(types.ErrWrongClientId, err) - } - - // check the sequencer is the same as the one in the state info +// removes state updates until the one specified and included +func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeight uint64) error { + // find the affected state info index + // skip if not found (height not committed yet) stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, fraudHeight) - if err != nil { + if errorsmod.IsOf(err, gerrc.ErrNotFound) { + return nil + } else if err != nil { return err } - if stateInfo.Sequencer != seqAddr { - return errorsmod.Wrapf(types.ErrWrongProposerAddr, "sequencer address %s does not match the one in the state info", seqAddr) - } - - /* - 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) - } - */ - - return nil -} - -// 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 - } - - /* - // remove state updates - k.removeStateUpdatesUntil(ctx, rollappID, height+1) - - // update revision number - k.modifyRollappForRollback(ctx, &rollapp, mustUpgrade) - */ - - rollapp.Frozen = true - k.RevertPendingStates(ctx, rollappID) - - 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 -} - -// 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) + // 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) } - tmClientState, ok := clientState.(*cometbfttypes.ClientState) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidClientState, "client state with ID %s is not a tendermint client state", clientId) + // trunc the state info if needed + err = k.TruncStateInfo(ctx, stateInfo, fraudHeight) + if err != nil { + return errorsmod.Wrap(err, "trunc state info") } - tmClientState.FrozenHeight = clienttypes.NewHeight(tmClientState.GetLatestHeight().GetRevisionHeight(), tmClientState.GetLatestHeight().GetRevisionNumber()) - k.ibcClientKeeper.SetClientState(ctx, clientId, tmClientState) + lastIdxToKeep := stateInfo.StateInfoIndex.Index - return nil -} - -// revert all pending states of a rollapp -func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string) { // TODO (#631): Prefix store by rollappID for efficient querying queuePerHeight := k.GetAllBlockHeightToFinalizationQueue(ctx) + revertedCount := 0 // Counter for reverted state updates + for _, queue := range queuePerHeight { leftPendingStates := []types.StateInfoIndex{} for _, stateInfoIndex := range queue.FinalizationQueue { @@ -194,111 +85,61 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string) { continue } - stateInfo, _ := k.GetStateInfo(ctx, stateInfoIndex.RollappId, stateInfoIndex.Index) - stateInfo.Status = common.Status_REVERTED - k.SetStateInfo(ctx, stateInfo) + // keep state info indexes with index less than the rollback index + if stateInfoIndex.Index <= lastIdxToKeep { + leftPendingStates = append(leftPendingStates, stateInfoIndex) + continue + } + + // keep pending packets with height less than the rollback height + k.RemoveStateInfo(ctx, stateInfoIndex.RollappId, stateInfoIndex.Index) + revertedCount++ // Increment the counter + } + + // no change in the queue + if len(leftPendingStates) == len(queue.FinalizationQueue) { + continue } + // remove the queue if no pending states left if len(leftPendingStates) == 0 { k.RemoveBlockHeightToFinalizationQueue(ctx, queue.CreationHeight) - } else { - k.SetBlockHeightToFinalizationQueue(ctx, types.BlockHeightToFinalizationQueue{ - CreationHeight: queue.CreationHeight, - FinalizationQueue: leftPendingStates, - }) + continue } - } -} - -// 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 + // update the queue after removing the reverted states + k.SetBlockHeightToFinalizationQueue(ctx, types.BlockHeightToFinalizationQueue{ + CreationHeight: queue.CreationHeight, + FinalizationQueue: leftPendingStates, + }) } -} - -/* -// removes state updates until the one specified and included -func (k Keeper) removeStateUpdatesUntil(ctx, rollappID, height) { - batch, found := k.getBatchID(ctx, rollappID, height) - // if batch not found we revert nothing, no rollbacks fundamentally. - if !found { - return - } + ctx.Logger().Info(fmt.Sprintf("Reverted state updates for rollapp: %s, count: %d", rollappID, revertedCount)) - lastBatch := k.lastBatch(ctx, rollappID) - // remove batches until the rollback one - for cursor := batch.Id; cursor <= lastBatch.Id; cursor++ { - k.removeBatch(ctx, rollappID, cursor) - } - // remove block descriptors until the one we need to rollback to. - for { - bd := batch.BDs.Pop() - if bd.Height < height { - break - } - } - if batch.BDs.len() == 0 { - // no more blocks in the faulty batch means remove it - k.removeBatch(ctx, rollappID, batch.Id) - } else { - // this means we need to truncate the batch - // which also becomes the last batch. - k.setBatch(ctx, rollappID, batch) - } + return nil } +// trunc fraudelent state info +func (k Keeper) TruncStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) error { + return nil - -func (k Keeper) modifyRollappForRollback(ctx, *rollapp, mustUpgrade) { - rollapp.RevisionNumber += 1 - rollapp.LastHubUpdate = ctx.Height() // marks the last update done by the hub - // other things are needed for liveness slashing, refer to the spec: https://www.notion.so/dymension/sequencer-jailing-slashing-3455fe70923143cbbfd8f96d71deb583 - rollapp.LivenessHeight = TODO // dependent on liveness slashing - - if mustUpgrade { - lastStateUpdate := k.GetLastStateUpda - rollapp.FaultyDRS = lastStateUpdate.BDs[last].DrsVersion - } + /* + // heightToKeep := fraudHeight + 1 + + // remove block descriptors until the one we need to rollback to. + for { + bd := batch.BDs.Pop() + if bd.Height < height { + break + } + } + if batch.BDs.len() == 0 { + // no more blocks in the faulty batch means remove it + k.removeBatch(ctx, rollappID, batch.Id) + } else { + // this means we need to truncate the batch + // which also becomes the last batch. + k.setBatch(ctx, rollappID, batch) + } + */ } - -*/ diff --git a/x/rollapp/keeper/grpc_query_state_info.go b/x/rollapp/keeper/grpc_query_state_info.go index b0d228e60..e4e3514b6 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 { - return nil, errorsmod.Wrapf(types.ErrNotFound, + // 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: startInfo should start at least with last unpruned hight (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/rollapp.go b/x/rollapp/keeper/rollapp.go index b0548cf9c..f7abf5183 100644 --- a/x/rollapp/keeper/rollapp.go +++ b/x/rollapp/keeper/rollapp.go @@ -246,7 +246,7 @@ func (k Keeper) IsRollappStarted(ctx sdk.Context, rollappId string) bool { } func (k Keeper) MarkRollappAsVulnerable(ctx sdk.Context, rollappId string) error { - return k.HardFork(ctx, rollappId, "vulnerability", 0, "") // FIXME: use a proper hard fork version + return k.HardFork(ctx, rollappId, 0) // FIXME: use a proper hard fork version } func (k Keeper) FilterRollapps(ctx sdk.Context, f func(types.Rollapp) bool) []types.Rollapp { diff --git a/x/rollapp/proposal_handler.go b/x/rollapp/proposal_handler.go index 691f5032c..d10bb1535 100644 --- a/x/rollapp/proposal_handler.go +++ b/x/rollapp/proposal_handler.go @@ -23,7 +23,9 @@ func NewRollappProposalHandler(k *keeper.Keeper) govtypes.Handler { } func HandleSubmitFraudProposal(ctx sdk.Context, k *keeper.Keeper, p *types.SubmitFraudProposal) error { - err := k.HardFork(ctx, p.RollappId, p.IbcClientId, p.FraudelentHeight, p.FraudelentSequencerAddress) + // FIXME: jail the sequencer + + err := k.HardFork(ctx, p.RollappId, p.FraudelentHeight) if err != nil { return err } diff --git a/x/rollapp/types/hooks.go b/x/rollapp/types/hooks.go index 9a59a5b72..2f247eac6 100644 --- a/x/rollapp/types/hooks.go +++ b/x/rollapp/types/hooks.go @@ -17,7 +17,7 @@ type RollappHooks interface { 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, seqAddr string) error + OnHardFork(ctx sdk.Context, rollappID string, height uint64) error // OnHardFork(ctx, rollappID string, newValidHeight uint64, revisionNumber uint64) error } @@ -61,9 +61,9 @@ func (h MultiRollappHooks) AfterStateFinalized(ctx sdk.Context, rollappID string return nil } -func (h MultiRollappHooks) OnHardFork(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { +func (h MultiRollappHooks) OnHardFork(ctx sdk.Context, rollappID string, height uint64) error { for i := range h { - err := h[i].OnHardFork(ctx, rollappID, height, seqAddr) + err := h[i].OnHardFork(ctx, rollappID, height) if err != nil { return err } @@ -104,7 +104,7 @@ func (StubRollappCreatedHooks) BeforeUpdateState(sdk.Context, string, string, bo func (StubRollappCreatedHooks) AfterUpdateState(sdk.Context, string, *StateInfo) error { return nil } -func (StubRollappCreatedHooks) OnHardFork(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/sequencer/keeper/hook_listener.go b/x/sequencer/keeper/hook_listener.go index 224b4d89a..38f480f2c 100644 --- a/x/sequencer/keeper/hook_listener.go +++ b/x/sequencer/keeper/hook_listener.go @@ -50,17 +50,21 @@ func (hook rollappHook) BeforeUpdateState(ctx sdk.Context, seqAddr, rollappId st // OnHardFork implements the RollappHooks interface // It slashes the sequencer and unbonds all other bonded sequencers -func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappID string, height uint64, seqAddr string) error { - err := hook.k.JailSequencerOnFraud(ctx, seqAddr) - if err != nil { - return err - } +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappID string, height uint64) error { - // unbond all other other rollapp sequencers - err = hook.k.InstantUnbondAllSequencers(ctx, rollappID) - if err != nil { - return err - } + // FIXME: probably need to validate we have active proposer + /* + err := hook.k.JailSequencerOnFraud(ctx, seqAddr) + if err != nil { + return err + } + + // unbond all other other rollapp sequencers + err = hook.k.InstantUnbondAllSequencers(ctx, rollappID) + if err != nil { + return err + } + */ return nil } diff --git a/x/sequencer/keeper/hooks_test.go b/x/sequencer/keeper/hooks_test.go index f1c266435..0f5836168 100644 --- a/x/sequencer/keeper/hooks_test.go +++ b/x/sequencer/keeper/hooks_test.go @@ -40,7 +40,7 @@ func (suite *SequencerTestSuite) TestFraudSubmittedHook() { bds := keeper.GetMatureDecreasingBondIDs(suite.Ctx, resp.GetCompletionTime()) suite.Require().Len(bds, 1) - err = keeper.RollappHooks().OnHardFork(suite.Ctx, rollappId, 0, proposer) + err = keeper.RollappHooks().OnHardFork(suite.Ctx, rollappId, 0) suite.Require().NoError(err) // check if proposer is slashed From b713df3ccfb63b8f202157554d7efb6f19b3a5c9 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Tue, 22 Oct 2024 17:30:48 +0300 Subject: [PATCH 03/68] removed frozen notation. added revision number in rollapp object --- app/upgrades/v4/upgrade.go | 2 +- ibctesting/light_client_test.go | 4 +- .../dymension/rollapp/rollapp.proto | 8 +- testutil/keeper/lightclient.go | 4 + x/delayedack/keeper/invariants.go | 14 +- x/lightclient/keeper/hook_listener.go | 2 +- x/lightclient/types/expected_keepers.go | 1 + x/rollapp/keeper/fraud_handler.go | 4 +- x/rollapp/keeper/invariants.go | 3 - .../msg_server_mark_vulnerable_rollapps.go | 3 +- .../keeper/msg_server_transfer_ownership.go | 4 - .../msg_server_transfer_ownership_test.go | 10 - x/rollapp/keeper/msg_server_update_state.go | 6 - x/rollapp/keeper/rollapp.go | 28 +-- x/rollapp/types/rollapp.go | 4 - x/rollapp/types/rollapp.pb.go | 177 +++++++++--------- .../keeper/msg_server_create_sequencer.go | 4 - .../keeper/msg_server_update_sequencer.go | 5 - .../msg_server_update_sequencer_test.go | 12 -- 19 files changed, 113 insertions(+), 182 deletions(-) diff --git a/app/upgrades/v4/upgrade.go b/app/upgrades/v4/upgrade.go index 7fc295229..08748a275 100644 --- a/app/upgrades/v4/upgrade.go +++ b/app/upgrades/v4/upgrade.go @@ -221,7 +221,6 @@ func ConvertOldRollappToNew(oldRollapp rollapptypes.Rollapp) rollapptypes.Rollap Owner: oldRollapp.Owner, GenesisState: oldRollapp.GenesisState, ChannelId: oldRollapp.ChannelId, - Frozen: oldRollapp.Frozen, RegisteredDenoms: oldRollapp.RegisteredDenoms, // TODO: regarding missing data - https://github.com/dymensionxyz/dymension/issues/986 VmType: rollapptypes.Rollapp_EVM, // placeholder data @@ -249,6 +248,7 @@ func ConvertOldRollappToNew(oldRollapp rollapptypes.Rollapp) rollapptypes.Rollap }, InitialSequencer: "*", Launched: true, + RevisionNumber: 1, } } diff --git a/ibctesting/light_client_test.go b/ibctesting/light_client_test.go index cc71a747e..929f8fd3e 100644 --- a/ibctesting/light_client_test.go +++ b/ibctesting/light_client_test.go @@ -347,5 +347,7 @@ func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_NotCompat s.False(found) // Ensuring that the rollapp is now frozen as part of fraud handling rollapp, _ := s.hubApp().RollappKeeper.GetRollapp(s.hubCtx(), s.rollappChain().ChainID) - s.True(rollapp.Frozen) + s.Equal(2, rollapp.RevisionNumber) + + // FIXME: better test for fraud handling } diff --git a/proto/dymensionxyz/dymension/rollapp/rollapp.proto b/proto/dymensionxyz/dymension/rollapp/rollapp.proto index 74d92f64f..a95b0438e 100644 --- a/proto/dymensionxyz/dymension/rollapp/rollapp.proto +++ b/proto/dymensionxyz/dymension/rollapp/rollapp.proto @@ -41,8 +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 9; + // registeredDenoms is a list of registered denom bases on this rollapp repeated string registeredDenoms = 10; // metadata is the rollapp metadata @@ -75,6 +76,9 @@ 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 from 1 + int64 revision_number = 19; } // Rollapp summary is a compact representation of Rollapp diff --git a/testutil/keeper/lightclient.go b/testutil/keeper/lightclient.go index 6c56767b3..b65c0f99e 100644 --- a/testutil/keeper/lightclient.go +++ b/testutil/keeper/lightclient.go @@ -159,6 +159,10 @@ func (m *MockSequencerKeeper) GetSequencersByRollapp(ctx sdk.Context, rollappId return seqs } +func (m *MockSequencerKeeper) JailSequencerOnFraud(ctx sdk.Context, seqAddr string) error { + return nil +} + type MockRollappKeeper struct{} func NewMockRollappKeeper() *MockRollappKeeper { diff --git a/x/delayedack/keeper/invariants.go b/x/delayedack/keeper/invariants.go index f68cc2ffa..9f36d4fd8 100644 --- a/x/delayedack/keeper/invariants.go +++ b/x/delayedack/keeper/invariants.go @@ -25,23 +25,23 @@ func (k Keeper) RegisterInvariants(ir sdk.InvariantRegistry) { // 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) + return k.packetsCorrespondsToStatusHeight(checkFinalizedPackets)(ctx) } // PacketsFromRevertedHeightsAreReverted checks that all rollapp packets stored are set to // reverted status for all heights up to the latest height // Check if the rollapp is frozen func (k Keeper) PacketsFromRevertedHeightsAreReverted(ctx sdk.Context) (string, bool) { - return k.packetsCorrespondsToStatusHeight(checkRevertedPackets, true)(ctx) + return k.packetsCorrespondsToStatusHeight(checkRevertedPackets)(ctx) } 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 { +func (k Keeper) packetsCorrespondsToStatusHeight(checkPackets checkPacketsFn) sdk.Invariant { return func(ctx sdk.Context) (msg string, stop bool) { for _, rollapp := range k.rollappKeeper.GetAllRollapps(ctx) { - msg = k.checkRollapp(ctx, rollapp, checkPackets, checkRollappFrozen) + msg = k.checkRollapp(ctx, rollapp, checkPackets) if stop = msg != ""; stop { break } @@ -51,11 +51,7 @@ func (k Keeper) packetsCorrespondsToStatusHeight(checkPackets checkPacketsFn, ch } } -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, checkPackets checkPacketsFn) (msg string) { // will stay 0 if no state is found // but will still check packets var latestFinalizedHeight uint64 diff --git a/x/lightclient/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index 5ea68f667..35d2d807d 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -96,7 +96,7 @@ func (hook rollappHook) checkStateForHeight(ctx sdk.Context, rollappId string, b return err } // FIXME: punish the sequencer - hook.k.sequencerKeeper.JailSequencer(ctx, sequencerAddress) + hook.k.sequencerKeeper.JailSequencerOnFraud(ctx, sequencerAddress) err = hook.k.rollappKeeper.HardFork(ctx, rollappId, bd.GetHeight()) if err != nil { diff --git a/x/lightclient/types/expected_keepers.go b/x/lightclient/types/expected_keepers.go index 63f5b4184..2bdc2bf2f 100644 --- a/x/lightclient/types/expected_keepers.go +++ b/x/lightclient/types/expected_keepers.go @@ -16,6 +16,7 @@ type SequencerKeeperExpected interface { GetSequencer(ctx sdk.Context, sequencerAddress string) (val sequencertypes.Sequencer, found bool) GetSequencersByRollapp(ctx sdk.Context, rollappId string) (list []sequencertypes.Sequencer) UnbondingTime(ctx sdk.Context) (res time.Duration) + JailSequencerOnFraud(ctx sdk.Context, sequencerAddress string) error } type RollappKeeperExpected interface { diff --git a/x/rollapp/keeper/fraud_handler.go b/x/rollapp/keeper/fraud_handler.go index d32adbe1e..fbd072e1b 100644 --- a/x/rollapp/keeper/fraud_handler.go +++ b/x/rollapp/keeper/fraud_handler.go @@ -25,10 +25,8 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) } // update revision number - // rollapp.RevisionNumber += 1 + rollapp.RevisionNumber += 1 // fixme: set liveness height - - rollapp.Frozen = true k.SetRollapp(ctx, rollapp) // slash the sequencer, clean delayed packets diff --git a/x/rollapp/keeper/invariants.go b/x/rollapp/keeper/invariants.go index 98b63ed47..402b1bd32 100644 --- a/x/rollapp/keeper/invariants.go +++ b/x/rollapp/keeper/invariants.go @@ -96,9 +96,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/msg_server_mark_vulnerable_rollapps.go b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go index 3e8da8fa0..7210ca6ff 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go +++ b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go @@ -53,10 +53,9 @@ func (k Keeper) MarkVulnerableRollapps(ctx sdk.Context, drsVersions []string) (i var ( logger = k.Logger(ctx) - nonVulnerable = k.FilterRollapps(ctx, FilterNonVulnerable) vulnerableNum int ) - for _, rollapp := range nonVulnerable { + 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") 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_state.go b/x/rollapp/keeper/msg_server_update_state.go index 25b752383..30723902e 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -6,7 +6,6 @@ import ( 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 +19,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 diff --git a/x/rollapp/keeper/rollapp.go b/x/rollapp/keeper/rollapp.go index f7abf5183..749402d6c 100644 --- a/x/rollapp/keeper/rollapp.go +++ b/x/rollapp/keeper/rollapp.go @@ -23,10 +23,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 @@ -81,28 +77,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 - } - 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 } @@ -265,10 +247,6 @@ 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 string) bool { ok, err := k.vulnerableDRSVersions.Has(ctx, version) if err != nil { diff --git a/x/rollapp/types/rollapp.go b/x/rollapp/types/rollapp.go index 05a1ec20e..4d55d93c4 100644 --- a/x/rollapp/types/rollapp.go +++ b/x/rollapp/types/rollapp.go @@ -103,10 +103,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 7795c4a88..76712b992 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"` // registeredDenoms is a list of registered denom bases on this rollapp RegisteredDenoms []string `protobuf:"bytes,10,rep,name=registeredDenoms,proto3" json:"registeredDenoms,omitempty"` // metadata is the rollapp metadata @@ -151,6 +149,8 @@ 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 from 1 + RevisionNumber int64 `protobuf:"varint,19,opt,name=revision_number,json=revisionNumber,proto3" json:"revision_number,omitempty"` } func (m *Rollapp) Reset() { *m = Rollapp{} } @@ -214,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) GetRegisteredDenoms() []string { if m != nil { return m.RegisteredDenoms @@ -284,6 +277,13 @@ func (m *Rollapp) GetLastStateUpdateHeight() int64 { return 0 } +func (m *Rollapp) GetRevisionNumber() int64 { + if m != nil { + return m.RevisionNumber + } + return 0 +} + // Rollapp summary is a compact representation of Rollapp type RollappSummary struct { // The unique identifier of the rollapp chain. @@ -377,54 +377,55 @@ func init() { } var fileDescriptor_d4ef2bec3aea5528 = []byte{ - // 745 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xcd, 0x4e, 0xc3, 0x46, - 0x10, 0x8e, 0x93, 0x90, 0x9f, 0x4d, 0x00, 0xb3, 0x40, 0xeb, 0x46, 0x25, 0x44, 0x39, 0x45, 0x85, - 0xda, 0xe2, 0x47, 0xea, 0xb9, 0xa8, 0x14, 0x42, 0x9b, 0x1e, 0x1c, 0xa0, 0x12, 0x87, 0x5a, 0x4e, - 0x3c, 0x71, 0x56, 0xb2, 0x77, 0x5d, 0xef, 0x26, 0x25, 0x3c, 0x05, 0xaf, 0xd0, 0xb7, 0xe1, 0x88, - 0x7a, 0xea, 0xa9, 0xad, 0xe0, 0x45, 0x2a, 0xaf, 0xd7, 0x21, 0x2d, 0xd0, 0xa0, 0x9e, 0xd6, 0x33, - 0xdf, 0x7c, 0xdf, 0xfc, 0xec, 0x8e, 0xd1, 0xbe, 0x37, 0x0b, 0x81, 0x72, 0xc2, 0xe8, 0xed, 0xec, - 0xce, 0x9a, 0x1b, 0x56, 0xcc, 0x82, 0xc0, 0x8d, 0xa2, 0xec, 0x34, 0xa3, 0x98, 0x09, 0x86, 0x9b, - 0x8b, 0xd1, 0xe6, 0xdc, 0x30, 0x55, 0x54, 0x63, 0xcb, 0x67, 0x3e, 0x93, 0xa1, 0x56, 0xf2, 0x95, - 0xb2, 0x1a, 0xbb, 0x3e, 0x63, 0x7e, 0x00, 0x96, 0xb4, 0x06, 0x93, 0x91, 0x25, 0x48, 0x08, 0x5c, - 0xb8, 0xa1, 0x92, 0x6d, 0x7c, 0x3a, 0x64, 0x3c, 0x64, 0xdc, 0x0a, 0xb9, 0x6f, 0x4d, 0x0f, 0x92, - 0x43, 0x01, 0xd6, 0x92, 0xea, 0xb8, 0x70, 0x05, 0x38, 0x84, 0x8e, 0xb2, 0x54, 0x5f, 0x2e, 0x21, - 0x84, 0x20, 0x5c, 0xcf, 0x15, 0xae, 0x0a, 0x3f, 0x58, 0x12, 0xee, 0x03, 0x05, 0x4e, 0xf8, 0x42, - 0x86, 0xf6, 0x39, 0xda, 0xb4, 0x53, 0xf4, 0x2c, 0x05, 0xfb, 0x49, 0x0d, 0x78, 0x0f, 0x6d, 0x88, - 0xd8, 0xa5, 0x7c, 0x04, 0x31, 0x77, 0x80, 0xba, 0x83, 0x00, 0x3c, 0x23, 0xdf, 0xd2, 0x3a, 0x15, - 0x5b, 0x9f, 0x03, 0xa7, 0xa9, 0xff, 0xa2, 0x58, 0xd1, 0xf4, 0x7c, 0xfb, 0xd7, 0x12, 0x2a, 0x2b, - 0x29, 0xbc, 0x83, 0x90, 0xca, 0xe9, 0x10, 0xcf, 0xd0, 0x5a, 0x5a, 0xa7, 0x6a, 0x57, 0x95, 0xa7, - 0xeb, 0xe1, 0x2d, 0xb4, 0xc2, 0x7e, 0xa1, 0x10, 0x4b, 0xc5, 0xaa, 0x9d, 0x1a, 0xf8, 0x27, 0xb4, - 0x9a, 0x15, 0x28, 0x07, 0x61, 0x94, 0x5b, 0x5a, 0xa7, 0x76, 0x78, 0x64, 0xfe, 0xf7, 0x2d, 0x99, - 0x6f, 0xd4, 0x7f, 0x52, 0x7c, 0xf8, 0x63, 0x37, 0x67, 0xd7, 0xfd, 0xc5, 0x9e, 0x76, 0x10, 0x1a, - 0x8e, 0x5d, 0x4a, 0x21, 0x48, 0x8a, 0xaa, 0xa4, 0x45, 0x29, 0x4f, 0xd7, 0xc3, 0x9f, 0xa0, 0xd2, - 0x28, 0x66, 0x77, 0x40, 0x8d, 0xaa, 0xec, 0x53, 0x59, 0xf8, 0x0b, 0xa4, 0xc7, 0xe0, 0x13, 0x2e, - 0x20, 0x06, 0xef, 0x1b, 0xa0, 0x2c, 0xe4, 0x06, 0x6a, 0x15, 0x3a, 0x55, 0xfb, 0x95, 0x1f, 0x7f, - 0x87, 0x2a, 0xd9, 0x95, 0x18, 0x35, 0x59, 0xbd, 0xf5, 0xc1, 0xea, 0x7b, 0x8a, 0x66, 0xcf, 0x05, - 0xf0, 0x25, 0xaa, 0x2f, 0x5e, 0x98, 0x51, 0x97, 0x82, 0x7b, 0xcb, 0x04, 0xd5, 0x1c, 0xba, 0x74, - 0xc4, 0xd4, 0x18, 0x6a, 0xfe, 0x8b, 0x2b, 0xb9, 0x59, 0x42, 0x89, 0x20, 0x6e, 0xe0, 0x70, 0xf8, - 0x79, 0x02, 0x74, 0x08, 0xb1, 0xb1, 0x2a, 0x87, 0xa1, 0x2b, 0xa0, 0x9f, 0xf9, 0xf1, 0x19, 0x2a, - 0x4f, 0x43, 0x47, 0xcc, 0x22, 0x30, 0xd6, 0x5a, 0x5a, 0x67, 0xed, 0xd0, 0xfc, 0x60, 0x3b, 0xe6, - 0x75, 0xef, 0x72, 0x16, 0x81, 0x5d, 0x9a, 0x86, 0xc9, 0x89, 0x1b, 0xa8, 0x12, 0xb8, 0x13, 0x3a, - 0x1c, 0x83, 0x67, 0xac, 0xcb, 0xf1, 0xce, 0x6d, 0x7c, 0x8e, 0xd6, 0xa3, 0x18, 0x9c, 0xd4, 0x76, - 0x92, 0x65, 0x32, 0x74, 0xd9, 0x6a, 0xc3, 0x4c, 0x37, 0xcd, 0xcc, 0x36, 0xcd, 0xbc, 0xcc, 0x36, - 0xed, 0xa4, 0x78, 0xff, 0xe7, 0xae, 0x66, 0xaf, 0x46, 0x31, 0x7c, 0x2f, 0x79, 0x09, 0x82, 0x0f, - 0xd1, 0x76, 0x40, 0xa6, 0x49, 0xb3, 0xdc, 0x81, 0x29, 0x50, 0xe1, 0x8c, 0x81, 0xf8, 0x63, 0x61, - 0x6c, 0xb4, 0xb4, 0x4e, 0xc1, 0xde, 0xcc, 0xc0, 0xd3, 0x04, 0x3b, 0x97, 0x10, 0xfe, 0x0a, 0x19, - 0x81, 0xcb, 0x45, 0xfa, 0xe4, 0x9c, 0x49, 0xe4, 0x25, 0x87, 0xa2, 0x61, 0x49, 0xdb, 0x4e, 0x70, - 0xf9, 0x84, 0xae, 0x24, 0x9a, 0x12, 0xdb, 0xfb, 0xa8, 0x94, 0x36, 0x89, 0xd7, 0x51, 0xed, 0x8a, - 0xf2, 0x08, 0x86, 0x64, 0x44, 0xc0, 0xd3, 0x73, 0xb8, 0x8c, 0x0a, 0xa7, 0xd7, 0x3d, 0x5d, 0xc3, - 0x15, 0x54, 0xfc, 0xf1, 0xeb, 0x7e, 0x4f, 0xcf, 0x5f, 0x14, 0x2b, 0x05, 0xbd, 0xdc, 0xfe, 0x2d, - 0x8f, 0xd6, 0xd4, 0x84, 0xfa, 0x93, 0x30, 0x74, 0xe3, 0x19, 0xfe, 0x1c, 0xbd, 0x2c, 0xc6, 0xeb, - 0x4d, 0xb9, 0x41, 0x7a, 0xe0, 0x0a, 0x50, 0xf9, 0xbb, 0xd4, 0x83, 0x5b, 0xb9, 0x34, 0xb5, 0xe5, - 0x37, 0xa1, 0x18, 0x23, 0x26, 0x59, 0xf6, 0x2b, 0x1d, 0x1c, 0xa0, 0xcf, 0x52, 0xdf, 0xb7, 0x84, - 0xba, 0x01, 0xb9, 0x03, 0x6f, 0x21, 0x49, 0xe1, 0x7f, 0x25, 0x79, 0x5f, 0x10, 0xb7, 0x51, 0x3d, - 0x05, 0xd3, 0xf1, 0x19, 0xc5, 0x96, 0xd6, 0x29, 0xda, 0xff, 0xf0, 0xe1, 0x63, 0xb4, 0xfd, 0x2f, - 0x01, 0x15, 0xbc, 0x22, 0x83, 0xdf, 0x06, 0x4f, 0x7e, 0x78, 0x78, 0x6a, 0x6a, 0x8f, 0x4f, 0x4d, - 0xed, 0xaf, 0xa7, 0xa6, 0x76, 0xff, 0xdc, 0xcc, 0x3d, 0x3e, 0x37, 0x73, 0xbf, 0x3f, 0x37, 0x73, - 0x37, 0xc7, 0x3e, 0x11, 0xe3, 0xc9, 0xc0, 0x1c, 0xb2, 0xf0, 0xbd, 0x5f, 0xef, 0xf4, 0xc8, 0xba, - 0x9d, 0xff, 0x1f, 0x93, 0x87, 0xce, 0x07, 0x25, 0xf9, 0xdc, 0x8e, 0xfe, 0x0e, 0x00, 0x00, 0xff, - 0xff, 0x9c, 0xe3, 0xa5, 0xb0, 0x4c, 0x06, 0x00, 0x00, + // 762 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xcd, 0x6e, 0xea, 0x46, + 0x14, 0xc6, 0xe0, 0x0b, 0x66, 0x20, 0xe0, 0x3b, 0xb9, 0x51, 0x5d, 0xd4, 0x4b, 0x10, 0x9b, 0xa2, + 0xde, 0x5b, 0x5b, 0xf9, 0x91, 0xba, 0x6e, 0xd4, 0x34, 0x21, 0x2d, 0x59, 0x98, 0x24, 0x95, 0xb2, + 0xa8, 0x65, 0xf0, 0xc1, 0x8c, 0x64, 0x8f, 0x5d, 0xcf, 0x40, 0x43, 0x9e, 0x22, 0x8f, 0xd3, 0x47, + 0xc8, 0x32, 0xea, 0xaa, 0xab, 0xb6, 0x4a, 0x5e, 0xa4, 0xf2, 0x78, 0x4c, 0x68, 0x93, 0x94, 0xe8, + 0xae, 0xc6, 0xe7, 0xfb, 0xce, 0xcf, 0x77, 0xce, 0xcc, 0x31, 0xfa, 0xe8, 0x2d, 0x42, 0xa0, 0x8c, + 0x44, 0xf4, 0x6a, 0x71, 0x6d, 0x2d, 0x0d, 0x2b, 0x89, 0x82, 0xc0, 0x8d, 0xe3, 0xfc, 0x34, 0xe3, + 0x24, 0xe2, 0x11, 0x6e, 0xaf, 0x7a, 0x9b, 0x4b, 0xc3, 0x94, 0x5e, 0xad, 0x77, 0x7e, 0xe4, 0x47, + 0xc2, 0xd5, 0x4a, 0xbf, 0xb2, 0xa8, 0xd6, 0xb6, 0x1f, 0x45, 0x7e, 0x00, 0x96, 0xb0, 0x46, 0xb3, + 0x89, 0xc5, 0x49, 0x08, 0x8c, 0xbb, 0xa1, 0x4c, 0xdb, 0xfa, 0x6c, 0x1c, 0xb1, 0x30, 0x62, 0x56, + 0xc8, 0x7c, 0x6b, 0xbe, 0x93, 0x1e, 0x92, 0xb0, 0xd6, 0xa8, 0x63, 0xdc, 0xe5, 0xe0, 0x10, 0x3a, + 0xc9, 0x4b, 0x7d, 0xbd, 0x26, 0x20, 0x04, 0xee, 0x7a, 0x2e, 0x77, 0xa5, 0xfb, 0xce, 0x1a, 0x77, + 0x1f, 0x28, 0x30, 0xc2, 0x56, 0x2a, 0x74, 0x8f, 0xd1, 0xa6, 0x9d, 0xb1, 0x47, 0x19, 0x39, 0x4c, + 0x35, 0xe0, 0x0f, 0xe8, 0x2d, 0x4f, 0x5c, 0xca, 0x26, 0x90, 0x30, 0x07, 0xa8, 0x3b, 0x0a, 0xc0, + 0x33, 0x8a, 0x1d, 0xa5, 0xa7, 0xd9, 0xfa, 0x92, 0x38, 0xcc, 0xf0, 0x13, 0x55, 0x53, 0xf4, 0x62, + 0xf7, 0xb7, 0x32, 0xaa, 0xc8, 0x54, 0xf8, 0x3d, 0x42, 0xb2, 0xa6, 0x43, 0x3c, 0x43, 0xe9, 0x28, + 0xbd, 0xaa, 0x5d, 0x95, 0x48, 0xdf, 0xc3, 0xef, 0xd0, 0x9b, 0xe8, 0x57, 0x0a, 0x89, 0xc8, 0x58, + 0xb5, 0x33, 0x03, 0xff, 0x8c, 0x36, 0x72, 0x81, 0x62, 0x10, 0x46, 0xa5, 0xa3, 0xf4, 0x6a, 0xbb, + 0x7b, 0xe6, 0xff, 0xdf, 0x92, 0xf9, 0x8c, 0xfe, 0x03, 0xf5, 0xf6, 0xcf, 0xed, 0x82, 0x5d, 0xf7, + 0x57, 0x7b, 0x7a, 0x8f, 0xd0, 0x78, 0xea, 0x52, 0x0a, 0x41, 0x2a, 0x4a, 0xcb, 0x44, 0x49, 0xa4, + 0xef, 0xe1, 0xaf, 0x90, 0x9e, 0x80, 0x4f, 0x18, 0x87, 0x04, 0xbc, 0xef, 0x80, 0x46, 0x21, 0x33, + 0x50, 0xa7, 0xd4, 0xab, 0xda, 0x4f, 0x70, 0xfc, 0x03, 0xd2, 0xf2, 0xd1, 0x1b, 0x35, 0xa1, 0xd2, + 0x7a, 0xa5, 0xca, 0x81, 0x0c, 0xb3, 0x97, 0x09, 0xf0, 0x19, 0xaa, 0xaf, 0x5e, 0x8c, 0x51, 0x17, + 0x09, 0x3f, 0xac, 0x4b, 0x28, 0xfb, 0xed, 0xd3, 0x49, 0x24, 0xdb, 0xad, 0xf9, 0x8f, 0x50, 0x7a, + 0x83, 0x84, 0x12, 0x4e, 0xdc, 0xc0, 0x61, 0xf0, 0xcb, 0x0c, 0xe8, 0x18, 0x12, 0x63, 0x43, 0x34, + 0xad, 0x4b, 0x62, 0x98, 0xe3, 0xf8, 0x08, 0x55, 0xe6, 0xa1, 0xc3, 0x17, 0x31, 0x18, 0x8d, 0x8e, + 0xd2, 0x6b, 0xec, 0x9a, 0xaf, 0x6c, 0xc7, 0xbc, 0x18, 0x9c, 0x2d, 0x62, 0xb0, 0xcb, 0xf3, 0x30, + 0x3d, 0x71, 0x0b, 0x69, 0x81, 0x3b, 0xa3, 0xe3, 0x29, 0x78, 0x46, 0x53, 0x3c, 0x97, 0xa5, 0x8d, + 0x8f, 0x51, 0x33, 0x4e, 0xc0, 0xc9, 0x6c, 0x27, 0x5d, 0x1a, 0x43, 0x17, 0xad, 0xb6, 0xcc, 0x6c, + 0xa3, 0xcc, 0x7c, 0xa3, 0xcc, 0xb3, 0x7c, 0xa3, 0x0e, 0xd4, 0x9b, 0xbf, 0xb6, 0x15, 0x7b, 0x23, + 0x4e, 0xe0, 0x47, 0x11, 0x97, 0x32, 0x78, 0x17, 0x6d, 0x05, 0x64, 0x9e, 0x36, 0xcb, 0x1c, 0x98, + 0x03, 0xe5, 0xce, 0x14, 0x88, 0x3f, 0xe5, 0xc6, 0xdb, 0x8e, 0xd2, 0x2b, 0xd9, 0x9b, 0x39, 0x79, + 0x98, 0x72, 0xc7, 0x82, 0xc2, 0xdf, 0x20, 0x23, 0x70, 0x19, 0xcf, 0x9e, 0x96, 0x33, 0x8b, 0xbd, + 0xf4, 0x90, 0x61, 0x58, 0x84, 0x6d, 0xa5, 0xbc, 0x78, 0x2a, 0xe7, 0x82, 0x95, 0x81, 0x5f, 0xa2, + 0x66, 0x02, 0x73, 0x92, 0x76, 0xef, 0xd0, 0x59, 0x38, 0x82, 0xc4, 0xd8, 0x14, 0xfe, 0x8d, 0x1c, + 0x3e, 0x15, 0x68, 0xf7, 0x23, 0x2a, 0x67, 0xd3, 0xc0, 0x4d, 0x54, 0x3b, 0xa7, 0x2c, 0x86, 0x31, + 0x99, 0x10, 0xf0, 0xf4, 0x02, 0xae, 0xa0, 0xd2, 0xe1, 0xc5, 0x40, 0x57, 0xb0, 0x86, 0xd4, 0x9f, + 0xbe, 0x1d, 0x0e, 0xf4, 0xe2, 0x89, 0xaa, 0x95, 0xf4, 0xca, 0x89, 0xaa, 0x55, 0x75, 0xd4, 0xfd, + 0xbd, 0x88, 0x1a, 0x72, 0xa0, 0xc3, 0x59, 0x18, 0xba, 0xc9, 0x02, 0x7f, 0x81, 0x1e, 0xf7, 0xe5, + 0xe9, 0x02, 0x5d, 0x22, 0x3d, 0x70, 0x39, 0x48, 0xb9, 0x7d, 0xea, 0xc1, 0x95, 0xd8, 0xa5, 0xda, + 0xfa, 0x8b, 0x93, 0x11, 0x93, 0x48, 0x44, 0xd9, 0x4f, 0xf2, 0xe0, 0x00, 0x7d, 0x9e, 0x61, 0xdf, + 0x13, 0xea, 0x06, 0xe4, 0x1a, 0xbc, 0x95, 0x22, 0xa5, 0x4f, 0x2a, 0xf2, 0x72, 0x42, 0xdc, 0x45, + 0xf5, 0x8c, 0xcc, 0xa6, 0x6d, 0xa8, 0x1d, 0xa5, 0xa7, 0xda, 0xff, 0xc2, 0xf0, 0x3e, 0xda, 0xfa, + 0x4f, 0x02, 0xe9, 0xfc, 0x46, 0x38, 0x3f, 0x4f, 0x1e, 0x9c, 0xde, 0xde, 0xb7, 0x95, 0xbb, 0xfb, + 0xb6, 0xf2, 0xf7, 0x7d, 0x5b, 0xb9, 0x79, 0x68, 0x17, 0xee, 0x1e, 0xda, 0x85, 0x3f, 0x1e, 0xda, + 0x85, 0xcb, 0x7d, 0x9f, 0xf0, 0xe9, 0x6c, 0x64, 0x8e, 0xa3, 0xf0, 0xa5, 0x3f, 0xf2, 0x7c, 0xcf, + 0xba, 0x5a, 0xfe, 0x36, 0xd3, 0xbd, 0x60, 0xa3, 0xb2, 0x78, 0x9d, 0x7b, 0xff, 0x04, 0x00, 0x00, + 0xff, 0xff, 0xf8, 0xef, 0x30, 0xa7, 0x63, 0x06, 0x00, 0x00, } func (m *RollappGenesisState) Marshal() (dAtA []byte, err error) { @@ -480,6 +481,13 @@ func (m *Rollapp) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + 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-- @@ -559,16 +567,6 @@ func (m *Rollapp) MarshalToSizedBuffer(dAtA []byte) (int, error) { dAtA[i] = 0x52 } } - 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) @@ -710,9 +708,6 @@ func (m *Rollapp) Size() (n int) { if l > 0 { n += 1 + l + sovRollapp(uint64(l)) } - if m.Frozen { - n += 2 - } if len(m.RegisteredDenoms) > 0 { for _, s := range m.RegisteredDenoms { l = len(s) @@ -745,6 +740,9 @@ 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)) + } return n } @@ -1009,26 +1007,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 10: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field RegisteredDenoms", wireType) @@ -1275,6 +1253,25 @@ 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 |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipRollapp(dAtA[iNdEx:]) diff --git a/x/sequencer/keeper/msg_server_create_sequencer.go b/x/sequencer/keeper/msg_server_create_sequencer.go index 00516aab4..d20696cd0 100644 --- a/x/sequencer/keeper/msg_server_create_sequencer.go +++ b/x/sequencer/keeper/msg_server_create_sequencer.go @@ -23,10 +23,6 @@ func (k msgServer) CreateSequencer(goCtx context.Context, msg *types.MsgCreateSe return nil, types.ErrUnknownRollappID } - if rollapp.Frozen { - return nil, types.ErrRollappFrozen - } - if err := msg.VMSpecificValidate(rollapp.VmType); err != nil { return nil, errors.Join(types.ErrInvalidRequest, err) } diff --git a/x/sequencer/keeper/msg_server_update_sequencer.go b/x/sequencer/keeper/msg_server_update_sequencer.go index 9431bf9bf..4e5052ef3 100644 --- a/x/sequencer/keeper/msg_server_update_sequencer.go +++ b/x/sequencer/keeper/msg_server_update_sequencer.go @@ -24,11 +24,6 @@ func (k msgServer) UpdateSequencerInformation(goCtx context.Context, msg *types. } rollapp := k.rollappKeeper.MustGetRollapp(ctx, sequencer.RollappId) - - if rollapp.Frozen { - return nil, types.ErrRollappFrozen - } - if err := msg.VMSpecificValidate(rollapp.VmType); err != nil { return nil, err } diff --git a/x/sequencer/keeper/msg_server_update_sequencer_test.go b/x/sequencer/keeper/msg_server_update_sequencer_test.go index b369e6f86..1aa4ae4f8 100644 --- a/x/sequencer/keeper/msg_server_update_sequencer_test.go +++ b/x/sequencer/keeper/msg_server_update_sequencer_test.go @@ -90,18 +90,6 @@ func (suite *SequencerTestSuite) TestUpdateSequencer() { Tokens: nil, UnbondTime: time.Time{}, }, - }, { - name: "Update rollapp: fail - try to update a frozen rollapp", - update: &types.MsgUpdateSequencerInformation{ - Creator: addr.String(), - }, - malleate: func(*types.Sequencer) { - suite.App.RollappKeeper.SetRollapp(suite.Ctx, rollapptypes.Rollapp{ - RollappId: rollappID, - Frozen: true, - }) - }, - expError: types.ErrRollappFrozen, }, { name: "Update rollapp: fail - try to update a jailed sequencer", update: &types.MsgUpdateSequencerInformation{ From 4d7ca1812c3ec244d1900643738daa066060063f Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 27 Oct 2024 09:13:00 +0200 Subject: [PATCH 04/68] cleanup --- ibctesting/light_client_test.go | 11 ++++++----- x/delayedack/keeper/invariants.go | 2 -- x/lightclient/keeper/rollback.go | 25 +++++++++++++++++++++++++ x/rollapp/proposal_handler.go | 2 ++ 4 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 x/lightclient/keeper/rollback.go diff --git a/ibctesting/light_client_test.go b/ibctesting/light_client_test.go index 929f8fd3e..853c954c0 100644 --- a/ibctesting/light_client_test.go +++ b/ibctesting/light_client_test.go @@ -342,12 +342,13 @@ func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_NotCompat ) _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) s.Error(err) - // The optimistic update valhash should be removed as part of fraud handling - _, found = s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) - s.False(found) - // Ensuring that the rollapp is now frozen as part of fraud handling + + // Assert that hard fork was triggered rollapp, _ := s.hubApp().RollappKeeper.GetRollapp(s.hubCtx(), s.rollappChain().ChainID) s.Equal(2, rollapp.RevisionNumber) - // FIXME: better test for fraud handling + // The optimistic update valhash should be removed as part of fraud handling + _, found = s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) + s.False(found) + // FIXME: test for fraud handling in the `x/lightclient` } diff --git a/x/delayedack/keeper/invariants.go b/x/delayedack/keeper/invariants.go index 9f36d4fd8..04c9ed12b 100644 --- a/x/delayedack/keeper/invariants.go +++ b/x/delayedack/keeper/invariants.go @@ -23,14 +23,12 @@ func (k Keeper) RegisterInvariants(ir sdk.InvariantRegistry) { // 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)(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)(ctx) } diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go new file mode 100644 index 000000000..74bcbb8a3 --- /dev/null +++ b/x/lightclient/keeper/rollback.go @@ -0,0 +1,25 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func (hook rollappHook) OnHardFork(sdk.Context, string, uint64) error { + /* + // freeze IBC client state + 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 +} diff --git a/x/rollapp/proposal_handler.go b/x/rollapp/proposal_handler.go index d10bb1535..ef9290199 100644 --- a/x/rollapp/proposal_handler.go +++ b/x/rollapp/proposal_handler.go @@ -11,6 +11,8 @@ import ( errorsmod "cosmossdk.io/errors" ) +// FIXME: refactor the proposal handler to support different types of proposals + func NewRollappProposalHandler(k *keeper.Keeper) govtypes.Handler { return func(ctx sdk.Context, content govtypes.Content) error { switch c := content.(type) { From fffe076b6b353ad6fdd12867d3482cbb2c5db65f Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 27 Oct 2024 12:02:21 +0200 Subject: [PATCH 05/68] UT compiles --- .../dymension/rollapp/rollapp.proto | 2 +- x/delayedack/keeper/invariants.go | 2 +- x/rollapp/keeper/fraud_handler.go | 2 +- x/rollapp/keeper/fraud_handler_test.go | 52 +++---------------- .../keeper/msg_server_create_rollapp_test.go | 10 +--- ...sg_server_mark_vulnerable_rollapps_test.go | 13 +++-- .../keeper/msg_server_update_rollapp_test.go | 13 ----- x/rollapp/keeper/rollapp.go | 2 +- x/rollapp/keeper/rollapp_suite_test.go | 2 +- x/rollapp/types/rollapp.go | 1 + 10 files changed, 25 insertions(+), 74 deletions(-) diff --git a/proto/dymensionxyz/dymension/rollapp/rollapp.proto b/proto/dymensionxyz/dymension/rollapp/rollapp.proto index c49c5c06c..c0903e71c 100644 --- a/proto/dymensionxyz/dymension/rollapp/rollapp.proto +++ b/proto/dymensionxyz/dymension/rollapp/rollapp.proto @@ -76,7 +76,7 @@ message Rollapp { // received int64 last_state_update_height = 18; - // The revision number of the rollapp. starts always from 1 + // The revision number of the rollapp. starts always with 0 revision int64 revision_number = 19; } diff --git a/x/delayedack/keeper/invariants.go b/x/delayedack/keeper/invariants.go index 04c9ed12b..382744407 100644 --- a/x/delayedack/keeper/invariants.go +++ b/x/delayedack/keeper/invariants.go @@ -18,7 +18,7 @@ const ( // 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) + // ir.RegisterRoute(types.ModuleName, routeRevertedPacket, k.PacketsFromRevertedHeightsAreReverted) } // PacketsFinalizationCorrespondsToFinalizationHeight checks that all rollapp packets stored are set to diff --git a/x/rollapp/keeper/fraud_handler.go b/x/rollapp/keeper/fraud_handler.go index fbd072e1b..2405a44ab 100644 --- a/x/rollapp/keeper/fraud_handler.go +++ b/x/rollapp/keeper/fraud_handler.go @@ -26,7 +26,7 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) // update revision number rollapp.RevisionNumber += 1 - // fixme: set liveness height + // FIXME: set liveness height k.SetRollapp(ctx, rollapp) // slash the sequencer, clean delayed packets diff --git a/x/rollapp/keeper/fraud_handler_test.go b/x/rollapp/keeper/fraud_handler_test.go index cabef7bcc..6a60ccfff 100644 --- a/x/rollapp/keeper/fraud_handler_test.go +++ b/x/rollapp/keeper/fraud_handler_test.go @@ -52,7 +52,7 @@ func (suite *RollappTestSuite) TestHardFork() { // assert before fraud submission suite.assertBeforeFraud(rollapp, fraudHeight) - err = keeper.HardFork(*ctx, rollapp, "", fraudHeight, proposer) + err = keeper.HardFork(*ctx, rollapp, fraudHeight) suite.Require().Nil(err) suite.assertFraudHandled(rollapp) @@ -67,7 +67,7 @@ func (suite *RollappTestSuite) TestHardFork_InvalidRollapp() { _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) suite.Require().Nil(err) - err = keeper.HardFork(*ctx, "invalidRollapp", "", 2, proposer) + err = keeper.HardFork(*ctx, "invalidRollapp", 2) suite.Require().NotNil(err) } @@ -80,33 +80,7 @@ func (suite *RollappTestSuite) TestHardFork_WrongHeight() { _, err := suite.PostStateUpdate(*ctx, rollapp, proposer, 1, uint64(10)) suite.Require().Nil(err) - err = keeper.HardFork(*ctx, rollapp, "", 100, proposer) - suite.Require().NotNil(err) -} - -// Fail - Wrong sequencer address -func (suite *RollappTestSuite) TestHardFork_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.HardFork(*ctx, rollapp, "", 2, "wrongSequencer") - suite.Require().NotNil(err) -} - -// Fail - Wrong channel-ID -func (suite *RollappTestSuite) TestHardFork_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.HardFork(*ctx, rollapp, "wrongChannelID", 2, proposer) + err = keeper.HardFork(*ctx, rollapp, 100) suite.Require().NotNil(err) } @@ -132,10 +106,10 @@ func (suite *RollappTestSuite) TestHardFork_AlreadyReverted() { suite.Ctx = suite.Ctx.WithBlockHeight(suite.Ctx.BlockHeader().Height + 1) } - err = keeper.HardFork(*ctx, rollapp, "", 11, proposer) + err = keeper.HardFork(*ctx, rollapp, 11) suite.Require().Nil(err) - err = keeper.HardFork(*ctx, rollapp, "", 1, proposer) + err = keeper.HardFork(*ctx, rollapp, 1) suite.Require().NotNil(err) } @@ -155,19 +129,17 @@ func (suite *RollappTestSuite) TestHardFork_AlreadyFinalized() { suite.Require().Nil(err) suite.Require().Equal(common.Status_FINALIZED, stateInfo.Status) - err = keeper.HardFork(*ctx, rollapp, "", 2, proposer) + err = keeper.HardFork(*ctx, rollapp, 2) 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) + suite.Require().Zero(rollapp.RevisionNumber) // check sequencers sequencers := suite.App.SequencerKeeper.GetSequencersByRollapp(suite.Ctx, rollappId) @@ -200,15 +172,7 @@ func (suite *RollappTestSuite) assertBeforeFraud(rollappId string, height uint64 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 sequencers - sequencers := suite.App.SequencerKeeper.GetSequencersByRollappByStatus(suite.Ctx, rollappId, types.Bonded) - suite.Require().Equal(0, len(sequencers)) - _, ok := suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().False(ok) - seq := suite.App.SequencerKeeper.ExpectedNextProposer(suite.Ctx, rollappId) - suite.Require().Empty(seq.Address) + suite.Require().Equal(uint64(1), rollapp.RevisionNumber) // check states finalIdx, _ := suite.App.RollappKeeper.GetLatestFinalizedStateIndex(suite.Ctx, rollappId) diff --git a/x/rollapp/keeper/msg_server_create_rollapp_test.go b/x/rollapp/keeper/msg_server_create_rollapp_test.go index e15b824c5..f42afd7d1 100644 --- a/x/rollapp/keeper/msg_server_create_rollapp_test.go +++ b/x/rollapp/keeper/msg_server_create_rollapp_test.go @@ -77,10 +77,9 @@ func (suite *RollappTestSuite) TestCreateRollappAlreadyExists() { rollappId: "rollapp_1234-2", malleate: func() { r := rollapp.GetRollapp() - r.Frozen = true suite.App.RollappKeeper.SetRollapp(suite.Ctx, r) }, - expErr: nil, + expErr: types.ErrRollappExists, }, { name: "different rollapp, revision not 1", rollappId: "trollapp_2345-2", @@ -213,14 +212,9 @@ func (suite *RollappTestSuite) TestForkChainId() { _, 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, @@ -236,7 +230,7 @@ func (suite *RollappTestSuite) TestForkChainId() { _, err = suite.msgServer.CreateRollapp(goCtx, &rollappMsg2) if test.valid { suite.Require().NoError(err) - _, found = suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappMsg2.RollappId) + _, found := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappMsg2.RollappId) suite.Require().True(found) } else { suite.Require().ErrorIs(err, types.ErrInvalidRollappID) diff --git a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go index ed11dc05b..8c493dd9c 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go +++ b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go @@ -10,10 +10,11 @@ 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" ) +// FIXME: validate mark vulnerable causes hard fork + func (s *RollappTestSuite) TestMarkVulnerableRollapps() { type rollapp struct { name string @@ -152,7 +153,7 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { 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) + nonVulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterNonVulnerable) actualNonVulnRollappIDs := uslice.Map(nonVulnRa, func(r types.Rollapp) string { return r.RollappId }) allRollapps := slices.Concat(expectedVulnRollappIDs, expectedNonVulnRollappIDs) s.ElementsMatch(allRollapps, actualNonVulnRollappIDs) @@ -173,7 +174,7 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { s.AssertEventEmitted(s.Ctx, eventName, 1) // check non-vulnerable rollapps - nonVulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, keeper.FilterNonVulnerable) + nonVulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterNonVulnerable) actualNonVulnRollappIDs := uslice.Map(nonVulnRa, func(r types.Rollapp) string { return r.RollappId }) s.ElementsMatch(expectedNonVulnRollappIDs, actualNonVulnRollappIDs) @@ -192,5 +193,9 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { } func FilterVulnerable(b types.Rollapp) bool { - return b.Frozen + return b.RevisionNumber > 0 +} + +func FilterNonVulnerable(b types.Rollapp) bool { + return b.RevisionNumber == 0 } diff --git a/x/rollapp/keeper/msg_server_update_rollapp_test.go b/x/rollapp/keeper/msg_server_update_rollapp_test.go index d1aadb652..0cd707ab9 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 }{ @@ -78,15 +77,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{ @@ -161,7 +151,6 @@ func (suite *RollappTestSuite) TestUpdateRollapp() { Owner: alice, InitialSequencer: "", ChannelId: "", - Frozen: false, Launched: true, VmType: types.Rollapp_EVM, Metadata: &mockRollappMetadata, @@ -192,7 +181,6 @@ func (suite *RollappTestSuite) TestUpdateRollapp() { Owner: alice, InitialSequencer: "", ChannelId: "", - Frozen: false, Launched: false, VmType: types.Rollapp_EVM, Metadata: &mockRollappMetadata, @@ -219,7 +207,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/rollapp.go b/x/rollapp/keeper/rollapp.go index cc2a6200f..65e698945 100644 --- a/x/rollapp/keeper/rollapp.go +++ b/x/rollapp/keeper/rollapp.go @@ -233,7 +233,7 @@ func (k Keeper) IsRollappStarted(ctx sdk.Context, rollappId string) bool { } func (k Keeper) MarkRollappAsVulnerable(ctx sdk.Context, rollappId string) error { - return k.HardFork(ctx, rollappId, 0) // FIXME: use a proper hard fork version + return k.HardFork(ctx, rollappId, 0) // FIXME: use a proper hard fork height } func (k Keeper) FilterRollapps(ctx sdk.Context, f func(types.Rollapp) bool) []types.Rollapp { diff --git a/x/rollapp/keeper/rollapp_suite_test.go b/x/rollapp/keeper/rollapp_suite_test.go index 663501969..886112464 100644 --- a/x/rollapp/keeper/rollapp_suite_test.go +++ b/x/rollapp/keeper/rollapp_suite_test.go @@ -75,7 +75,7 @@ func TestRollappKeeperTestSuite(t *testing.T) { func (suite *RollappTestSuite) IsRollappVulnerable(rollappID string) bool { ra, ok := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappID) suite.Require().True(ok) - return ra.IsVulnerable() + return ra.RevisionNumber > 0 } func (suite *RollappTestSuite) GetRollappLastHeight(rollappID string) uint64 { diff --git a/x/rollapp/types/rollapp.go b/x/rollapp/types/rollapp.go index 4d55d93c4..d0001ed08 100644 --- a/x/rollapp/types/rollapp.go +++ b/x/rollapp/types/rollapp.go @@ -46,6 +46,7 @@ func NewRollapp( GenesisState: RollappGenesisState{ TransfersEnabled: transfersEnabled, }, + RevisionNumber: 0, } } From e61d2af108d078159f7904ff12321a7c5d34d985 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 27 Oct 2024 14:51:59 +0200 Subject: [PATCH 06/68] fixed state deletion on fraud --- .../dymension/rollapp/genesis.proto | 2 +- .../dymension/rollapp/rollapp.proto | 2 +- x/rollapp/keeper/fraud_handler.go | 83 ++++--- x/rollapp/keeper/fraud_handler_test.go | 215 +++++++----------- x/rollapp/types/genesis.pb.go | 66 +++--- x/rollapp/types/rollapp.pb.go | 36 +-- 6 files changed, 187 insertions(+), 217 deletions(-) diff --git a/proto/dymensionxyz/dymension/rollapp/genesis.proto b/proto/dymensionxyz/dymension/rollapp/genesis.proto index cab01cea4..b9cc9ed19 100644 --- a/proto/dymensionxyz/dymension/rollapp/genesis.proto +++ b/proto/dymensionxyz/dymension/rollapp/genesis.proto @@ -26,5 +26,5 @@ message GenesisState { message RollappRegisteredDenoms { string rollapp_id = 1; - repeated string denoms = 2 [(gogoproto.nullable) = false]; + repeated string denoms = 2; } diff --git a/proto/dymensionxyz/dymension/rollapp/rollapp.proto b/proto/dymensionxyz/dymension/rollapp/rollapp.proto index c0903e71c..5529e9e4f 100644 --- a/proto/dymensionxyz/dymension/rollapp/rollapp.proto +++ b/proto/dymensionxyz/dymension/rollapp/rollapp.proto @@ -77,7 +77,7 @@ message Rollapp { int64 last_state_update_height = 18; // The revision number of the rollapp. starts always with 0 revision - int64 revision_number = 19; + uint64 revision_number = 19; } // Rollapp summary is a compact representation of Rollapp diff --git a/x/rollapp/keeper/fraud_handler.go b/x/rollapp/keeper/fraud_handler.go index 2405a44ab..6dcc72cd8 100644 --- a/x/rollapp/keeper/fraud_handler.go +++ b/x/rollapp/keeper/fraud_handler.go @@ -29,7 +29,7 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) // FIXME: set liveness height k.SetRollapp(ctx, rollapp) - // slash the sequencer, clean delayed packets + // handle the sequencers, clean delayed packets, handle light client err = k.hooks.OnHardFork(ctx, rollappID, fraudHeight) if err != nil { return err @@ -49,7 +49,9 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) // removes state updates until the one specified and included func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeight uint64) error { // find the affected state info index - // skip if not found (height not committed yet) + // skip if not found (fraud height is not committed yet) + + // FIXME: can we hard fork over uncommitted height?? stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, fraudHeight) if errorsmod.IsOf(err, gerrc.ErrNotFound) { return nil @@ -63,17 +65,27 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig } // trunc the state info if needed - err = k.TruncStateInfo(ctx, stateInfo, fraudHeight) + lastStateIdxToKeep, err := k.TruncStateInfo(ctx, stateInfo, fraudHeight) if err != nil { return errorsmod.Wrap(err, "trunc state info") } - lastIdxToKeep := stateInfo.StateInfoIndex.Index + // clear state info + revertedStatesCount := 0 // Counter for reverted state updates + lastIdx, _ := k.GetLatestStateInfoIndex(ctx, rollappID) + for i := lastStateIdxToKeep + 1; i <= lastIdx.Index; i++ { + k.RemoveStateInfo(ctx, rollappID, i) + revertedStatesCount++ // Increment the counter + } + k.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ + RollappId: rollappID, + Index: lastStateIdxToKeep, + }) // TODO (#631): Prefix store by rollappID for efficient querying queuePerHeight := k.GetAllBlockHeightToFinalizationQueue(ctx) - revertedCount := 0 // Counter for reverted state updates + revertedQueueCount := 0 for _, queue := range queuePerHeight { leftPendingStates := []types.StateInfoIndex{} for _, stateInfoIndex := range queue.FinalizationQueue { @@ -84,14 +96,13 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig } // keep state info indexes with index less than the rollback index - if stateInfoIndex.Index <= lastIdxToKeep { + if stateInfoIndex.Index <= lastStateIdxToKeep { leftPendingStates = append(leftPendingStates, stateInfoIndex) continue } - // keep pending packets with height less than the rollback height - k.RemoveStateInfo(ctx, stateInfoIndex.RollappId, stateInfoIndex.Index) - revertedCount++ // Increment the counter + // remove the state info index from the queue + revertedQueueCount++ } // no change in the queue @@ -112,32 +123,42 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig }) } - ctx.Logger().Info(fmt.Sprintf("Reverted state updates for rollapp: %s, count: %d", rollappID, revertedCount)) + // FIXME: remove. this is probably more invariant check + if revertedQueueCount != revertedStatesCount { + return fmt.Errorf("reverted state updates count mismatch: states: %d, queue: %d", revertedStatesCount, revertedQueueCount) + } + + ctx.Logger().Info(fmt.Sprintf("Reverted state updates for rollapp: %s, count: %d", rollappID, revertedStatesCount)) return nil } -// trunc fraudelent state info -func (k Keeper) TruncStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) error { - return nil +// TruncStateInfo truncates the state info to the last valid block before the fraud height. +// It returns the index of the last state info to keep. +func (k Keeper) TruncStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) (uint64, error) { + // If fraud height is at the beginning of the state info, return the previous index to keep + if stateInfo.StartHeight == fraudHeight { + return stateInfo.StateInfoIndex.Index - 1, nil + } - /* - // heightToKeep := fraudHeight + 1 + // Otherwise, create a new state info with the truncated height + heightToKeep := fraudHeight - 1 - // remove block descriptors until the one we need to rollback to. - for { - bd := batch.BDs.Pop() - if bd.Height < height { - break - } - } - if batch.BDs.len() == 0 { - // no more blocks in the faulty batch means remove it - k.removeBatch(ctx, rollappID, batch.Id) - } else { - // this means we need to truncate the batch - // which also becomes the last batch. - k.setBatch(ctx, rollappID, batch) - } - */ + // Remove block descriptors until the one we need to rollback to + var truncatedBDs []types.BlockDescriptor + for i, bd := range stateInfo.BDs.BD { + if bd.Height > heightToKeep { + truncatedBDs = stateInfo.BDs.BD[:i] + break + } + } + + // Update the state info to reflect truncated data + stateInfo.NumBlocks = uint64(len(truncatedBDs)) + stateInfo.BDs.BD = truncatedBDs + + // Update the state info in the keeper + k.SetStateInfo(ctx, *stateInfo) + + return stateInfo.StateInfoIndex.Index, nil } diff --git a/x/rollapp/keeper/fraud_handler_test.go b/x/rollapp/keeper/fraud_handler_test.go index 6a60ccfff..f564f1b18 100644 --- a/x/rollapp/keeper/fraud_handler_test.go +++ b/x/rollapp/keeper/fraud_handler_test.go @@ -2,60 +2,88 @@ 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 +// FIXME: Liveness???? +// TestHardFork - Test the HardFork function +// - deleted states +// - pending queue is cleared up to the fraud height +// - revision number incremented func (suite *RollappTestSuite) TestHardFork() { - 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) + numOfFinalizedStates := uint64(10) 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) + 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}, + {"first batch not committed yet", 0, 0, 10, false}, + {"Fraud at future height", 10, 1, 300, false}, + + // error flows + {"height already finalized", numOfStates, numOfFinalizedStates, 20, true}, } - // 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) + for _, tc := range testCases { + suite.Run(tc.name, func() { + // Reset the state for the next test case + suite.SetupTest() + + initialHeight := uint64(1) + suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialHeight)) + + // unrelated rollapp just to validate it's unaffected + rollapp2, proposer2 := suite.CreateDefaultRollappAndProposer() + + // 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 + var lastHeight uint64 = 1 + for i := uint64(0); i < tc.statesCommitted; i++ { + _, err := suite.PostStateUpdate(suite.Ctx, rollappId, proposer, lastHeight, numOfBlocks) + suite.Require().NoError(err) + + lastHeight, err = suite.PostStateUpdate(suite.Ctx, rollapp2, proposer2, lastHeight, numOfBlocks) + suite.Require().NoError(err) + + suite.Ctx = suite.Ctx.WithBlockHeight(suite.Ctx.BlockHeader().Height + 1) + } + + // Assert initial stats (revision 0, states pending) + rollapp, found := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappId) + suite.Require().True(found) + suite.Require().Zero(rollapp.RevisionNumber) + + // check queue + queue := suite.App.RollappKeeper.GetAllFinalizationQueueUntilHeightInclusive(suite.Ctx, initialHeight+tc.statesCommitted+suite.App.RollappKeeper.DisputePeriodInBlocks(suite.Ctx)+110000000) + 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) + } + }) } - - // finalize some of the states - suite.App.RollappKeeper.FinalizeRollappStates(suite.Ctx.WithBlockHeight(20)) - - // assert before fraud submission - suite.assertBeforeFraud(rollapp, fraudHeight) - - err = keeper.HardFork(*ctx, rollapp, fraudHeight) - suite.Require().Nil(err) - - suite.assertFraudHandled(rollapp) } // Fail - Invalid rollapp @@ -68,49 +96,7 @@ func (suite *RollappTestSuite) TestHardFork_InvalidRollapp() { suite.Require().Nil(err) err = keeper.HardFork(*ctx, "invalidRollapp", 2) - suite.Require().NotNil(err) -} - -// Fail - Wrong height -func (suite *RollappTestSuite) TestHardFork_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.HardFork(*ctx, rollapp, 100) - suite.Require().NotNil(err) -} - -// Fail - Disputing already reverted state -func (suite *RollappTestSuite) TestHardFork_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.HardFork(*ctx, rollapp, 11) - suite.Require().Nil(err) - - err = keeper.HardFork(*ctx, rollapp, 1) - suite.Require().NotNil(err) + suite.Require().Error(err) } // Fail - Disputing already finalized state @@ -134,64 +120,27 @@ func (suite *RollappTestSuite) TestHardFork_AlreadyFinalized() { } /* ---------------------------------- 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().Zero(rollapp.RevisionNumber) - - // check sequencers - sequencers := suite.App.SequencerKeeper.GetSequencersByRollapp(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.GetBlockHeightToFinalizationQueue(suite.Ctx, expectedHeight) - 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) { +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 - 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) + // finalIdx, _ := suite.App.RollappKeeper.GetLatestFinalizedStateIndex(suite.Ctx, rollappId) + // startIdx := finalIdx.Index + 1 + lastestStateInfo, ok := suite.App.RollappKeeper.GetLatestStateInfo(suite.Ctx, rollappId) + if ok { + suite.Require().Equal(height-1, lastestStateInfo.GetLatestHeight()) } // check queue queue := suite.App.RollappKeeper.GetAllBlockHeightToFinalizationQueue(suite.Ctx) - suite.Greater(len(queue), 0) + suite.Require().Greater(len(queue), 0) for _, q := range queue { for _, stateInfoIndex := range q.FinalizationQueue { - suite.Require().NotEqual(rollappId, stateInfoIndex.RollappId) + if stateInfoIndex.RollappId == rollappId { + suite.Require().LessOrEqual(stateInfoIndex.Index, lastestStateInfo.StateInfoIndex.Index) + } } } } diff --git a/x/rollapp/types/genesis.pb.go b/x/rollapp/types/genesis.pb.go index 22a2a98f4..b296aa264 100644 --- a/x/rollapp/types/genesis.pb.go +++ b/x/rollapp/types/genesis.pb.go @@ -195,39 +195,39 @@ func init() { } var fileDescriptor_b76890aebc09aa04 = []byte{ - // 502 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0x4d, 0x6b, 0x13, 0x41, - 0x1c, 0xc6, 0xb3, 0xb6, 0x26, 0x66, 0xa2, 0x22, 0x83, 0xe0, 0x12, 0xec, 0x5a, 0x22, 0x68, 0x44, - 0xbb, 0x0b, 0xad, 0xe0, 0x4d, 0x30, 0xd6, 0x97, 0x40, 0xf1, 0x25, 0x55, 0x0f, 0x7a, 0x28, 0x9b, - 0xee, 0xbf, 0xdb, 0xc1, 0xcd, 0xcc, 0xb2, 0x33, 0x09, 0x49, 0x3e, 0x84, 0x78, 0xf0, 0x43, 0xf5, - 0xd8, 0xa3, 0x27, 0x91, 0xe4, 0x8b, 0xc8, 0xce, 0xfe, 0x67, 0x89, 0x95, 0x64, 0x02, 0x9e, 0xf6, - 0xed, 0x79, 0x7e, 0xcf, 0xb3, 0xc3, 0x7f, 0x86, 0x3c, 0x8a, 0x26, 0x03, 0xe0, 0x92, 0x09, 0x3e, - 0x9e, 0x4c, 0x83, 0xf2, 0x21, 0xc8, 0x44, 0x92, 0x84, 0x69, 0x1a, 0xc4, 0xc0, 0x41, 0x32, 0xe9, - 0xa7, 0x99, 0x50, 0x82, 0x7a, 0x8b, 0x6a, 0xbf, 0x7c, 0xf0, 0x51, 0xdd, 0xbc, 0x19, 0x8b, 0x58, - 0x68, 0x69, 0x90, 0xdf, 0x15, 0xae, 0xe6, 0x43, 0x4b, 0x46, 0x1a, 0x66, 0xe1, 0x00, 0x23, 0x9a, - 0xb6, 0x42, 0x78, 0x45, 0x75, 0x60, 0x51, 0x4b, 0x15, 0x2a, 0x38, 0x62, 0xfc, 0xc4, 0x74, 0xd9, - 0xb1, 0x18, 0x12, 0x36, 0xca, 0xff, 0xd8, 0xb4, 0x69, 0x5b, 0xe4, 0x65, 0x93, 0xd6, 0xb7, 0x1a, - 0xb9, 0xfa, 0xaa, 0x58, 0xac, 0xc3, 0x3c, 0x94, 0xee, 0x93, 0x6a, 0xf1, 0x63, 0xae, 0xb3, 0xed, - 0xb4, 0x1b, 0xbb, 0xf7, 0xfc, 0xd5, 0x8b, 0xe7, 0xbf, 0xd3, 0xea, 0xce, 0xe6, 0xd9, 0xaf, 0x3b, - 0x95, 0x1e, 0x7a, 0xe9, 0x5b, 0xd2, 0xc0, 0xef, 0x07, 0x4c, 0x2a, 0xf7, 0xd2, 0xf6, 0x46, 0xbb, - 0xb1, 0x7b, 0xdf, 0x86, 0xea, 0x15, 0x57, 0x64, 0x2d, 0x12, 0xe8, 0x47, 0x72, 0x4d, 0x2f, 0x4a, - 0x97, 0x9f, 0x08, 0x8d, 0xdc, 0xd0, 0xc8, 0x07, 0x36, 0xe4, 0xa1, 0x31, 0x21, 0xf4, 0x6f, 0x0a, - 0x4d, 0x89, 0x9b, 0x84, 0x0a, 0xa4, 0x2a, 0x75, 0x5d, 0x1e, 0xc1, 0x58, 0x27, 0x6c, 0xea, 0x04, - 0x7f, 0xed, 0x04, 0xed, 0xc4, 0x98, 0xa5, 0x54, 0x3a, 0x25, 0x5b, 0xc5, 0xb7, 0x97, 0x8c, 0x87, - 0x09, 0x9b, 0x42, 0x84, 0x22, 0x13, 0x7b, 0xf9, 0x3f, 0x62, 0x57, 0xa3, 0xe9, 0x0f, 0x87, 0xb4, - 0xfa, 0x89, 0x38, 0xfe, 0xfa, 0x1a, 0x58, 0x7c, 0xaa, 0x3e, 0x08, 0x14, 0x86, 0x8a, 0x09, 0xfe, - 0x7e, 0x08, 0x43, 0xd0, 0x0d, 0xaa, 0xba, 0xc1, 0x53, 0x5b, 0x83, 0xce, 0x4a, 0x12, 0x36, 0x5a, - 0x23, 0x8f, 0x7e, 0x21, 0xd7, 0xcd, 0xfc, 0xbe, 0x18, 0x01, 0x57, 0xd2, 0xad, 0xe9, 0x06, 0x3b, - 0xb6, 0x06, 0x07, 0x8b, 0x2e, 0x0c, 0xbc, 0x80, 0xa2, 0xcf, 0x49, 0xcd, 0x4c, 0xe1, 0x15, 0x4d, - 0xbd, 0x6b, 0xa3, 0x3e, 0x2b, 0x27, 0xd0, 0x38, 0x29, 0x23, 0x37, 0x32, 0x88, 0x99, 0x54, 0x90, - 0x41, 0xb4, 0x0f, 0x5c, 0x0c, 0xa4, 0x5b, 0xd7, 0xb4, 0x27, 0x6b, 0xce, 0x74, 0xef, 0x82, 0x1d, - 0x13, 0xfe, 0xc1, 0xb6, 0x3e, 0x91, 0x5b, 0x4b, 0x2c, 0x74, 0x8b, 0x10, 0xa4, 0x1e, 0xb1, 0x48, - 0x6f, 0xcf, 0x7a, 0xaf, 0x8e, 0x6f, 0xba, 0x11, 0xbd, 0x4d, 0xaa, 0x51, 0x51, 0x2d, 0xdf, 0x6e, - 0x75, 0xb3, 0x23, 0x8b, 0x77, 0x9d, 0x37, 0x67, 0x33, 0xcf, 0x39, 0x9f, 0x79, 0xce, 0xef, 0x99, - 0xe7, 0x7c, 0x9f, 0x7b, 0x95, 0xf3, 0xb9, 0x57, 0xf9, 0x39, 0xf7, 0x2a, 0x9f, 0x1f, 0xc7, 0x4c, - 0x9d, 0x0e, 0xfb, 0xfe, 0xb1, 0x18, 0x2c, 0x3b, 0x97, 0x46, 0x7b, 0xc1, 0xb8, 0x3c, 0x3c, 0xd4, - 0x24, 0x05, 0xd9, 0xaf, 0xea, 0xf3, 0x63, 0xef, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd7, 0xc7, - 0x8b, 0xbc, 0x8a, 0x05, 0x00, 0x00, + // 499 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0x4f, 0x8b, 0xd3, 0x40, + 0x18, 0xc6, 0x1b, 0x77, 0x6d, 0xed, 0x54, 0x45, 0x06, 0xd1, 0x50, 0xd8, 0xb8, 0x54, 0xd0, 0x8a, + 0x6e, 0x02, 0xbb, 0x82, 0x37, 0xc1, 0xba, 0xfe, 0x29, 0x2c, 0xba, 0x66, 0xf5, 0xa2, 0x87, 0x25, + 0xdd, 0xbc, 0x9b, 0x1d, 0x4c, 0x66, 0x42, 0x66, 0x5a, 0xda, 0x7e, 0x08, 0xf1, 0xe0, 0x87, 0xda, + 0xe3, 0x1e, 0x3d, 0x89, 0xb4, 0x5f, 0x44, 0x32, 0x79, 0x13, 0xea, 0x4a, 0x3b, 0x05, 0x4f, 0xe9, + 0x34, 0xcf, 0xf3, 0x7b, 0x9e, 0x0c, 0xef, 0x0c, 0x79, 0x12, 0x4e, 0x12, 0xe0, 0x92, 0x09, 0x3e, + 0x9e, 0x4c, 0xbd, 0x6a, 0xe1, 0x65, 0x22, 0x8e, 0x83, 0x34, 0xf5, 0x22, 0xe0, 0x20, 0x99, 0x74, + 0xd3, 0x4c, 0x28, 0x41, 0x9d, 0x45, 0xb5, 0x5b, 0x2d, 0x5c, 0x54, 0xb7, 0x6f, 0x47, 0x22, 0x12, + 0x5a, 0xea, 0xe5, 0xbf, 0x0a, 0x57, 0xfb, 0xb1, 0x21, 0x23, 0x0d, 0xb2, 0x20, 0xc1, 0x88, 0xb6, + 0xa9, 0x10, 0x3e, 0x51, 0xed, 0x19, 0xd4, 0x52, 0x05, 0x0a, 0x8e, 0x19, 0x3f, 0x2d, 0xbb, 0xec, + 0x18, 0x0c, 0x31, 0x1b, 0xe5, 0x5f, 0x5c, 0xb6, 0xe9, 0x1a, 0xe4, 0x55, 0x93, 0xce, 0xb7, 0x06, + 0xb9, 0xfe, 0xa6, 0xd8, 0xac, 0xa3, 0x3c, 0x94, 0xee, 0x93, 0x7a, 0xf1, 0x61, 0xb6, 0xb5, 0x6d, + 0x75, 0x5b, 0xbb, 0x0f, 0xdc, 0xd5, 0x9b, 0xe7, 0x1e, 0x6a, 0x75, 0x6f, 0xf3, 0xfc, 0xd7, 0xbd, + 0x9a, 0x8f, 0x5e, 0xfa, 0x9e, 0xb4, 0xf0, 0xfd, 0x01, 0x93, 0xca, 0xbe, 0xb2, 0xbd, 0xd1, 0x6d, + 0xed, 0x3e, 0x34, 0xa1, 0xfc, 0xe2, 0x89, 0xac, 0x45, 0x02, 0xfd, 0x44, 0x6e, 0xe8, 0x4d, 0xe9, + 0xf3, 0x53, 0xa1, 0x91, 0x1b, 0x1a, 0xf9, 0xc8, 0x84, 0x3c, 0x2a, 0x4d, 0x08, 0xfd, 0x9b, 0x42, + 0x53, 0x62, 0xc7, 0x81, 0x02, 0xa9, 0x2a, 0x5d, 0x9f, 0x87, 0x30, 0xd6, 0x09, 0x9b, 0x3a, 0xc1, + 0x5d, 0x3b, 0x41, 0x3b, 0x31, 0x66, 0x29, 0x95, 0x4e, 0xc9, 0x56, 0xf1, 0xee, 0x35, 0xe3, 0x41, + 0xcc, 0xa6, 0x10, 0xa2, 0xa8, 0x8c, 0xbd, 0xfa, 0x1f, 0xb1, 0xab, 0xd1, 0xf4, 0x87, 0x45, 0x3a, + 0x83, 0x58, 0x9c, 0x7c, 0x7d, 0x0b, 0x2c, 0x3a, 0x53, 0x1f, 0x05, 0x0a, 0x03, 0xc5, 0x04, 0xff, + 0x30, 0x84, 0x21, 0xe8, 0x06, 0x75, 0xdd, 0xe0, 0xb9, 0xa9, 0x41, 0x6f, 0x25, 0x09, 0x1b, 0xad, + 0x91, 0x47, 0xbf, 0x90, 0x9b, 0xe5, 0xfc, 0xbe, 0x1a, 0x01, 0x57, 0xd2, 0x6e, 0xe8, 0x06, 0x3b, + 0xa6, 0x06, 0x07, 0x8b, 0x2e, 0x0c, 0xbc, 0x84, 0xa2, 0x2f, 0x49, 0xa3, 0x9c, 0xc2, 0x6b, 0x9a, + 0x7a, 0xdf, 0x44, 0x7d, 0x51, 0x4d, 0x60, 0xe9, 0xa4, 0x8c, 0xdc, 0xca, 0x20, 0x62, 0x52, 0x41, + 0x06, 0xe1, 0x3e, 0x70, 0x91, 0x48, 0xbb, 0xa9, 0x69, 0xcf, 0xd6, 0x9c, 0x69, 0xff, 0x92, 0x1d, + 0x13, 0xfe, 0xc1, 0x76, 0x0e, 0xc9, 0xdd, 0x25, 0x16, 0xba, 0x45, 0x08, 0x52, 0x8f, 0x59, 0xa8, + 0x8f, 0x67, 0xd3, 0x6f, 0xe2, 0x3f, 0xfd, 0x90, 0xde, 0x21, 0xf5, 0xb0, 0xa8, 0x96, 0x1f, 0xb7, + 0xa6, 0x8f, 0xab, 0xde, 0xbb, 0xf3, 0x99, 0x63, 0x5d, 0xcc, 0x1c, 0xeb, 0xf7, 0xcc, 0xb1, 0xbe, + 0xcf, 0x9d, 0xda, 0xc5, 0xdc, 0xa9, 0xfd, 0x9c, 0x3b, 0xb5, 0xcf, 0x4f, 0x23, 0xa6, 0xce, 0x86, + 0x03, 0xf7, 0x44, 0x24, 0xcb, 0x6e, 0xa4, 0xd1, 0x9e, 0x37, 0xae, 0xae, 0x0d, 0x35, 0x49, 0x41, + 0x0e, 0xea, 0xfa, 0xe6, 0xd8, 0xfb, 0x13, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x9d, 0x0c, 0xa4, 0x84, + 0x05, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { diff --git a/x/rollapp/types/rollapp.pb.go b/x/rollapp/types/rollapp.pb.go index 875ad8fb6..47fe08d19 100644 --- a/x/rollapp/types/rollapp.pb.go +++ b/x/rollapp/types/rollapp.pb.go @@ -147,8 +147,8 @@ 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 from 1 - RevisionNumber int64 `protobuf:"varint,19,opt,name=revision_number,json=revisionNumber,proto3" json:"revision_number,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"` } func (m *Rollapp) Reset() { *m = Rollapp{} } @@ -268,7 +268,7 @@ func (m *Rollapp) GetLastStateUpdateHeight() int64 { return 0 } -func (m *Rollapp) GetRevisionNumber() int64 { +func (m *Rollapp) GetRevisionNumber() uint64 { if m != nil { return m.RevisionNumber } @@ -402,20 +402,20 @@ var fileDescriptor_d4ef2bec3aea5528 = []byte{ 0x65, 0xa5, 0x21, 0xb4, 0x72, 0xfa, 0x6a, 0x0a, 0x1e, 0xc6, 0xd8, 0x31, 0x83, 0xf0, 0xff, 0x48, 0x71, 0xcc, 0x30, 0x4a, 0x9e, 0x8b, 0x31, 0xf6, 0xad, 0xf8, 0xe0, 0x34, 0xcc, 0x68, 0xeb, 0x31, 0xce, 0xae, 0xff, 0x8c, 0xa1, 0x9c, 0xf8, 0x2f, 0xaa, 0x06, 0x30, 0x21, 0x71, 0xf7, 0x06, 0x1d, - 0xbb, 0x7d, 0x08, 0x94, 0x55, 0x16, 0x5f, 0x49, 0xdd, 0x27, 0xcc, 0xdb, 0xdc, 0x46, 0xf9, 0x64, - 0x1a, 0xb8, 0x8a, 0x4a, 0x67, 0x34, 0xf4, 0x61, 0x40, 0x86, 0x04, 0x2c, 0x39, 0x83, 0x0b, 0x28, - 0x77, 0x78, 0xde, 0x95, 0x05, 0x2c, 0x21, 0xf1, 0xdd, 0xab, 0x5e, 0x57, 0xce, 0x76, 0x44, 0x29, - 0x27, 0x17, 0x3a, 0xa2, 0x54, 0x94, 0x51, 0x47, 0x94, 0x90, 0x5c, 0x6a, 0x7e, 0xce, 0xa2, 0x0a, - 0x1f, 0x6b, 0x6f, 0xec, 0xba, 0x66, 0x30, 0xc5, 0xff, 0xa0, 0x87, 0x4d, 0x78, 0xbc, 0x1a, 0x17, - 0x48, 0x76, 0xcc, 0x08, 0x78, 0xd1, 0x6d, 0x6a, 0xc1, 0x25, 0xdb, 0x92, 0xd2, 0xe2, 0xeb, 0xe3, - 0x8c, 0xa1, 0xc7, 0x58, 0xfa, 0x23, 0x1d, 0xec, 0xa0, 0xbf, 0x13, 0xdf, 0x6b, 0x42, 0x4d, 0x87, - 0x5c, 0x81, 0x35, 0x97, 0x24, 0xf7, 0x47, 0x49, 0x9e, 0x17, 0xc4, 0x4d, 0x54, 0x4e, 0xc0, 0x64, - 0xe6, 0x8a, 0xd8, 0x10, 0x5a, 0xa2, 0xfe, 0x93, 0x0f, 0xef, 0xa3, 0xf5, 0x5f, 0x04, 0x78, 0xf0, - 0x12, 0x0b, 0x7e, 0x1a, 0x3c, 0x38, 0xb9, 0xb9, 0xab, 0x0b, 0xb7, 0x77, 0x75, 0xe1, 0xfb, 0x5d, - 0x5d, 0xb8, 0xbe, 0xaf, 0x67, 0x6e, 0xef, 0xeb, 0x99, 0x2f, 0xf7, 0xf5, 0xcc, 0xc5, 0xbe, 0x4d, - 0xa2, 0xd1, 0xb8, 0xaf, 0x0e, 0x3c, 0xf7, 0xb9, 0x7f, 0xed, 0x64, 0x4f, 0xbb, 0x9c, 0xfd, 0x10, - 0xe3, 0xed, 0x08, 0xfb, 0x79, 0xf6, 0x46, 0xf7, 0x7e, 0x04, 0x00, 0x00, 0xff, 0xff, 0x69, 0x62, - 0xfa, 0x9a, 0x3d, 0x06, 0x00, 0x00, + 0xbb, 0x7d, 0x08, 0x94, 0xd5, 0x86, 0xd0, 0x12, 0xf5, 0x4a, 0xea, 0x3e, 0x61, 0xde, 0xe6, 0x36, + 0xca, 0x27, 0xd3, 0xc0, 0x55, 0x54, 0x3a, 0xa3, 0xa1, 0x0f, 0x03, 0x32, 0x24, 0x60, 0xc9, 0x19, + 0x5c, 0x40, 0xb9, 0xc3, 0xf3, 0xae, 0x2c, 0x60, 0x09, 0x89, 0xef, 0x5e, 0xf5, 0xba, 0x72, 0xb6, + 0x23, 0x4a, 0x39, 0xb9, 0xd0, 0x11, 0xa5, 0xa2, 0x8c, 0x3a, 0xa2, 0x84, 0xe4, 0x52, 0xf3, 0x73, + 0x16, 0x55, 0xf8, 0x58, 0x7b, 0x63, 0xd7, 0x35, 0x83, 0x29, 0xfe, 0x07, 0x3d, 0x6c, 0xc2, 0xe3, + 0xd5, 0xb8, 0x40, 0xb2, 0x63, 0x46, 0xc0, 0x8b, 0x6e, 0x53, 0x0b, 0x2e, 0xd9, 0x96, 0x94, 0x16, + 0x5f, 0x1f, 0x67, 0x0c, 0x3d, 0xc6, 0xd2, 0x1f, 0xe9, 0x60, 0x07, 0xfd, 0x9d, 0xf8, 0x5e, 0x13, + 0x6a, 0x3a, 0xe4, 0x0a, 0xac, 0xb9, 0x24, 0xb9, 0x3f, 0x4a, 0xf2, 0xbc, 0x20, 0x6e, 0xa2, 0x72, + 0x02, 0x26, 0x33, 0x57, 0x44, 0x36, 0xe0, 0x9f, 0x7c, 0x78, 0x1f, 0xad, 0xff, 0x22, 0xc0, 0x83, + 0x97, 0x58, 0xf0, 0xd3, 0xe0, 0xc1, 0xc9, 0xcd, 0x5d, 0x5d, 0xb8, 0xbd, 0xab, 0x0b, 0xdf, 0xef, + 0xea, 0xc2, 0xf5, 0x7d, 0x3d, 0x73, 0x7b, 0x5f, 0xcf, 0x7c, 0xb9, 0xaf, 0x67, 0x2e, 0xf6, 0x6d, + 0x12, 0x8d, 0xc6, 0x7d, 0x75, 0xe0, 0xb9, 0xcf, 0xfd, 0x6b, 0x27, 0x7b, 0xda, 0xe5, 0xec, 0x87, + 0x18, 0x6f, 0x47, 0xd8, 0xcf, 0xb3, 0x37, 0xba, 0xf7, 0x23, 0x00, 0x00, 0xff, 0xff, 0xe9, 0x06, + 0x28, 0xa6, 0x3d, 0x06, 0x00, 0x00, } func (m *RollappGenesisState) Marshal() (dAtA []byte, err error) { @@ -1210,7 +1210,7 @@ func (m *Rollapp) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.RevisionNumber |= int64(b&0x7F) << shift + m.RevisionNumber |= uint64(b&0x7F) << shift if b < 0x80 { break } From 654b06946fae2e7d19897d8c2c7a98416ec6a9ab Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 27 Oct 2024 15:08:23 +0200 Subject: [PATCH 07/68] UT pass --- x/rollapp/genesis_test.go | 2 +- x/rollapp/keeper/fraud_handler.go | 2 - x/rollapp/keeper/fraud_handler_test.go | 32 ++++--- .../keeper/grpc_query_state_info_test.go | 3 +- .../keeper/msg_server_create_rollapp_test.go | 93 +------------------ x/rollapp/keeper/rollapp.go | 5 - x/rollapp/types/chain_id.go | 5 + 7 files changed, 31 insertions(+), 111 deletions(-) diff --git a/x/rollapp/genesis_test.go b/x/rollapp/genesis_test.go index 18f9500dc..1f931a42e 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/fraud_handler.go b/x/rollapp/keeper/fraud_handler.go index 6dcc72cd8..c14d11a24 100644 --- a/x/rollapp/keeper/fraud_handler.go +++ b/x/rollapp/keeper/fraud_handler.go @@ -50,8 +50,6 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeight uint64) error { // find the affected state info index // skip if not found (fraud height is not committed yet) - - // FIXME: can we hard fork over uncommitted height?? stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, fraudHeight) if errorsmod.IsOf(err, gerrc.ErrNotFound) { return nil diff --git a/x/rollapp/keeper/fraud_handler_test.go b/x/rollapp/keeper/fraud_handler_test.go index f564f1b18..414322bd3 100644 --- a/x/rollapp/keeper/fraud_handler_test.go +++ b/x/rollapp/keeper/fraud_handler_test.go @@ -44,6 +44,15 @@ func (suite *RollappTestSuite) TestHardFork() { // 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() @@ -52,15 +61,11 @@ func (suite *RollappTestSuite) TestHardFork() { } // send state updates - var lastHeight uint64 = 1 + lastHeight = 1 for i := uint64(0); i < tc.statesCommitted; i++ { - _, err := suite.PostStateUpdate(suite.Ctx, rollappId, proposer, lastHeight, numOfBlocks) + suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialHeight + i)) + lastHeight, err = suite.PostStateUpdate(suite.Ctx, rollappId, proposer, lastHeight, numOfBlocks) suite.Require().NoError(err) - - lastHeight, err = suite.PostStateUpdate(suite.Ctx, rollapp2, proposer2, lastHeight, numOfBlocks) - suite.Require().NoError(err) - - suite.Ctx = suite.Ctx.WithBlockHeight(suite.Ctx.BlockHeader().Height + 1) } // Assert initial stats (revision 0, states pending) @@ -69,13 +74,13 @@ func (suite *RollappTestSuite) TestHardFork() { suite.Require().Zero(rollapp.RevisionNumber) // check queue - queue := suite.App.RollappKeeper.GetAllFinalizationQueueUntilHeightInclusive(suite.Ctx, initialHeight+tc.statesCommitted+suite.App.RollappKeeper.DisputePeriodInBlocks(suite.Ctx)+110000000) - suite.Require().Len(queue, int(tc.statesCommitted)) + queue := suite.App.RollappKeeper.GetAllFinalizationQueueUntilHeightInclusive(suite.Ctx, initialHeight+numOfStates+suite.App.RollappKeeper.DisputePeriodInBlocks(suite.Ctx)) + suite.Require().Len(queue, int(numOfStates)) // 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) + err = suite.App.RollappKeeper.HardFork(suite.Ctx, rollappId, tc.fraudHeight) if tc.expectError { suite.Require().Error(err) } else { @@ -125,12 +130,11 @@ func (suite *RollappTestSuite) assertFraudHandled(rollappId string, height uint6 suite.Require().True(found) suite.Require().Equal(uint64(1), rollapp.RevisionNumber) - // check states - // finalIdx, _ := suite.App.RollappKeeper.GetLatestFinalizedStateIndex(suite.Ctx, rollappId) - // startIdx := finalIdx.Index + 1 + // 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().Equal(height-1, lastestStateInfo.GetLatestHeight()) + suite.Require().Less(lastestStateInfo.GetLatestHeight(), height) } // check queue 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/msg_server_create_rollapp_test.go b/x/rollapp/keeper/msg_server_create_rollapp_test.go index f42afd7d1..132fb7b7f 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,18 +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() - suite.App.RollappKeeper.SetRollapp(suite.Ctx, r) - }, - expErr: types.ErrRollappExists, - }, { - name: "different rollapp, revision not 1", - rollappId: "trollapp_2345-2", - expErr: types.ErrInvalidRollappID, }, } for _, test := range tests { @@ -96,10 +83,6 @@ func (suite *RollappTestSuite) TestCreateRollappAlreadyExists() { GenesisInfo: mockGenesisInfo, } - if test.malleate != nil { - test.malleate() - } - suite.FundForAliasRegistration(newRollapp) _, err := suite.msgServer.CreateRollapp(goCtx, &newRollapp) @@ -158,6 +141,11 @@ func (suite *RollappTestSuite) TestCreateRollappId() { rollappId: "rollapp_1234-x", expErr: types.ErrInvalidRollappID, }, + { + name: "non 1 revision", + rollappId: "rollapp_1234-2", + expErr: types.ErrInvalidRollappID, + }, } for _, test := range tests { suite.Run(test.name, func() { @@ -168,77 +156,6 @@ func (suite *RollappTestSuite) TestCreateRollappId() { } } -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) - - 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/rollapp.go b/x/rollapp/keeper/rollapp.go index 65e698945..c95e36b92 100644 --- a/x/rollapp/keeper/rollapp.go +++ b/x/rollapp/keeper/rollapp.go @@ -85,11 +85,6 @@ func (k Keeper) CheckIfRollappExists(ctx sdk.Context, rollappId types.ChainID) e 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 } diff --git a/x/rollapp/types/chain_id.go b/x/rollapp/types/chain_id.go index a4766c6af..990a5b1e2 100644 --- a/x/rollapp/types/chain_id.go +++ b/x/rollapp/types/chain_id.go @@ -59,6 +59,11 @@ func NewChainID(id string) (ChainID, error) { return ChainID{}, errorsmod.Wrapf(ErrInvalidRollappID, "parse revision number: error: %v", err) } + // when creating a new Rollapp, the revision number should always be 1 + if revision != 1 { + return ChainID{}, errorsmod.Wrapf(ErrInvalidRollappID, "revision number should be 1, got: %d", revision) + } + return ChainID{ chainID: chainID, eip155ID: chainIDInt, From 6782578b61542ff5ac7658e97585b93019181685 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Mon, 28 Oct 2024 14:26:46 +0200 Subject: [PATCH 08/68] fixed StateInfoByHeight UT --- ibctesting/delayed_ack_test.go | 2 + ...rpc_query_get_state_info_by_height_test.go | 109 +++++++----------- 2 files changed, 42 insertions(+), 69 deletions(-) diff --git a/ibctesting/delayed_ack_test.go b/ibctesting/delayed_ack_test.go index 1eb90a508..a6d1d649f 100644 --- a/ibctesting/delayed_ack_test.go +++ b/ibctesting/delayed_ack_test.go @@ -235,3 +235,5 @@ func (s *delayedAckSuite) TestHubToRollappTimeout() { postFinalizeBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) s.Require().Equal(preSendBalance.Amount, postFinalizeBalance.Amount) } + +// FIXME: test refunds due to hard fork + receipt deletion 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 +} From c4d25ac9c1209e7f12d3e27f6867c47b8f5969f7 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Mon, 28 Oct 2024 14:54:56 +0200 Subject: [PATCH 09/68] chainId revision check moved back to create rollapp. as it mess up dymns UT --- x/rollapp/keeper/msg_server_create_rollapp.go | 6 ++++++ .../keeper/msg_server_mark_vulnerable_rollapps_test.go | 4 ++-- x/rollapp/types/chain_id.go | 5 ----- x/rollapp/types/errors.go | 1 - 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/x/rollapp/keeper/msg_server_create_rollapp.go b/x/rollapp/keeper/msg_server_create_rollapp.go index 66a720378..ab25d3e05 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,11 @@ 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 revision number should always be 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_mark_vulnerable_rollapps_test.go b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go index 8c493dd9c..dfac07a7d 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go +++ b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go @@ -114,9 +114,9 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { // prepare test data vulnVersions := uslice.ToKeySet(tc.vulnVersions) // list of expected vulnerable rollapps - expectedVulnRollappIDs := make([]string, 0, len(tc.vulnVersions)) + expectedVulnRollappIDs := make([]string, 0, len(tc.rollapps)) // list of expected non-vulnerable rollapps - expectedNonVulnRollappIDs := make([]string, 0, len(tc.vulnVersions)) + expectedNonVulnRollappIDs := make([]string, 0, len(tc.rollapps)) // create rollapps for every rollapp record from the test case for _, ra := range tc.rollapps { // create a rollapp diff --git a/x/rollapp/types/chain_id.go b/x/rollapp/types/chain_id.go index 990a5b1e2..a4766c6af 100644 --- a/x/rollapp/types/chain_id.go +++ b/x/rollapp/types/chain_id.go @@ -59,11 +59,6 @@ func NewChainID(id string) (ChainID, error) { return ChainID{}, errorsmod.Wrapf(ErrInvalidRollappID, "parse revision number: error: %v", err) } - // when creating a new Rollapp, the revision number should always be 1 - if revision != 1 { - return ChainID{}, errorsmod.Wrapf(ErrInvalidRollappID, "revision number should be 1, got: %d", revision) - } - return ChainID{ chainID: chainID, eip155ID: chainIDInt, diff --git a/x/rollapp/types/errors.go b/x/rollapp/types/errors.go index c0a8851e7..77117affc 100644 --- a/x/rollapp/types/errors.go +++ b/x/rollapp/types/errors.go @@ -52,7 +52,6 @@ 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") From 3e06f201241886f4f347e63fab5871b7653da386 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 30 Oct 2024 21:11:52 +0200 Subject: [PATCH 10/68] PR comments --- x/rollapp/keeper/fraud_handler.go | 55 +++++++++++++------------------ 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/x/rollapp/keeper/fraud_handler.go b/x/rollapp/keeper/fraud_handler.go index c14d11a24..762761a65 100644 --- a/x/rollapp/keeper/fraud_handler.go +++ b/x/rollapp/keeper/fraud_handler.go @@ -19,6 +19,14 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) return gerrc.ErrNotFound } + // FIXME: enable later on + /* + // enforce the assumption that genesis transfer is completed before hard fork + if !rollapp.IsTransferEnabled() { + return errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "can't hard fork before transfer is enabled") + } + */ + err := k.RevertPendingStates(ctx, rollappID, fraudHeight) if err != nil { return errorsmod.Wrap(err, "revert pending states") @@ -62,10 +70,14 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig return errorsmod.Wrapf(types.ErrDisputeAlreadyFinalized, "state info for height %d is already finalized", fraudHeight) } + lastStateIdxToKeep := stateInfo.StateInfoIndex.Index // trunc the state info if needed - lastStateIdxToKeep, err := k.TruncStateInfo(ctx, stateInfo, fraudHeight) - if err != nil { - return errorsmod.Wrap(err, "trunc state info") + if stateInfo.StartHeight == fraudHeight { + // If fraud height is at the beginning of the state info, return the previous index to keep + lastStateIdxToKeep -= 1 + } else { + // otherwise, truncate the state info + k.TruncStateInfo(ctx, stateInfo, fraudHeight) } // clear state info @@ -80,10 +92,11 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig Index: lastStateIdxToKeep, }) - // TODO (#631): Prefix store by rollappID for efficient querying - queuePerHeight := k.GetAllBlockHeightToFinalizationQueue(ctx) - - revertedQueueCount := 0 + // remove all the pending states from the finalization queue + // we iterate over the queue, + // - skipping the states that are not related to the rollapp + // - skipping the states that are less than the rollback index + queuePerHeight := k.GetAllBlockHeightToFinalizationQueue(ctx) // FIXME (#631): Prefix store by rollappID for efficient querying for _, queue := range queuePerHeight { leftPendingStates := []types.StateInfoIndex{} for _, stateInfoIndex := range queue.FinalizationQueue { @@ -98,9 +111,6 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig leftPendingStates = append(leftPendingStates, stateInfoIndex) continue } - - // remove the state info index from the queue - revertedQueueCount++ } // no change in the queue @@ -121,11 +131,6 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig }) } - // FIXME: remove. this is probably more invariant check - if revertedQueueCount != revertedStatesCount { - return fmt.Errorf("reverted state updates count mismatch: states: %d, queue: %d", revertedStatesCount, revertedQueueCount) - } - ctx.Logger().Info(fmt.Sprintf("Reverted state updates for rollapp: %s, count: %d", rollappID, revertedStatesCount)) return nil @@ -133,23 +138,9 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig // TruncStateInfo truncates the state info to the last valid block before the fraud height. // It returns the index of the last state info to keep. -func (k Keeper) TruncStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) (uint64, error) { - // If fraud height is at the beginning of the state info, return the previous index to keep - if stateInfo.StartHeight == fraudHeight { - return stateInfo.StateInfoIndex.Index - 1, nil - } - - // Otherwise, create a new state info with the truncated height - heightToKeep := fraudHeight - 1 - +func (k Keeper) TruncStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) { // Remove block descriptors until the one we need to rollback to - var truncatedBDs []types.BlockDescriptor - for i, bd := range stateInfo.BDs.BD { - if bd.Height > heightToKeep { - truncatedBDs = stateInfo.BDs.BD[:i] - break - } - } + truncatedBDs := stateInfo.BDs.BD[:fraudHeight-stateInfo.StartHeight] // Update the state info to reflect truncated data stateInfo.NumBlocks = uint64(len(truncatedBDs)) @@ -157,6 +148,4 @@ func (k Keeper) TruncStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, frau // Update the state info in the keeper k.SetStateInfo(ctx, *stateInfo) - - return stateInfo.StateInfoIndex.Index, nil } From 411f4c52941bda68cc53ed63e0c0c51fc40d8e8d Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 30 Oct 2024 21:56:52 +0200 Subject: [PATCH 11/68] fixed basic sequencer logic to unbond all --- x/sequencer/keeper/hook_listener.go | 22 ++++------------------ x/sequencer/keeper/hooks_test.go | 8 +------- x/sequencer/keeper/unbond.go | 2 +- 3 files changed, 6 insertions(+), 26 deletions(-) diff --git a/x/sequencer/keeper/hook_listener.go b/x/sequencer/keeper/hook_listener.go index 38f480f2c..3ea185a73 100644 --- a/x/sequencer/keeper/hook_listener.go +++ b/x/sequencer/keeper/hook_listener.go @@ -49,22 +49,8 @@ func (hook rollappHook) BeforeUpdateState(ctx sdk.Context, seqAddr, rollappId st } // OnHardFork implements the RollappHooks interface -// It slashes the sequencer and unbonds all other bonded sequencers -func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappID string, height uint64) error { - - // FIXME: probably need to validate we have active proposer - /* - err := hook.k.JailSequencerOnFraud(ctx, seqAddr) - if err != nil { - return err - } - - // unbond all other other rollapp sequencers - err = hook.k.InstantUnbondAllSequencers(ctx, rollappID) - if err != nil { - return err - } - */ - - return nil +// 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 { + return hook.k.InstantUnbondAllSequencers(ctx, rollappID) } diff --git a/x/sequencer/keeper/hooks_test.go b/x/sequencer/keeper/hooks_test.go index 0f5836168..876077b10 100644 --- a/x/sequencer/keeper/hooks_test.go +++ b/x/sequencer/keeper/hooks_test.go @@ -43,14 +43,8 @@ func (suite *SequencerTestSuite) TestFraudSubmittedHook() { err = keeper.RollappHooks().OnHardFork(suite.Ctx, rollappId, 0) suite.Require().NoError(err) - // check if proposer is slashed - sequencer, found := keeper.GetSequencer(suite.Ctx, proposer) - suite.Require().True(found) - suite.Require().True(sequencer.Jailed) - suite.Require().Equal(sequencer.Status, types.Unbonded) - // check if other sequencers are unbonded - for i := 1; i < numOfSequencers; i++ { + for i := 0; i < numOfSequencers; i++ { sequencer, found := keeper.GetSequencer(suite.Ctx, seqAddrs[i]) suite.Require().True(found) suite.Require().Equal(sequencer.Status, types.Unbonded) diff --git a/x/sequencer/keeper/unbond.go b/x/sequencer/keeper/unbond.go index b6df29000..5d64fe34c 100644 --- a/x/sequencer/keeper/unbond.go +++ b/x/sequencer/keeper/unbond.go @@ -59,7 +59,7 @@ func (k Keeper) InstantUnbondAllSequencers(ctx sdk.Context, rollappID string) er for _, sequencer := range append(bonded, unbonding...) { err := k.unbondSequencer(ctx, sequencer.Address) if err != nil { - return err + k.Logger(ctx).Error("unbond sequencer", "error", err, "sequencer", sequencer.Address) } } From b08a10691f3cded57aed831dbf9361f7bfae7535 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Thu, 31 Oct 2024 10:51:46 +0200 Subject: [PATCH 12/68] feat(hard_fork): part2 (Delyayed ack callback) (#1355) --- app/keepers/keepers.go | 1 + .../dymension/common/status.proto | 1 - testutil/keeper/delayedack.go | 1 + x/common/types/key_rollapp_packet.go | 4 - x/common/types/status.pb.go | 18 ++-- x/delayedack/client/cli/query.go | 4 +- x/delayedack/keeper/finalize.go | 42 ++------ x/delayedack/keeper/finalize_test.go | 2 +- x/delayedack/keeper/fraud.go | 35 +++--- x/delayedack/keeper/fraud_test.go | 63 ++++------- x/delayedack/keeper/grpc_query.go | 2 +- x/delayedack/keeper/hooks.go | 4 +- x/delayedack/keeper/invariants.go | 67 +++--------- x/delayedack/keeper/invariants_test.go | 102 +++++------------- x/delayedack/keeper/keeper.go | 37 +++---- x/delayedack/keeper/rollapp_packet.go | 27 ++++- x/delayedack/keeper/rollapp_packet_test.go | 49 +++++---- x/delayedack/keeper/transfer.go | 5 +- x/delayedack/rollapp_hooks.go | 2 +- .../types/rollapp_packets_list_filter.go | 15 ++- .../types/rollapp_packets_list_filter_test.go | 83 +++++++++----- x/eibc/client/cli/query_command_orders.go | 2 +- x/eibc/genesis_test.go | 2 +- x/eibc/keeper/grpc_query.go | 2 +- x/eibc/keeper/grpc_query_test.go | 2 +- x/eibc/keeper/hooks.go | 3 +- x/eibc/keeper/hooks_test.go | 17 ++- x/eibc/keeper/invariants.go | 11 +- x/eibc/keeper/invariants_test.go | 4 +- x/eibc/keeper/keeper.go | 2 - x/eibc/types/keys.go | 4 - 31 files changed, 260 insertions(+), 353 deletions(-) diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 5d494e6c5..dff448404 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -475,6 +475,7 @@ func (a *AppKeepers) InitKeepers( a.DelayedAckKeeper = *delayedackkeeper.NewKeeper( appCodec, a.keys[delayedacktypes.StoreKey], + a.keys[ibcexported.StoreKey], a.GetSubspace(delayedacktypes.ModuleName), a.RollappKeeper, a.IBCKeeper.ChannelKeeper, diff --git a/proto/dymensionxyz/dymension/common/status.proto b/proto/dymensionxyz/dymension/common/status.proto index 432a15a15..3cb04faa4 100644 --- a/proto/dymensionxyz/dymension/common/status.proto +++ b/proto/dymensionxyz/dymension/common/status.proto @@ -8,5 +8,4 @@ option go_package = "github.com/dymensionxyz/dymension/v3/x/common/types"; enum Status { PENDING = 0; FINALIZED = 1; - REVERTED = 3; } diff --git a/testutil/keeper/delayedack.go b/testutil/keeper/delayedack.go index 442336c73..019ec85a6 100644 --- a/testutil/keeper/delayedack.go +++ b/testutil/keeper/delayedack.go @@ -137,6 +137,7 @@ func DelayedackKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { k := keeper.NewKeeper(cdc, storeKey, + nil, paramsSubspace, RollappKeeperStub{}, ICS4WrapperStub{}, diff --git a/x/common/types/key_rollapp_packet.go b/x/common/types/key_rollapp_packet.go index 3f79ebb16..9566d4303 100644 --- a/x/common/types/key_rollapp_packet.go +++ b/x/common/types/key_rollapp_packet.go @@ -18,8 +18,6 @@ var ( PendingRollappPacketKeyPrefix = []byte{0x00, 0x01} // FinalizedRollappPacketKeyPrefix is the prefix for finalized rollapp packets FinalizedRollappPacketKeyPrefix = []byte{0x00, 0x02} - // RevertedRollappPacketKeyPrefix is the prefix for reverted rollapp packets - RevertedRollappPacketKeyPrefix = []byte{0x00, 0x03} // keySeparatorBytes is used to separate the rollapp packet key parts keySeparatorBytes = []byte("/") ) @@ -100,8 +98,6 @@ func MustGetStatusBytes(status Status) []byte { return PendingRollappPacketKeyPrefix case Status_FINALIZED: return FinalizedRollappPacketKeyPrefix - case Status_REVERTED: - return RevertedRollappPacketKeyPrefix default: panic(fmt.Sprintf("invalid packet status: %s", status)) } diff --git a/x/common/types/status.pb.go b/x/common/types/status.pb.go index dbf4fdfc2..a803d617f 100644 --- a/x/common/types/status.pb.go +++ b/x/common/types/status.pb.go @@ -26,19 +26,16 @@ type Status int32 const ( Status_PENDING Status = 0 Status_FINALIZED Status = 1 - Status_REVERTED Status = 3 ) var Status_name = map[int32]string{ 0: "PENDING", 1: "FINALIZED", - 3: "REVERTED", } var Status_value = map[string]int32{ "PENDING": 0, "FINALIZED": 1, - "REVERTED": 3, } func (x Status) String() string { @@ -58,17 +55,16 @@ func init() { } var fileDescriptor_acfb62db52f6fda8 = []byte{ - // 190 bytes of a gzipped FileDescriptorProto + // 176 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4a, 0xa9, 0xcc, 0x4d, 0xcd, 0x2b, 0xce, 0xcc, 0xcf, 0xab, 0xa8, 0xac, 0xd2, 0x87, 0x73, 0xf4, 0x93, 0xf3, 0x73, 0x73, 0xf3, 0xf3, 0xf4, 0x8b, 0x4b, 0x12, 0x4b, 0x4a, 0x8b, 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0x64, 0x91, 0xd5, 0xea, 0xc1, 0x39, 0x7a, 0x10, 0xb5, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, - 0x95, 0xfa, 0x20, 0x16, 0x44, 0x93, 0x96, 0x11, 0x17, 0x5b, 0x30, 0xd8, 0x10, 0x21, 0x6e, 0x2e, + 0x95, 0xfa, 0x20, 0x16, 0x44, 0x93, 0x96, 0x0a, 0x17, 0x5b, 0x30, 0xd8, 0x10, 0x21, 0x6e, 0x2e, 0xf6, 0x00, 0x57, 0x3f, 0x17, 0x4f, 0x3f, 0x77, 0x01, 0x06, 0x21, 0x5e, 0x2e, 0x4e, 0x37, 0x4f, - 0x3f, 0x47, 0x1f, 0xcf, 0x28, 0x57, 0x17, 0x01, 0x46, 0x21, 0x1e, 0x2e, 0x8e, 0x20, 0xd7, 0x30, - 0xd7, 0xa0, 0x10, 0x57, 0x17, 0x01, 0x66, 0x27, 0xdf, 0x13, 0x8f, 0xe4, 0x18, 0x2f, 0x3c, 0x92, - 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, 0x6e, 0x3c, - 0x96, 0x63, 0x88, 0x32, 0x4e, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0x02, 0x59, 0xa9, 0x8f, 0xc3, 0xe5, - 0x65, 0xc6, 0xfa, 0x15, 0x30, 0xe7, 0x97, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0x5d, 0x62, - 0x0c, 0x08, 0x00, 0x00, 0xff, 0xff, 0x50, 0xdb, 0xd7, 0x0d, 0xec, 0x00, 0x00, 0x00, + 0x3f, 0x47, 0x1f, 0xcf, 0x28, 0x57, 0x17, 0x01, 0x46, 0x27, 0xdf, 0x13, 0x8f, 0xe4, 0x18, 0x2f, + 0x3c, 0x92, 0x63, 0x7c, 0xf0, 0x48, 0x8e, 0x71, 0xc2, 0x63, 0x39, 0x86, 0x0b, 0x8f, 0xe5, 0x18, + 0x6e, 0x3c, 0x96, 0x63, 0x88, 0x32, 0x4e, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, 0x02, 0x59, 0xa2, 0x8f, + 0xc3, 0xad, 0x65, 0xc6, 0xfa, 0x15, 0x30, 0x07, 0x97, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, + 0xed, 0x36, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0x19, 0xa7, 0x17, 0xce, 0xde, 0x00, 0x00, 0x00, } diff --git a/x/delayedack/client/cli/query.go b/x/delayedack/client/cli/query.go index aac99e140..3779759d9 100644 --- a/x/delayedack/client/cli/query.go +++ b/x/delayedack/client/cli/query.go @@ -62,7 +62,7 @@ func CmdGetPacketsByRollapp() *cobra.Command { cmd := &cobra.Command{ Use: "packets-by-rollapp rollapp-id [status] [type]", Short: "Get packets by rollapp-id", - Long: `Get packets by rollapp-id. Can filter by status (pending/finalized/reverted) and by type (recv/ack/timeout) + Long: `Get packets by rollapp-id. Can filter by status (pending/finalized) and by type (recv/ack/timeout) Example: packets rollapp1 packets rollapp1 PENDING @@ -124,7 +124,7 @@ func CmdGetPacketsByStatus() *cobra.Command { cmd := &cobra.Command{ Use: "packets-by-status status [type]", Short: "Get packets by status", - Long: `Get packets by status (pending/finalized/reverted). Can filter by type (recv/ack/timeout) + Long: `Get packets by status (pending/finalized). Can filter by type (recv/ack/timeout) Example: packets-by-status pending packets-by-status finalized recv`, diff --git a/x/delayedack/keeper/finalize.go b/x/delayedack/keeper/finalize.go index 3026f28d3..0323ff6f9 100644 --- a/x/delayedack/keeper/finalize.go +++ b/x/delayedack/keeper/finalize.go @@ -11,7 +11,6 @@ import ( "github.com/osmosis-labs/osmosis/v15/osmoutils" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" - "github.com/dymensionxyz/dymension/v3/x/delayedack/types" ) // FinalizeRollappPacket finalizes a singe packet by its rollapp packet key. @@ -25,7 +24,7 @@ func (k Keeper) FinalizeRollappPacket(ctx sdk.Context, ibc porttypes.IBCModule, // Verify the height is finalized err = k.VerifyHeightFinalized(ctx, packet.RollappId, packet.ProofHeight) if err != nil { - return packet, fmt.Errorf("verify height is finalized: rollapp '%s': %w", packet.RollappId, err) + return packet, fmt.Errorf("verify height: rollapp '%s': %w", packet.RollappId, err) } // Finalize the packet @@ -137,41 +136,14 @@ func (k Keeper) onTimeoutPacket(rollappPacket commontypes.RollappPacket, ibc por } func (k Keeper) VerifyHeightFinalized(ctx sdk.Context, rollappID string, height uint64) error { - // Get the latest state info of the rollapp - latestIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, rollappID) - if !found { - return gerrc.ErrNotFound.Wrapf("latest finalized state index is not found") - } - stateInfo, found := k.rollappKeeper.GetStateInfo(ctx, rollappID, latestIndex.Index) - if !found { - return gerrc.ErrNotFound.Wrapf("state info is not found") + latestFinalizedHeight, err := k.getRollappLatestFinalizedHeight(ctx, rollappID) + if err != nil { + return err } + // Check the latest finalized height of the rollapp is higher than the height specified - if height > stateInfo.GetLatestHeight() { - return gerrc.ErrInvalidArgument.Wrapf("packet height is not finalized yet: height '%d', latest height '%d'", height, stateInfo.GetLatestHeight()) + if height > latestFinalizedHeight { + return gerrc.ErrInvalidArgument.Wrapf("packet height is not finalized yet: height '%d', latest finalized height '%d'", height, latestFinalizedHeight) } return nil } - -func (k Keeper) GetRollappLatestFinalizedHeight(ctx sdk.Context, rollappID string) (uint64, error) { - latestIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, rollappID) - if !found { - return 0, gerrc.ErrNotFound.Wrapf("latest finalized state index is not found") - } - stateInfo, found := k.rollappKeeper.GetStateInfo(ctx, rollappID, latestIndex.Index) - if !found { - return 0, gerrc.ErrNotFound.Wrapf("state info is not found") - } - return stateInfo.GetLatestHeight(), nil -} - -func (k Keeper) GetPendingPacketsUntilLatestHeight(ctx sdk.Context, rollappID string) ([]commontypes.RollappPacket, uint64, error) { - // Get rollapp's latest finalized height - latestFinalizedHeight, err := k.GetRollappLatestFinalizedHeight(ctx, rollappID) - if err != nil { - return nil, 0, fmt.Errorf("get latest finalized height: rollapp '%s': %w", rollappID, err) - } - - // Get all pending rollapp packets until the latest finalized height - return k.ListRollappPackets(ctx, types.PendingByRollappIDByMaxHeight(rollappID, latestFinalizedHeight)), latestFinalizedHeight, nil -} diff --git a/x/delayedack/keeper/finalize_test.go b/x/delayedack/keeper/finalize_test.go index 9fa890597..6dce23e84 100644 --- a/x/delayedack/keeper/finalize_test.go +++ b/x/delayedack/keeper/finalize_test.go @@ -51,7 +51,7 @@ func (s *DelayedAckTestSuite) TestFinalizePacket() { }, rollappHeight: 10, expectErr: true, - errContains: "packet height is not finalized yet: height '15', latest height '10'", + errContains: "verify height", }, } diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 74b26938c..790fcb54e 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -5,18 +5,16 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" ) -func (k Keeper) HandleFraud(ctx sdk.Context, rollappID string, ibc porttypes.IBCModule) error { - // Get all the pending packets - rollappPendingPackets := k.ListRollappPackets(ctx, types.ByRollappIDByStatus(rollappID, commontypes.Status_PENDING)) - if len(rollappPendingPackets) == 0 { - return nil - } +func (k Keeper) HandleHardFork(ctx sdk.Context, rollappID string, height uint64, ibc porttypes.IBCModule) error { logger := ctx.Logger().With("module", "DelayedAckMiddleware") - logger.Info("reverting IBC rollapp packets", "rollappID", rollappID) + + // Get all the pending packets from fork height inclusive + rollappPendingPackets := k.ListRollappPackets(ctx, types.PendingByRollappIDFromHeight(rollappID, height)) // Iterate over all the pending packets and revert them for _, rollappPacket := range rollappPendingPackets { @@ -28,22 +26,31 @@ func (k Keeper) HandleFraud(ctx sdk.Context, rollappID string, ibc porttypes.IBC "sequence", rollappPacket.Packet.Sequence, } + // refund all pending outgoing packets if rollappPacket.Type == commontypes.RollappPacket_ON_ACK || rollappPacket.Type == commontypes.RollappPacket_ON_TIMEOUT { - // refund all pending outgoing packets // we don't have access directly to `refundPacketToken` function, so we'll use the `OnTimeoutPacket` function err := ibc.OnTimeoutPacket(ctx, *rollappPacket.Packet, rollappPacket.Relayer) if err != nil { logger.Error("failed to refund reverted packet", append(logContext, "error", err.Error())...) } - } - // Update status to reverted - _, err := k.UpdateRollappPacketWithStatus(ctx, rollappPacket, commontypes.Status_REVERTED) - if err != nil { - logger.Error("error reverting IBC rollapp packet", append(logContext, "error", err.Error())...) - return err + } else { + // for incoming packets, we need to reset the packet receipt + ibcPacket := rollappPacket.Packet + k.deletePacketReceipt(ctx, ibcPacket.GetDestPort(), ibcPacket.GetDestChannel(), ibcPacket.GetSequence()) } + // delete the packet + k.DeleteRollappPacket(ctx, &rollappPacket) logger.Debug("reverted IBC rollapp packet", logContext...) } + + logger.Info("reverting IBC rollapp packets", "rollappID", rollappID, "numPackets", len(rollappPendingPackets)) + return nil } + +// DeleteRollappPacket deletes a packet receipt from the store +func (k Keeper) deletePacketReceipt(ctx sdk.Context, portID, channelID string, sequence uint64) { + store := ctx.KVStore(k.channelKeeperStoreKey) + store.Delete(host.PacketReceiptKey(portID, channelID, sequence)) +} diff --git a/x/delayedack/keeper/fraud_test.go b/x/delayedack/keeper/fraud_test.go index ae3555a28..7d3f5ec99 100644 --- a/x/delayedack/keeper/fraud_test.go +++ b/x/delayedack/keeper/fraud_test.go @@ -18,66 +18,45 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { ) rollappId := "testRollappId" - pkts := generatePackets(rollappId, 5) + pkts := generatePackets(rollappId, 10) rollappId2 := "testRollappId2" - pkts2 := generatePackets(rollappId2, 5) + pkts2 := generatePackets(rollappId2, 10) prefixPending1 := types.ByRollappIDByStatus(rollappId, commontypes.Status_PENDING) prefixPending2 := types.ByRollappIDByStatus(rollappId2, commontypes.Status_PENDING) - prefixReverted := types.ByRollappIDByStatus(rollappId, commontypes.Status_REVERTED) - prefixFinalized := types.ByRollappIDByStatus(rollappId, commontypes.Status_FINALIZED) + prefixFinalized1 := types.ByRollappIDByStatus(rollappId, commontypes.Status_FINALIZED) prefixFinalized2 := types.ByRollappIDByStatus(rollappId, commontypes.Status_FINALIZED) for _, pkt := range append(pkts, pkts2...) { keeper.SetRollappPacket(ctx, pkt) } - suite.Require().Equal(5, len(keeper.ListRollappPackets(ctx, prefixPending1))) - suite.Require().Equal(5, len(keeper.ListRollappPackets(ctx, prefixPending2))) + suite.Require().Equal(10, len(keeper.ListRollappPackets(ctx, prefixPending1))) + suite.Require().Equal(10, len(keeper.ListRollappPackets(ctx, prefixPending2))) - // finalize some packets + // finalize one packet _, err := keeper.UpdateRollappPacketWithStatus(ctx, pkts[0], commontypes.Status_FINALIZED) suite.Require().Nil(err) _, err = keeper.UpdateRollappPacketWithStatus(ctx, pkts2[0], commontypes.Status_FINALIZED) suite.Require().Nil(err) - err = keeper.HandleFraud(ctx, rollappId, transferStack) + // call fraud on the 4 packet + err = keeper.HandleHardFork(ctx, rollappId, 4, transferStack) suite.Require().Nil(err) - suite.Require().Equal(0, len(keeper.ListRollappPackets(ctx, prefixPending1))) - suite.Require().Equal(4, len(keeper.ListRollappPackets(ctx, prefixPending2))) - suite.Require().Equal(4, len(keeper.ListRollappPackets(ctx, prefixReverted))) - suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized))) - suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized2))) -} - -func (suite *DelayedAckTestSuite) TestDeletionOfRevertedPackets() { - keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx - transferStack := damodule.NewIBCMiddleware( - damodule.WithIBCModule(ibctransfer.NewIBCModule(suite.App.TransferKeeper)), - damodule.WithKeeper(keeper), - damodule.WithRollappKeeper(suite.App.RollappKeeper), - ) - - rollappId := "testRollappId" - pkts := generatePackets(rollappId, 5) - rollappId2 := "testRollappId2" - pkts2 := generatePackets(rollappId2, 5) - - for _, pkt := range append(pkts, pkts2...) { - keeper.SetRollappPacket(ctx, pkt) - } - - err := keeper.HandleFraud(ctx, rollappId, transferStack) - suite.Require().Nil(err) + // expected result: + // rollappId: + // - packet 1 are finalized + // - packet 2-3 are still pending + // - packets 4-10 are deleted + // rollappId2: + // - packet 1 are finalized + // - packets 2-10 are still pending - suite.Require().Equal(10, len(keeper.GetAllRollappPackets(ctx))) + suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized1))) + suite.Require().Equal(2, len(keeper.ListRollappPackets(ctx, prefixPending1))) - keeper.SetParams(ctx, types.Params{EpochIdentifier: "minute", BridgingFee: keeper.BridgingFee(ctx)}) - epochHooks := keeper.GetEpochHooks() - err = epochHooks.AfterEpochEnd(ctx, "minute", 1) - suite.Require().NoError(err) - - suite.Require().Equal(5, len(keeper.GetAllRollappPackets(ctx))) + suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized2))) + suite.Require().Equal(9, len(keeper.ListRollappPackets(ctx, prefixPending2))) } // TODO: test refunds of pending packets @@ -86,7 +65,7 @@ func (suite *DelayedAckTestSuite) TestDeletionOfRevertedPackets() { func generatePackets(rollappId string, num uint64) []commontypes.RollappPacket { var packets []commontypes.RollappPacket - for i := uint64(0); i < num; i++ { + for i := uint64(1); i <= num; i++ { packets = append(packets, commontypes.RollappPacket{ RollappId: rollappId, Packet: &channeltypes.Packet{ diff --git a/x/delayedack/keeper/grpc_query.go b/x/delayedack/keeper/grpc_query.go index 70d558627..151b7fb18 100644 --- a/x/delayedack/keeper/grpc_query.go +++ b/x/delayedack/keeper/grpc_query.go @@ -63,7 +63,7 @@ func (q Querier) GetPendingPacketsByReceiver(goCtx context.Context, req *types.Q ctx := sdk.UnwrapSDKContext(goCtx) // Get all pending rollapp packets until the latest finalized height - rollappPendingPackets, _, err := q.GetPendingPacketsUntilLatestHeight(ctx, req.RollappId) + rollappPendingPackets, _, err := q.GetPendingPacketsUntilFinalizedHeight(ctx, req.RollappId) if err != nil { return nil, fmt.Errorf("get pending rollapp packets until the latest finalized height: rollapp '%s': %w", req.RollappId, err) } diff --git a/x/delayedack/keeper/hooks.go b/x/delayedack/keeper/hooks.go index 401b43d97..5d777b0b3 100644 --- a/x/delayedack/keeper/hooks.go +++ b/x/delayedack/keeper/hooks.go @@ -72,7 +72,7 @@ func (e epochHooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epoch return nil } - listFilter := types.ByStatus(commontypes.Status_FINALIZED, commontypes.Status_REVERTED).Take(int(deletePacketsBatchSize)) + listFilter := types.ByStatus(commontypes.Status_FINALIZED).Take(int(deletePacketsBatchSize)) count := 0 // Get batch of rollapp packets with status != PENDING and delete them @@ -83,7 +83,7 @@ func (e epochHooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epoch for _, packet := range toDeletePackets { err := osmoutils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error { - return e.deleteRollappPacket(ctx, &packet) + return e.DeleteRollappPacket(ctx, &packet) }) if err != nil { e.Logger(ctx).Error("Failed to delete rollapp packet", diff --git a/x/delayedack/keeper/invariants.go b/x/delayedack/keeper/invariants.go index 382744407..66e615249 100644 --- a/x/delayedack/keeper/invariants.go +++ b/x/delayedack/keeper/invariants.go @@ -12,73 +12,48 @@ import ( const ( routeFinalizedPacket = "rollapp-finalized-packet" - routeRevertedPacket = "rollapp-reverted-packet" ) // RegisterInvariants registers the delayedack module invariants func (k Keeper) RegisterInvariants(ir sdk.InvariantRegistry) { - ir.RegisterRoute(types.ModuleName, routeFinalizedPacket, k.PacketsFinalizationCorrespondsToFinalizationHeight) - // ir.RegisterRoute(types.ModuleName, routeRevertedPacket, k.PacketsFromRevertedHeightsAreReverted) + // INVARIANTS DISABLED SINCE LAZY FINALIZATION FEATURE } // PacketsFinalizationCorrespondsToFinalizationHeight checks that all rollapp packets stored are set to // finalized status for all heights up to the latest height. -func (k Keeper) PacketsFinalizationCorrespondsToFinalizationHeight(ctx sdk.Context) (string, bool) { - return k.packetsCorrespondsToStatusHeight(checkFinalizedPackets)(ctx) -} - -// PacketsFromRevertedHeightsAreReverted checks that all rollapp packets stored are set to -// reverted status for all heights up to the latest height -func (k Keeper) PacketsFromRevertedHeightsAreReverted(ctx sdk.Context) (string, bool) { - return k.packetsCorrespondsToStatusHeight(checkRevertedPackets)(ctx) -} +func PacketsFinalizationCorrespondsToFinalizationHeight(k Keeper) sdk.Invariant { + return func(ctx sdk.Context) (string, bool) { + var ( + broken bool + msg string + ) -type checkPacketsFn func(packets []commontypes.RollappPacket, latestFinalizedHeight uint64) string - -// packetsCorrespondsToStatusHeight checks that all rollapp packets stored are set to adequate status for all heights up to the latest height -func (k Keeper) packetsCorrespondsToStatusHeight(checkPackets checkPacketsFn) sdk.Invariant { - return func(ctx sdk.Context) (msg string, stop bool) { for _, rollapp := range k.rollappKeeper.GetAllRollapps(ctx) { - msg = k.checkRollapp(ctx, rollapp, checkPackets) - if stop = msg != ""; stop { - break + msg = k.checkRollapp(ctx, rollapp) + if msg != "" { + msg += fmt.Sprintf("rollapp: %s, msg: %s\n", rollapp.RollappId, msg) + broken = true } } - return + return sdk.FormatInvariant(types.ModuleName, routeFinalizedPacket, msg), broken } } -func (k Keeper) checkRollapp(ctx sdk.Context, rollapp rtypes.Rollapp, checkPackets checkPacketsFn) (msg string) { +func (k Keeper) checkRollapp(ctx sdk.Context, rollapp rtypes.Rollapp) (msg string) { // will stay 0 if no state is found // but will still check packets var latestFinalizedHeight uint64 - defer func() { - if msg == "" { - packets := k.ListRollappPackets(ctx, types.ByRollappID(rollapp.RollappId)) - msg = checkPackets(packets, latestFinalizedHeight) - } - }() - latestFinalizedStateIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, rollapp.RollappId) if !found { return } - latestFinalizedStateInfo, found := k.rollappKeeper.GetStateInfo(ctx, rollapp.RollappId, latestFinalizedStateIndex.Index) - if !found { - msg = fmt.Sprintf("latest finalized state info not found for rollapp: %s", rollapp.RollappId) - return - } - + latestFinalizedStateInfo := k.rollappKeeper.MustGetStateInfo(ctx, rollapp.RollappId, latestFinalizedStateIndex.Index) latestFinalizedHeight = latestFinalizedStateInfo.GetLatestHeight() - return -} - -// checkFinalizedPackets checks that all rollapp packets stored are set to finalized status for all heights up to the latest height -func checkFinalizedPackets(packets []commontypes.RollappPacket, latestFinalizedHeight uint64) (_ string) { + packets := k.ListRollappPackets(ctx, types.ByRollappID(rollapp.RollappId)) for _, packet := range packets { if packet.ProofHeight > latestFinalizedHeight && packet.Status == commontypes.Status_FINALIZED { return fmt.Sprintf("rollapp packet for the height should not be in finalized status. height=%d, rollapp=%s, status=%s\n", @@ -87,15 +62,3 @@ func checkFinalizedPackets(packets []commontypes.RollappPacket, latestFinalizedH } return } - -// checkRevertedPackets checks that all rollapp packets stored are set to reverted status for all heights up to the latest height -func checkRevertedPackets(packets []commontypes.RollappPacket, latestFinalizedHeight uint64) (_ string) { - for _, packet := range packets { - if packet.ProofHeight > latestFinalizedHeight && packet.Status != commontypes.Status_REVERTED { - return fmt.Sprintf("packet should be reverted: rollapp: %s: height: %d: status: %s", - packet.RollappId, packet.ProofHeight, packet.Status) - } - } - - return -} diff --git a/x/delayedack/keeper/invariants_test.go b/x/delayedack/keeper/invariants_test.go index dae550a6e..f128e0c94 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -8,12 +8,12 @@ import ( commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" damodule "github.com/dymensionxyz/dymension/v3/x/delayedack" - "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + dakeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) func (suite *DelayedAckTestSuite) TestInvariants() { - suite.SetupTest() + suite.T().Skip("skipping TestInvariants as it's not supported with lazy finalization feature") transferStack := damodule.NewIBCMiddleware( damodule.WithIBCModule(ibctransfer.NewIBCModule(suite.App.TransferKeeper)), @@ -82,35 +82,35 @@ func (suite *DelayedAckTestSuite) TestInvariants() { // test fraud for rollapp := range seqPerRollapp { - err := suite.App.DelayedAckKeeper.HandleFraud(suite.Ctx, rollapp, transferStack) + err := suite.App.DelayedAckKeeper.HandleHardFork(suite.Ctx, rollapp, uint64(suite.Ctx.BlockHeight()), transferStack) suite.Require().NoError(err) break } // check invariant - msg, fails := suite.App.DelayedAckKeeper.PacketsFinalizationCorrespondsToFinalizationHeight(suite.Ctx) - suite.Require().False(fails, msg) - msg, fails = suite.App.DelayedAckKeeper.PacketsFromRevertedHeightsAreReverted(suite.Ctx) + msg, fails := dakeeper.PacketsFinalizationCorrespondsToFinalizationHeight(suite.App.DelayedAckKeeper)(suite.Ctx) suite.Require().False(fails, msg) } +// TestRollappPacketsCasesInvariant tests the invariant that checks if the packets are finalized only for finalized heights +// by default, we have: +// - state1 with blocks 1-10 which is finalized +// - state2 with blocks 11-20 which is pending func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { - rollapp := "rollapp_1234-1" + suite.T().Skip("skipping TestRollappPacketsCasesInvariant as it's not supported with lazy finalization feature") + rollapp := "rollapp_1234-1" cases := []struct { name string - frozenRollapp bool - allFinalized bool nothingFinalized bool packet commontypes.RollappPacket packet2 commontypes.RollappPacket expectedIsBroken bool }{ + // successful checks { "successful invariant check - packets are finalized only for finalized heights", false, - false, - false, commontypes.RollappPacket{ RollappId: rollapp, Status: commontypes.Status_FINALIZED, @@ -126,19 +126,17 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { false, }, { - "successful revert check - packets are reverted for non-finalized states", - true, - false, + "successful invariant check - packets are not yet finalized for finalized heights", false, commontypes.RollappPacket{ RollappId: rollapp, - Status: commontypes.Status_FINALIZED, + Status: commontypes.Status_PENDING, ProofHeight: 5, Packet: suite.getNewTestPacket(1), }, commontypes.RollappPacket{ RollappId: rollapp, - Status: commontypes.Status_REVERTED, + Status: commontypes.Status_PENDING, ProofHeight: 15, Packet: suite.getNewTestPacket(2), }, @@ -146,8 +144,6 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { }, { "successful non-finalized state invariant check - packets without finalization state are not finalized", - false, - false, true, commontypes.RollappPacket{ RollappId: rollapp, @@ -163,29 +159,9 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { }, false, }, - { - "wrong invariant revert check - packets for frozen rollapps in non-finalized heights are not reverted", - true, - false, - false, - commontypes.RollappPacket{ - RollappId: rollapp, - Status: commontypes.Status_FINALIZED, - ProofHeight: 5, - Packet: suite.getNewTestPacket(1), - }, - commontypes.RollappPacket{ - RollappId: rollapp, - Status: commontypes.Status_PENDING, - ProofHeight: 15, - Packet: suite.getNewTestPacket(2), - }, - true, - }, + // failed checks { "wrong finalized packet check - packets are finalized in non-finalized heights", - false, - false, true, commontypes.RollappPacket{ RollappId: rollapp, @@ -204,8 +180,6 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { { "wrong finalized packet check - packets for non-finalized heights are finalized", false, - false, - false, commontypes.RollappPacket{ RollappId: rollapp, Status: commontypes.Status_FINALIZED, @@ -240,6 +214,11 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { Status: commontypes.Status_FINALIZED, Sequencer: proposer, } + if tc.nothingFinalized { + stateInfo.Status = commontypes.Status_PENDING + } + suite.App.RollappKeeper.SetStateInfo(ctx, stateInfo) + stateInfo2 := rollapptypes.StateInfo{ StateInfoIndex: rollapptypes.StateInfoIndex{ RollappId: rollapp, @@ -250,40 +229,10 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { Status: commontypes.Status_PENDING, Sequencer: proposer, } - - // if nothingFinalized true, all the state infos submitted should be pending - if tc.nothingFinalized { - stateInfo.Status = commontypes.Status_PENDING - } else { - suite.App.RollappKeeper.SetLatestFinalizedStateIndex(ctx, types.StateInfoIndex{ - RollappId: rollapp, - Index: stateInfo.GetIndex().Index, - }) - } - - suite.App.RollappKeeper.SetStateInfo(ctx, stateInfo) - - // if allFinalized true, all the state infos submitted should be finalized - if tc.allFinalized { - stateInfo2.Status = commontypes.Status_FINALIZED - } - suite.App.RollappKeeper.SetStateInfo(ctx, stateInfo2) - if stateInfo2.Status == commontypes.Status_FINALIZED { - suite.App.RollappKeeper.SetLatestFinalizedStateIndex(ctx, types.StateInfoIndex{ - RollappId: rollapp, - Index: stateInfo2.GetIndex().Index, - }) - } - suite.App.RollappKeeper.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ - RollappId: rollapp, - Index: stateInfo2.GetIndex().Index, - }) - - // if frozenRollapp true, we should freeze the rollapp and revert pending states - if tc.frozenRollapp { - err := suite.App.RollappKeeper.HardFork(ctx, rollapp, 11) - suite.Require().NoError(err) + suite.App.RollappKeeper.SetLatestStateInfoIndex(ctx, stateInfo2.StateInfoIndex) + if !tc.nothingFinalized { + suite.App.RollappKeeper.SetLatestFinalizedStateIndex(ctx, stateInfo.StateInfoIndex) } // add rollapp packets @@ -291,10 +240,7 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { suite.App.DelayedAckKeeper.SetRollappPacket(ctx, tc.packet2) // check invariant - _, failsFinalize := suite.App.DelayedAckKeeper.PacketsFinalizationCorrespondsToFinalizationHeight(suite.Ctx) - _, failsRevert := suite.App.DelayedAckKeeper.PacketsFromRevertedHeightsAreReverted(suite.Ctx) - - isBroken := failsFinalize || failsRevert + _, isBroken := dakeeper.PacketsFinalizationCorrespondsToFinalizationHeight(suite.App.DelayedAckKeeper)(suite.Ctx) suite.Require().Equal(tc.expectedIsBroken, isBroken) }) } diff --git a/x/delayedack/keeper/keeper.go b/x/delayedack/keeper/keeper.go index 2d656b630..5288adb12 100644 --- a/x/delayedack/keeper/keeper.go +++ b/x/delayedack/keeper/keeper.go @@ -12,14 +12,14 @@ import ( porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) type Keeper struct { - cdc codec.BinaryCodec - storeKey storetypes.StoreKey - hooks types.MultiDelayedAckHooks - paramstore paramtypes.Subspace + cdc codec.BinaryCodec + storeKey storetypes.StoreKey + channelKeeperStoreKey storetypes.StoreKey // we need direct access to the IBC channel store + hooks types.MultiDelayedAckHooks + paramstore paramtypes.Subspace rollappKeeper types.RollappKeeper porttypes.ICS4Wrapper @@ -30,6 +30,7 @@ type Keeper struct { func NewKeeper( cdc codec.BinaryCodec, storeKey storetypes.StoreKey, + channelKeeperStoreKey storetypes.StoreKey, ps paramtypes.Subspace, rollappKeeper types.RollappKeeper, ics4Wrapper porttypes.ICS4Wrapper, @@ -41,13 +42,14 @@ func NewKeeper( ps = ps.WithKeyTable(types.ParamKeyTable()) } return &Keeper{ - cdc: cdc, - storeKey: storeKey, - paramstore: ps, - rollappKeeper: rollappKeeper, - ICS4Wrapper: ics4Wrapper, - channelKeeper: channelKeeper, - EIBCKeeper: eibcKeeper, + cdc: cdc, + storeKey: storeKey, + channelKeeperStoreKey: channelKeeperStoreKey, + paramstore: ps, + rollappKeeper: rollappKeeper, + ICS4Wrapper: ics4Wrapper, + channelKeeper: channelKeeper, + EIBCKeeper: eibcKeeper, } } @@ -55,17 +57,6 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } -func (k Keeper) getRollappFinalizedHeight(ctx sdk.Context, chainID string) (uint64, error) { - // GetLatestFinalizedStateIndex - latestFinalizedStateIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, chainID) - if !found { - return 0, rollapptypes.ErrNoFinalizedStateYetForRollapp - } - - stateInfo := k.rollappKeeper.MustGetStateInfo(ctx, chainID, latestFinalizedStateIndex.Index) - return stateInfo.StartHeight + stateInfo.NumBlocks - 1, nil -} - /* -------------------------------------------------------------------------- */ /* Hooks handling */ /* -------------------------------------------------------------------------- */ diff --git a/x/delayedack/keeper/rollapp_packet.go b/x/delayedack/keeper/rollapp_packet.go index 385cc16f1..4e56e7ace 100644 --- a/x/delayedack/keeper/rollapp_packet.go +++ b/x/delayedack/keeper/rollapp_packet.go @@ -1,11 +1,14 @@ package keeper import ( + "fmt" + sdk "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" ) // SetRollappPacket stores a rollapp packet in the KVStore. @@ -165,7 +168,7 @@ func (k Keeper) GetAllRollappPackets(ctx sdk.Context) (list []commontypes.Rollap return list } -func (k Keeper) deleteRollappPacket(ctx sdk.Context, rollappPacket *commontypes.RollappPacket) error { +func (k Keeper) DeleteRollappPacket(ctx sdk.Context, rollappPacket *commontypes.RollappPacket) error { store := ctx.KVStore(k.storeKey) rollappPacketKey := rollappPacket.RollappPacketKey() store.Delete(rollappPacketKey) @@ -178,3 +181,25 @@ func (k Keeper) deleteRollappPacket(ctx sdk.Context, rollappPacket *commontypes. return nil } + +// GetPendingPacketsUntilFinalizedHeight returns all pending rollapp packets until the latest finalized height. +func (k Keeper) GetPendingPacketsUntilFinalizedHeight(ctx sdk.Context, rollappID string) ([]commontypes.RollappPacket, uint64, error) { + // Get rollapp's latest finalized height + latestFinalizedHeight, err := k.getRollappLatestFinalizedHeight(ctx, rollappID) + if err != nil { + return nil, 0, fmt.Errorf("get latest finalized height: rollapp '%s': %w", rollappID, err) + } + + // Get all pending rollapp packets until the latest finalized height + return k.ListRollappPackets(ctx, types.PendingByRollappIDByMaxHeight(rollappID, latestFinalizedHeight)), latestFinalizedHeight, nil +} + +func (k Keeper) getRollappLatestFinalizedHeight(ctx sdk.Context, rollappID string) (uint64, error) { + latestIndex, found := k.rollappKeeper.GetLatestFinalizedStateIndex(ctx, rollappID) + if !found { + return 0, gerrc.ErrNotFound.Wrapf("latest finalized state index is not found") + } + + stateInfo := k.rollappKeeper.MustGetStateInfo(ctx, rollappID, latestIndex.Index) + return stateInfo.GetLatestHeight(), nil +} diff --git a/x/delayedack/keeper/rollapp_packet_test.go b/x/delayedack/keeper/rollapp_packet_test.go index e62354b8e..72a86ce0d 100644 --- a/x/delayedack/keeper/rollapp_packet_test.go +++ b/x/delayedack/keeper/rollapp_packet_test.go @@ -82,6 +82,10 @@ func (suite *DelayedAckTestSuite) TestRollappPacketEvents() { } } +// TestListRollappPackets tests the ListRollappPackets function +// we have 3 rollapps +// 2 pending packets, 3 finalized packets +// 2 onRecv packets, 2 onAck packets, 1 onTimeout packets func (suite *DelayedAckTestSuite) TestListRollappPackets() { keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx rollappIDs := []string{"testRollappID1", "testRollappID2", "testRollappID3"} @@ -89,7 +93,6 @@ func (suite *DelayedAckTestSuite) TestListRollappPackets() { sm := map[int]commontypes.Status{ 0: commontypes.Status_PENDING, 1: commontypes.Status_FINALIZED, - 2: commontypes.Status_REVERTED, } var packetsToSet []commontypes.RollappPacket @@ -106,7 +109,7 @@ func (suite *DelayedAckTestSuite) TestListRollappPackets() { Data: []byte("testData"), Sequence: uint64(i), }, - Status: sm[i%3], + Status: sm[i%2], Type: commontypes.RollappPacket_Type(i % 3), ProofHeight: uint64(6 - i), } @@ -123,50 +126,52 @@ func (suite *DelayedAckTestSuite) TestListRollappPackets() { packets := keeper.ListRollappPackets(ctx, types.ByRollappID(rollappIDs[0])) suite.Require().Equal(5, len(packets)) - expectPendingLength := 3 + expectPendingLength := 6 pendingPackets := keeper.ListRollappPackets(ctx, types.ByStatus(commontypes.Status_PENDING)) suite.Require().Equal(expectPendingLength, len(pendingPackets)) - expectFinalizedLength := 6 + expectFinalizedLength := 9 finalizedPackets := keeper.ListRollappPackets(ctx, types.ByStatus(commontypes.Status_FINALIZED)) suite.Require().Equal(expectFinalizedLength, len(finalizedPackets)) - expectRevertedLength := 6 - revertedPackets := keeper.ListRollappPackets(ctx, types.ByStatus(commontypes.Status_REVERTED)) - suite.Require().Equal(expectRevertedLength, len(revertedPackets)) + expectFinalizedLengthLimit := 4 + finalizedPacketsLimit := keeper.ListRollappPackets(ctx, types.ByStatus(commontypes.Status_FINALIZED).Take(4)) + suite.Require().Equal(expectFinalizedLengthLimit, len(finalizedPacketsLimit)) - expectRevertedLengthLimit := 4 - revertedPacketsLimit := keeper.ListRollappPackets(ctx, types.ByStatus(commontypes.Status_REVERTED).Take(4)) - suite.Require().Equal(expectRevertedLengthLimit, len(revertedPacketsLimit)) - - suite.Require().Equal(totalLength, len(pendingPackets)+len(finalizedPackets)+len(revertedPackets)) + suite.Require().Equal(totalLength, len(pendingPackets)+len(finalizedPackets)) rollappPacket1Finalized := keeper.ListRollappPackets(ctx, types.ByRollappIDByStatus(rollappIDs[0], commontypes.Status_FINALIZED)) rollappPacket2Pending := keeper.ListRollappPackets(ctx, types.ByRollappIDByStatus(rollappIDs[1], commontypes.Status_PENDING)) - rollappPacket3Reverted := keeper.ListRollappPackets(ctx, types.ByRollappIDByStatus(rollappIDs[2], commontypes.Status_REVERTED)) - suite.Require().Equal(2, len(rollappPacket1Finalized)) - suite.Require().Equal(1, len(rollappPacket2Pending)) - suite.Require().Equal(2, len(rollappPacket3Reverted)) + suite.Require().Equal(3, len(rollappPacket1Finalized)) + suite.Require().Equal(2, len(rollappPacket2Pending)) rollappPacket1MaxHeight4 := keeper.ListRollappPackets(ctx, types.PendingByRollappIDByMaxHeight(rollappIDs[0], 4)) - suite.Require().Equal(1, len(rollappPacket1MaxHeight4)) + suite.Require().Equal(2, len(rollappPacket1MaxHeight4)) rollappPacket2MaxHeight3 := keeper.ListRollappPackets(ctx, types.PendingByRollappIDByMaxHeight(rollappIDs[1], 3)) suite.Require().Equal(1, len(rollappPacket2MaxHeight3)) - expectOnRecvLength := 3 + expectOnRecvLength := 0 // i % 2 == 0 AND i % 3 == 0 onRecvPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_RECV, commontypes.Status_PENDING)) suite.Equal(expectOnRecvLength, len(onRecvPackets)) - expectOnAckLength := 6 + expectOnAckLength := 3 // i % 2 == 1 AND i % 3 == 1 (per rollapp) onAckPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_ACK, commontypes.Status_FINALIZED)) suite.Equal(expectOnAckLength, len(onAckPackets)) - expectOnTimeoutLength := 6 - onTimeoutPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_TIMEOUT, commontypes.Status_REVERTED)) + expectOnTimeoutLength := 3 // i % 2 == 1 AND i % 3 == 2 (per rollapp) + onTimeoutPackets := keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_TIMEOUT, commontypes.Status_FINALIZED)) suite.Equal(expectOnTimeoutLength, len(onTimeoutPackets)) - suite.Require().Equal(totalLength, len(onRecvPackets)+len(onAckPackets)+len(onTimeoutPackets)) + var totalCount int + for _, status := range sm { + onRecvPackets = keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_RECV, status)) + onAckPackets = keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_ACK, status)) + onTimeoutPackets = keeper.ListRollappPackets(ctx, types.ByTypeByStatus(commontypes.RollappPacket_ON_TIMEOUT, status)) + totalCount += len(onRecvPackets) + len(onAckPackets) + len(onTimeoutPackets) + } + + suite.Require().Equal(totalLength, totalCount) } func (suite *DelayedAckTestSuite) TestUpdateRollappPacketWithStatus() { diff --git a/x/delayedack/keeper/transfer.go b/x/delayedack/keeper/transfer.go index 4e4db0b4d..fbb8cc6b8 100644 --- a/x/delayedack/keeper/transfer.go +++ b/x/delayedack/keeper/transfer.go @@ -6,7 +6,6 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" "github.com/dymensionxyz/gerr-cosmos/gerrc" ) @@ -46,8 +45,8 @@ func (k Keeper) GetValidTransferWithFinalizationInfo( return } - finalizedHeight, err := k.getRollappFinalizedHeight(ctx, data.Rollapp.RollappId) - if errorsmod.IsOf(err, rollapptypes.ErrNoFinalizedStateYetForRollapp) { + finalizedHeight, err := k.getRollappLatestFinalizedHeight(ctx, data.Rollapp.RollappId) + if errorsmod.IsOf(err, gerrc.ErrNotFound) { err = nil } else if err != nil { err = errorsmod.Wrap(err, "get rollapp finalized height") diff --git a/x/delayedack/rollapp_hooks.go b/x/delayedack/rollapp_hooks.go index 7a4a12a7a..ab9b01e5c 100644 --- a/x/delayedack/rollapp_hooks.go +++ b/x/delayedack/rollapp_hooks.go @@ -9,5 +9,5 @@ import ( var _ rollapptypes.RollappHooks = &IBCMiddleware{} func (w IBCMiddleware) OnHardFork(ctx sdk.Context, rollappID string, height uint64) error { - return w.HandleFraud(ctx, rollappID, w.IBCModule) + return w.HandleHardFork(ctx, rollappID, height, w.IBCModule) } diff --git a/x/delayedack/types/rollapp_packets_list_filter.go b/x/delayedack/types/rollapp_packets_list_filter.go index 034cff45f..b921b71e9 100644 --- a/x/delayedack/types/rollapp_packets_list_filter.go +++ b/x/delayedack/types/rollapp_packets_list_filter.go @@ -1,6 +1,8 @@ package types import ( + math "math" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" ) @@ -33,6 +35,18 @@ func PendingByRollappIDByMaxHeight( } } +func PendingByRollappIDFromHeight(rollappID string, fromHeight uint64) RollappPacketListFilter { + return RollappPacketListFilter{ + Prefixes: []Prefix{ + { + Start: commontypes.RollappPacketByStatusByRollappIDByProofHeightPrefix(rollappID, commontypes.Status_PENDING, fromHeight), + End: commontypes.RollappPacketByStatusByRollappIDByProofHeightPrefix(rollappID, commontypes.Status_PENDING, math.MaxUint64), + }, + }, + FilterFunc: bypassFilter, + } +} + func ByRollappIDByStatus(rollappID string, status ...commontypes.Status) RollappPacketListFilter { prefixes := make([]Prefix, len(status)) for i, s := range status { @@ -58,7 +72,6 @@ func ByRollappID(rollappID string) RollappPacketListFilter { return ByRollappIDByStatus(rollappID, commontypes.Status_PENDING, commontypes.Status_FINALIZED, - commontypes.Status_REVERTED, ) } diff --git a/x/delayedack/types/rollapp_packets_list_filter_test.go b/x/delayedack/types/rollapp_packets_list_filter_test.go index 4e7b9ce5b..2bbe33b21 100644 --- a/x/delayedack/types/rollapp_packets_list_filter_test.go +++ b/x/delayedack/types/rollapp_packets_list_filter_test.go @@ -29,8 +29,6 @@ func TestByRollappID(t *testing.T) { Start: []uint8{0x00, 0x01, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f}, }, { Start: []uint8{0x00, 0x02, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f}, - }, { - Start: []uint8{0x00, 0x03, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f}, }, }, }, { @@ -43,8 +41,6 @@ func TestByRollappID(t *testing.T) { Start: []uint8{0x00, 0x01, 0x2f, 0x2f}, }, { Start: []uint8{0x00, 0x02, 0x2f, 0x2f}, - }, { - Start: []uint8{0x00, 0x03, 0x2f, 0x2f}, }, }, }, @@ -89,17 +85,6 @@ func TestByRollappIDByStatus(t *testing.T) { Start: []uint8{0x00, 0x02, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f}, }, }, - }, { - name: "Test with rollappID 1 and status REVERTED", - args: args{ - rollappID: "testRollappID1", - status: []commontypes.Status{commontypes.Status_REVERTED}, - }, - want: []types.Prefix{ - { - Start: []uint8{0x00, 0x03, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f}, - }, - }, }, { name: "Test with rollappID 1 and status PENDING, FINALIZED", args: args{ @@ -163,16 +148,6 @@ func TestByStatus(t *testing.T) { Start: []uint8{0x00, 0x02, 0x2f}, }, }, - }, { - name: "Test with status REVERTED", - args: args{ - status: []commontypes.Status{commontypes.Status_REVERTED}, - }, - want: []types.Prefix{ - { - Start: []uint8{0x00, 0x03, 0x2f}, - }, - }, }, } for _, tt := range tests { @@ -282,6 +257,64 @@ func TestByType(t *testing.T) { } } +func TestPendingByRollappIDFromHeight(t *testing.T) { + type args struct { + rollappID string + fromHeight uint64 + } + tests := []struct { + name string + args args + want []types.Prefix + }{ + { + name: "Test with rollappID 1 and fromHeight 100", + args: args{ + rollappID: "testRollappID1", + fromHeight: 100, + }, + want: []types.Prefix{ + { + Start: []uint8{0x00, 0x01, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64}, + End: []uint8{0x00, 0x01, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x31, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, + }, + }, + { + name: "Test with empty rollappID and fromHeight 50", + args: args{ + rollappID: "", + fromHeight: 50, + }, + want: []types.Prefix{ + { + Start: []uint8{0x0, 0x1, 0x2f, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x32}, + End: []uint8{0x0, 0x1, 0x2f, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, + }, + }, + { + name: "Test with rollappID 2 and fromHeight 0", + args: args{ + rollappID: "testRollappID2", + fromHeight: 0, + }, + want: []types.Prefix{ + { + Start: []uint8{0x0, 0x1, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x32, 0x2f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, + End: []uint8{0x0, 0x1, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x52, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x70, 0x49, 0x44, 0x32, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + filter := types.PendingByRollappIDFromHeight(tt.args.rollappID, tt.args.fromHeight) + require.Equal(t, tt.want, filter.Prefixes) + }) + } +} + var testRollappPackets = []commontypes.RollappPacket{ { RollappId: "rollapp-id-1", diff --git a/x/eibc/client/cli/query_command_orders.go b/x/eibc/client/cli/query_command_orders.go index 18622c574..8e320a222 100644 --- a/x/eibc/client/cli/query_command_orders.go +++ b/x/eibc/client/cli/query_command_orders.go @@ -18,7 +18,7 @@ func CmdListDemandOrdersByStatus() *cobra.Command { cmd := &cobra.Command{ Use: "list-demand-orders status [rollapp] [recipient] [type] [denom] [fulfilled] [fulfiller] [limit]", Short: "List all demand orders with a specific status", - Long: `Query demand orders filtered by status. Examples of status include "pending", "finalized", and "reverted". + Long: `Query demand orders filtered by status. Status can "pending" or "finalized". Optional arguments include rollapp_id, type (recv, timeout, ack), and limit.`, Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/x/eibc/genesis_test.go b/x/eibc/genesis_test.go index 5b2ac0545..0f1b1ac7f 100644 --- a/x/eibc/genesis_test.go +++ b/x/eibc/genesis_test.go @@ -33,7 +33,7 @@ func TestInitGenesis(t *testing.T) { Fee: sdk.Coins{sdk.Coin{Denom: "adym", Amount: math.NewInt(150)}}, Recipient: "dym15saxgqw6kvhv6k5sg6r45kmdf4sf88kfw2adcw", FulfillerAddress: "dym19pas0pqwje540u5ptwnffjxeamdxc9tajmdrfa", - TrackingPacketStatus: commontypes.Status_REVERTED, + TrackingPacketStatus: commontypes.Status_FINALIZED, }, }, } diff --git a/x/eibc/keeper/grpc_query.go b/x/eibc/keeper/grpc_query.go index f48758bd1..cd5ffe691 100644 --- a/x/eibc/keeper/grpc_query.go +++ b/x/eibc/keeper/grpc_query.go @@ -41,7 +41,7 @@ func (q Querier) DemandOrderById(goCtx context.Context, req *types.QueryGetDeman // Get the demand order by its ID and search for it in all statuses var demandOrder *types.DemandOrder var err error - statuses := []commontypes.Status{commontypes.Status_PENDING, commontypes.Status_FINALIZED, commontypes.Status_REVERTED} + statuses := []commontypes.Status{commontypes.Status_PENDING, commontypes.Status_FINALIZED} for _, status := range statuses { demandOrder, err = q.GetDemandOrder(ctx, status, req.Id) if err == nil && demandOrder != nil { diff --git a/x/eibc/keeper/grpc_query_test.go b/x/eibc/keeper/grpc_query_test.go index a54925e9b..4d340a9cd 100644 --- a/x/eibc/keeper/grpc_query_test.go +++ b/x/eibc/keeper/grpc_query_test.go @@ -51,7 +51,7 @@ func (suite *KeeperTestSuite) TestQueryDemandOrdersByStatus() { demandOrderAddresses := apptesting.AddTestAddrs(suite.App, suite.Ctx, demandOrdersNum, math.NewInt(1000)) // Define statuses to test - statuses := []commontypes.Status{commontypes.Status_PENDING, commontypes.Status_REVERTED, commontypes.Status_FINALIZED} + statuses := []commontypes.Status{commontypes.Status_PENDING, commontypes.Status_FINALIZED} // Create and set demand orders for each status for i, status := range statuses { diff --git a/x/eibc/keeper/hooks.go b/x/eibc/keeper/hooks.go index 67e67bc39..9b75215be 100644 --- a/x/eibc/keeper/hooks.go +++ b/x/eibc/keeper/hooks.go @@ -65,8 +65,7 @@ func (d delayedAckHooks) AfterPacketDeleted(ctx sdk.Context, rollappPacket *comm packetKey := rollappPacket.RollappPacketKey() demandOrderID := types.BuildDemandIDFromPacketKey(string(packetKey)) - // Check for demand order in both FINALIZED and REVERTED statuses - statuses := []commontypes.Status{commontypes.Status_FINALIZED, commontypes.Status_REVERTED} + statuses := []commontypes.Status{commontypes.Status_PENDING, commontypes.Status_FINALIZED} for _, status := range statuses { demandOrder, err := d.GetDemandOrder(ctx, status, demandOrderID) if err != nil { diff --git a/x/eibc/keeper/hooks_test.go b/x/eibc/keeper/hooks_test.go index 029676c16..54aded6f8 100644 --- a/x/eibc/keeper/hooks_test.go +++ b/x/eibc/keeper/hooks_test.go @@ -38,13 +38,13 @@ func (suite *KeeperTestSuite) TestAfterRollappPacketDeleted() { expectedError error }{ { - name: "Finalized packet", - packetStatus: commontypes.Status_FINALIZED, + name: "Pending packet", + packetStatus: commontypes.Status_PENDING, expectedError: types.ErrDemandOrderDoesNotExist, }, { - name: "Reverted packet", - packetStatus: commontypes.Status_REVERTED, + name: "Finalized packet", + packetStatus: commontypes.Status_FINALIZED, expectedError: types.ErrDemandOrderDoesNotExist, }, } @@ -64,13 +64,8 @@ func (suite *KeeperTestSuite) TestAfterRollappPacketDeleted() { _, err = suite.App.DelayedAckKeeper.UpdateRollappPacketWithStatus(suite.Ctx, *rollappPacket, tc.packetStatus) suite.Require().NoError(err) - // Trigger the delayed ack hook which should delete the rollapp packet and the demand order - epochIdentifier := "minute" - defParams := delayedacktypes.DefaultParams() - defParams.EpochIdentifier = epochIdentifier - suite.App.DelayedAckKeeper.SetParams(suite.Ctx, defParams) - hooks := suite.App.DelayedAckKeeper.GetEpochHooks() - err = hooks.AfterEpochEnd(suite.Ctx, epochIdentifier, 1) + // delete the rollapp packet + err = suite.App.DelayedAckKeeper.DeleteRollappPacket(suite.Ctx, rollappPacket) suite.Require().NoError(err) // Verify that the rollapp packet and demand order are deleted diff --git a/x/eibc/keeper/invariants.go b/x/eibc/keeper/invariants.go index 437c70a82..82e62edef 100644 --- a/x/eibc/keeper/invariants.go +++ b/x/eibc/keeper/invariants.go @@ -35,20 +35,15 @@ func DemandOrderCountInvariant(k Keeper) sdk.Invariant { msg += fmt.Sprintf("list pending demand orders failed: %v\n", err) broken = true } - revertedDemandOrders, err := k.ListDemandOrdersByStatus(ctx, commontypes.Status_REVERTED, 0) - if err != nil { - msg += fmt.Sprintf("list reverted demand orders failed: %v\n", err) - broken = true - } finalizedDemandOrders, err := k.ListDemandOrdersByStatus(ctx, commontypes.Status_FINALIZED, 0) if err != nil { msg += fmt.Sprintf("list finalized demand orders failed: %v\n", err) broken = true } // Validate the count of demand orders is equal to the sum of demand orders in all statuses - if len(allDemandOrders) != len(pendingDemandOrders)+len(revertedDemandOrders)+len(finalizedDemandOrders) { - msg += fmt.Sprintf("demand orders count mismatch: all(%d) != pending(%d) + reverted(%d) + finalized(%d)\n", - len(allDemandOrders), len(pendingDemandOrders), len(revertedDemandOrders), len(finalizedDemandOrders)) + if len(allDemandOrders) != len(pendingDemandOrders)+len(finalizedDemandOrders) { + msg += fmt.Sprintf("demand orders count mismatch: all(%d) != pending(%d) + finalized(%d)\n", + len(allDemandOrders), len(pendingDemandOrders), len(finalizedDemandOrders)) broken = true } return sdk.FormatInvariant(types.ModuleName, demandOrderCountInvariantName, msg), broken diff --git a/x/eibc/keeper/invariants_test.go b/x/eibc/keeper/invariants_test.go index f220c872a..a02df8c44 100644 --- a/x/eibc/keeper/invariants_test.go +++ b/x/eibc/keeper/invariants_test.go @@ -18,12 +18,10 @@ func (suite *KeeperTestSuite) TestInvariants() { // Create and set some demand orders with status pending for i := 0; i < demandOrdersNum; i++ { var status commontypes.Status - switch i % 3 { + switch i % 2 { case 0: status = commontypes.Status_PENDING case 1: - status = commontypes.Status_REVERTED - case 2: status = commontypes.Status_FINALIZED } rollappPacket := &commontypes.RollappPacket{ diff --git a/x/eibc/keeper/keeper.go b/x/eibc/keeper/keeper.go index eb0c74f2c..4e248697f 100644 --- a/x/eibc/keeper/keeper.go +++ b/x/eibc/keeper/keeper.go @@ -178,8 +178,6 @@ func (k Keeper) ListDemandOrdersByStatus(ctx sdk.Context, status commontypes.Sta statusPrefix = types.PendingDemandOrderKeyPrefix case commontypes.Status_FINALIZED: statusPrefix = types.FinalizedDemandOrderKeyPrefix - case commontypes.Status_REVERTED: - statusPrefix = types.RevertedDemandOrderKeyPrefix default: return nil, fmt.Errorf("invalid packet status: %s", status) } diff --git a/x/eibc/types/keys.go b/x/eibc/types/keys.go index 0fe1b4380..e44e789b7 100644 --- a/x/eibc/types/keys.go +++ b/x/eibc/types/keys.go @@ -34,8 +34,6 @@ var ( PendingDemandOrderKeyPrefix = []byte{0x00, 0x01} // FinalizedDemandOrderKeyPrefix is the prefix for finalized demand orders FinalizedDemandOrderKeyPrefix = []byte{0x00, 0x02} - // RevertedDemandOrderKeyPrefix is the prefix for reverted demand orders - RevertedDemandOrderKeyPrefix = []byte{0x00, 0x03} ) // GetDemandOrderKey constructs a key for a specific DemandOrder. @@ -47,8 +45,6 @@ func GetDemandOrderKey(packetStatus commontypes.Status, orderId string) ([]byte, prefix = PendingDemandOrderKeyPrefix case commontypes.Status_FINALIZED: prefix = FinalizedDemandOrderKeyPrefix - case commontypes.Status_REVERTED: - prefix = RevertedDemandOrderKeyPrefix default: return nil, fmt.Errorf("invalid packet status: %s", packetStatus) } From 617fa633476b7b83a65aad75123b484950a6cec3 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:53:34 +0200 Subject: [PATCH 13/68] feat(hard_fork): Lightclient rollback (#1363) --- ibctesting/light_client_test.go | 129 +++++++++++++++++++- testutil/keeper/delayedack.go | 5 + testutil/keeper/lightclient.go | 15 +++ x/delayedack/types/expected_keepers.go | 1 + x/lightclient/ante/ibc_msg_update_client.go | 15 +++ x/lightclient/ante/ibc_msgs_test.go | 11 ++ x/lightclient/keeper/canonical_client.go | 2 + x/lightclient/keeper/client_store.go | 87 +++++++++++++ x/lightclient/keeper/hook_listener.go | 7 ++ x/lightclient/keeper/rollback.go | 121 +++++++++++++++--- x/lightclient/types/errors.go | 3 + x/lightclient/types/expected_keepers.go | 4 + x/lightclient/types/keys.go | 7 ++ 13 files changed, 391 insertions(+), 16 deletions(-) create mode 100644 x/lightclient/keeper/client_store.go diff --git a/ibctesting/light_client_test.go b/ibctesting/light_client_test.go index 853c954c0..27f8a9ea6 100644 --- a/ibctesting/light_client_test.go +++ b/ibctesting/light_client_test.go @@ -6,6 +6,7 @@ import ( 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" @@ -345,10 +346,134 @@ func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_NotCompat // Assert that hard fork was triggered rollapp, _ := s.hubApp().RollappKeeper.GetRollapp(s.hubCtx(), s.rollappChain().ChainID) - s.Equal(2, rollapp.RevisionNumber) + s.Equal(uint64(1), rollapp.RevisionNumber) // The optimistic update valhash should be removed as part of fraud handling _, found = s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) s.False(found) - // FIXME: test for fraud handling in the `x/lightclient` +} + +// 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{} + + 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%5 == 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) + } + + } + + // 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 + s.hubApp().LightClientKeeper.RollbackCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, rollbackHeight) + + 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 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 last block descriptor + s.Require().Equal(bds.BD[len(bds.BD)-1].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/testutil/keeper/delayedack.go b/testutil/keeper/delayedack.go index 019ec85a6..88789414c 100644 --- a/testutil/keeper/delayedack.go +++ b/testutil/keeper/delayedack.go @@ -28,6 +28,11 @@ import ( type ChannelKeeperStub struct{} +// SetPacketReceipt implements types.ChannelKeeper. +func (c ChannelKeeperStub) SetPacketReceipt(ctx sdk.Context, portID string, channelID string, sequence uint64) { + return +} + func (ChannelKeeperStub) LookupModuleByChannel(ctx sdk.Context, portID, channelID string) (string, *capabilitytypes.Capability, error) { return "", nil, nil } diff --git a/testutil/keeper/lightclient.go b/testutil/keeper/lightclient.go index b65c0f99e..bf1ccf165 100644 --- a/testutil/keeper/lightclient.go +++ b/testutil/keeper/lightclient.go @@ -95,6 +95,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, @@ -136,6 +141,11 @@ type MockSequencerKeeper struct { sequencers map[string]sequencertypes.Sequencer } +// GetProposer implements types.SequencerKeeperExpected. +func (m *MockSequencerKeeper) GetProposer(ctx sdk.Context, rollappId string) (val sequencertypes.Sequencer, found bool) { + panic("unimplemented") +} + func (m *MockSequencerKeeper) UnbondingTime(ctx sdk.Context) (res time.Duration) { return types.DefaultExpectedCanonicalClientParams().UnbondingPeriod } @@ -165,6 +175,11 @@ func (m *MockSequencerKeeper) JailSequencerOnFraud(ctx sdk.Context, seqAddr stri 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{} } diff --git a/x/delayedack/types/expected_keepers.go b/x/delayedack/types/expected_keepers.go index 7d886bd3f..552fab58c 100644 --- a/x/delayedack/types/expected_keepers.go +++ b/x/delayedack/types/expected_keepers.go @@ -13,6 +13,7 @@ import ( // ChannelKeeper defines the expected IBC channel keeper type ChannelKeeper interface { LookupModuleByChannel(ctx sdk.Context, portID, channelID string) (string, *capabilitytypes.Capability, error) + SetPacketReceipt(ctx sdk.Context, portID, channelID string, sequence uint64) } type RollappKeeper interface { diff --git a/x/lightclient/ante/ibc_msg_update_client.go b/x/lightclient/ante/ibc_msg_update_client.go index f70d7481a..6a232c23a 100644 --- a/x/lightclient/ante/ibc_msg_update_client.go +++ b/x/lightclient/ante/ibc_msg_update_client.go @@ -14,6 +14,7 @@ func (i IBCMessagesDecorator) HandleMsgUpdateClient(ctx sdk.Context, msg *ibccli if !found { return nil } + // Cast client state to tendermint client state - we need this to get the chain id(rollapp id) tmClientState, ok := clientState.(*ibctm.ClientState) if !ok { @@ -26,6 +27,11 @@ func (i IBCMessagesDecorator) HandleMsgUpdateClient(ctx sdk.Context, msg *ibccli return nil // The client is not a rollapp's canonical client. Continue with default behaviour. } + // cannot update the LC unless fork is resolved (after receiving state updates of HF height +1 & HF height +2 + if i.lightClientKeeper.IsHardForkingInProgress(ctx, rollappID) { + return types.ErrorHardForkInProgress + } + clientMessage, err := ibcclienttypes.UnpackClientMessage(msg.ClientMessage) if err != nil { return nil @@ -39,6 +45,15 @@ func (i IBCMessagesDecorator) HandleMsgUpdateClient(ctx sdk.Context, msg *ibccli return nil } + // FIXME: enable later on + /* + // 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 != i.rollappKeeper.GetRevision(ctx, rollappID) { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "client is not compatible with the rollapp") + } + */ + // Check if there are existing block descriptors for the given height of client state height := uint64(header.Header.Height) stateInfo, err := i.rollappKeeper.FindStateInfoByHeight(ctx, rollappID, height) diff --git a/x/lightclient/ante/ibc_msgs_test.go b/x/lightclient/ante/ibc_msgs_test.go index d296f9ff7..fcc1019cf 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) { + panic("unimplemented") +} + func NewMockRollappKeeper(rollapps map[string]rollapptypes.Rollapp, stateInfos map[string]map[uint64]rollapptypes.StateInfo) *MockRollappKeeper { return &MockRollappKeeper{ rollapps: rollapps, @@ -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 7cf95443b..7270f472a 100644 --- a/x/lightclient/keeper/canonical_client.go +++ b/x/lightclient/keeper/canonical_client.go @@ -77,6 +77,8 @@ func (k Keeper) validClient(ctx sdk.Context, clientID string, cs exported.Client if err := types.IsCanonicalClientParamsValid(tmClientState, &expClient); err != nil { return errorsmod.Wrap(err, "params") } + + // FIXME: can be refactored using iterators 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..70f45c7a2 --- /dev/null +++ b/x/lightclient/keeper/client_store.go @@ -0,0 +1,87 @@ +package keeper + +import ( + "encoding/binary" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" + 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" +) + +// 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) +} + +func GetPreviousConsensusStateHeight(clientStore sdk.KVStore, cdc codec.BinaryCodec, height exported.Height) (exported.Height, bool) { + iterateStore := prefix.NewStore(clientStore, []byte(ibctm.KeyIterateConsensusStatePrefix)) + iterator := iterateStore.ReverseIterator(nil, bigEndianHeightBytes(height)) + defer iterator.Close() + + if !iterator.Valid() { + return nil, false + } + + prevHeight := ibctm.GetHeightFromIterationKey(iterator.Key()) + return prevHeight, true +} + +func bigEndianHeightBytes(height exported.Height) []byte { + heightBytes := make([]byte, 16) + binary.BigEndian.PutUint64(heightBytes, height.GetRevisionNumber()) + binary.BigEndian.PutUint64(heightBytes[8:], height.GetRevisionHeight()) + return heightBytes +} + +// 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/hook_listener.go b/x/lightclient/keeper/hook_listener.go index 35d2d807d..5160ac65f 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -39,6 +39,13 @@ func (hook rollappHook) AfterUpdateState( } return nil } + + // first state after hardfork, should reset the client to active state + if hook.k.IsHardForkingInProgress(ctx, rollappId) { + hook.k.ResolveHardFork(ctx, rollappId) + return nil + } + sequencerPk, err := hook.k.GetSequencerPubKey(ctx, stateInfo.Sequencer) if err != nil { return err diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index 74bcbb8a3..187664048 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -2,24 +2,117 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/dymensionxyz/dymension/v3/x/lightclient/types" + + 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(sdk.Context, string, uint64) error { - /* - // freeze IBC client state - clientState, ok := k.ibcClientKeeper.GetClientState(ctx, clientId) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidClientState, "client state for clientID %s not found", clientId) - } +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappId string, height uint64) error { + hook.k.RollbackCanonicalClient(ctx, rollappId, height) + return nil +} + +func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, height uint64) { + client, found := k.GetCanonicalClient(ctx, rollappId) + if !found { + k.Logger(ctx).Error("Canonical client not found", "rollappId", rollappId) + return + } + cs := k.ibcClientKeeper.ClientStore(ctx, client) - tmClientState, ok := clientState.(*cometbfttypes.ClientState) - if !ok { - return errorsmod.Wrapf(types.ErrInvalidClientState, "client state with ID %s is not a tendermint client state", clientId) + // iterate over all consensus states and metadata in the client store + ibctm.IterateConsensusStateAscending(cs, func(h exported.Height) bool { + // if the height is lower than the target height, continue + if h.GetRevisionHeight() < height { + return false } - tmClientState.FrozenHeight = clienttypes.NewHeight(tmClientState.GetLatestHeight().GetRevisionHeight(), tmClientState.GetLatestHeight().GetRevisionNumber()) - k.ibcClientKeeper.SetClientState(ctx, clientId, tmClientState) + // delete consensus state and metadata + deleteConsensusState(cs, h) + deleteConsensusMetadata(cs, h) - */ - return nil + // clean the optimistic updates valset + k.RemoveConsensusStateValHash(ctx, client, height) + + return false + }) + // 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, height) +} + +// set latest IBC consensus state nextValHash to the current proposing sequencer. +func (k Keeper) ResolveHardFork(ctx sdk.Context, rollappID string) { + client, _ := k.GetCanonicalClient(ctx, rollappID) + clientStore := k.ibcClientKeeper.ClientStore(ctx, client) + + stateinfo, _ := k.rollappKeeper.GetLatestStateInfo(ctx, rollappID) + height := stateinfo.GetLatestHeight() + bd := stateinfo.GetLatestBlockDescriptor() + + // unfreeze the client and set the latest height + k.resetClientToValidState(clientStore, height) + + // add consensus states based on the block descriptors + valHash := k.getValidatorHashForHeight(ctx, rollappID, height) + cs := ibctm.ConsensusState{ + Timestamp: bd.Timestamp, + Root: commitmenttypes.NewMerkleRoot(bd.StateRoot), + NextValidatorsHash: valHash, + } + + setConsensusState(clientStore, k.cdc, clienttypes.NewHeight(1, height), &cs) + + k.setHardForkResolved(ctx, rollappID) +} + +// 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) + 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) +} + +// FIXME: assure there's no case with no proposer +func (k Keeper) getValidatorHashForHeight(ctx sdk.Context, rollappId string, height uint64) []byte { + proposer, _ := k.sequencerKeeper.GetProposer(ctx, rollappId) + proposerHash, _ := proposer.GetDymintPubKeyHash() + + return proposerHash +} + +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)) } diff --git a/x/lightclient/types/errors.go b/x/lightclient/types/errors.go index 309fb6e1f..bc8db3724 100644 --- a/x/lightclient/types/errors.go +++ b/x/lightclient/types/errors.go @@ -10,4 +10,7 @@ var ( 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 not found") + 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, "cannot update light client until forking is finished") ) diff --git a/x/lightclient/types/expected_keepers.go b/x/lightclient/types/expected_keepers.go index 2bdc2bf2f..ac00ff3a4 100644 --- a/x/lightclient/types/expected_keepers.go +++ b/x/lightclient/types/expected_keepers.go @@ -17,12 +17,15 @@ type SequencerKeeperExpected interface { GetSequencersByRollapp(ctx sdk.Context, rollappId string) (list []sequencertypes.Sequencer) UnbondingTime(ctx sdk.Context) (res time.Duration) JailSequencerOnFraud(ctx sdk.Context, sequencerAddress string) error + + GetProposer(ctx sdk.Context, rollappId string) (val sequencertypes.Sequencer, found bool) } 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) GetStateInfo(ctx sdk.Context, rollappId string, index uint64) (val rollapptypes.StateInfo, found bool) + GetLatestStateInfo(ctx sdk.Context, rollappId string) (rollapptypes.StateInfo, bool) SetRollapp(ctx sdk.Context, rollapp rollapptypes.Rollapp) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error } @@ -32,6 +35,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/keys.go b/x/lightclient/types/keys.go index 3ad12c0ad..0b654aa36 100644 --- a/x/lightclient/types/keys.go +++ b/x/lightclient/types/keys.go @@ -22,6 +22,7 @@ var ( RollappClientKey = []byte{0x01} ConsensusStateValhashKey = []byte{0x03} canonicalClientKey = []byte{0x04} + hardForkKey = []byte{0x05} ) func GetRollappClientKey(rollappId string) []byte { @@ -51,3 +52,9 @@ func ParseConsensusStateValhashKey(key []byte) (clientID string, height uint64) height = sdk.BigEndianToUint64(parts[1]) return } + +func HardForkKey(rollappID string) []byte { + key := hardForkKey + key = append(key, []byte(rollappID)...) + return key +} From 076136a959dbde203cfbd248bd82e47ba509142f Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:53:57 +0200 Subject: [PATCH 14/68] feat(hard_fork): DRS and stateUpdate (#1369) --- app/upgrades/v4/upgrade.go | 2 +- proto/dymensionxyz/dymension/rollapp/tx.proto | 2 + x/rollapp/keeper/fraud_handler.go | 10 + x/rollapp/keeper/fraud_handler_test.go | 6 +- .../keeper/msg_server_create_rollapp_test.go | 65 ------- .../msg_server_mark_vulnerable_rollapps.go | 5 +- ...sg_server_mark_vulnerable_rollapps_test.go | 18 +- x/rollapp/keeper/msg_server_update_state.go | 52 ++++-- .../keeper/msg_server_update_state_test.go | 39 +--- x/rollapp/keeper/rollapp.go | 4 - x/rollapp/keeper/rollapp_suite_test.go | 9 +- x/rollapp/types/chain_id_test.go | 68 +++++++ x/rollapp/types/errors.go | 1 + x/rollapp/types/tx.pb.go | 171 +++++++++++------- 14 files changed, 240 insertions(+), 212 deletions(-) create mode 100644 x/rollapp/types/chain_id_test.go diff --git a/app/upgrades/v4/upgrade.go b/app/upgrades/v4/upgrade.go index 64ce75a8a..bb68de0e6 100644 --- a/app/upgrades/v4/upgrade.go +++ b/app/upgrades/v4/upgrade.go @@ -247,7 +247,7 @@ func ConvertOldRollappToNew(oldRollapp rollapptypes.Rollapp) rollapptypes.Rollap }, InitialSequencer: "*", Launched: true, - RevisionNumber: 1, + RevisionNumber: 0, } } diff --git a/proto/dymensionxyz/dymension/rollapp/tx.proto b/proto/dymensionxyz/dymension/rollapp/tx.proto index ac31e4da7..8ca650739 100644 --- a/proto/dymensionxyz/dymension/rollapp/tx.proto +++ b/proto/dymensionxyz/dymension/rollapp/tx.proto @@ -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 + uint64 rollapp_revision = 9; } message MsgUpdateStateResponse { diff --git a/x/rollapp/keeper/fraud_handler.go b/x/rollapp/keeper/fraud_handler.go index 762761a65..e019717d7 100644 --- a/x/rollapp/keeper/fraud_handler.go +++ b/x/rollapp/keeper/fraud_handler.go @@ -149,3 +149,13 @@ func (k Keeper) TruncStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, frau // Update the state info in the keeper k.SetStateInfo(ctx, *stateInfo) } + +func (k Keeper) HardForkObsoleteDRSVersion(ctx sdk.Context, rollappID string) error { + lastBatch, ok := k.GetLatestStateInfo(ctx, rollappID) + if !ok { + return errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "can't hard fork before the first state info is created") + } + + // we invoke a hard fork on the last posted batch without reverting any states + return k.HardFork(ctx, rollappID, lastBatch.GetLatestHeight()+1) +} diff --git a/x/rollapp/keeper/fraud_handler_test.go b/x/rollapp/keeper/fraud_handler_test.go index 414322bd3..c3e6d0ba0 100644 --- a/x/rollapp/keeper/fraud_handler_test.go +++ b/x/rollapp/keeper/fraud_handler_test.go @@ -69,11 +69,7 @@ func (suite *RollappTestSuite) TestHardFork() { } // Assert initial stats (revision 0, states pending) - rollapp, found := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappId) - suite.Require().True(found) - suite.Require().Zero(rollapp.RevisionNumber) - - // check queue + suite.assertNotForked(rollappId) queue := suite.App.RollappKeeper.GetAllFinalizationQueueUntilHeightInclusive(suite.Ctx, initialHeight+numOfStates+suite.App.RollappKeeper.DisputePeriodInBlocks(suite.Ctx)) suite.Require().Len(queue, int(numOfStates)) diff --git a/x/rollapp/keeper/msg_server_create_rollapp_test.go b/x/rollapp/keeper/msg_server_create_rollapp_test.go index 132fb7b7f..0f5ec5bf2 100644 --- a/x/rollapp/keeper/msg_server_create_rollapp_test.go +++ b/x/rollapp/keeper/msg_server_create_rollapp_test.go @@ -91,71 +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, - }, - { - name: "non 1 revision", - rollappId: "rollapp_1234-2", - 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) TestOverwriteEIP155Key() { tests := []struct { name string diff --git a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go index 7210ca6ff..c79d23bbd 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go +++ b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go @@ -72,10 +72,9 @@ func (k Keeper) MarkVulnerableRollapps(ctx sdk.Context, drsVersions []string) (i _, vulnerable := vulnerableVersions[bd.DrsVersion] if vulnerable { - err := k.MarkRollappAsVulnerable(ctx, rollapp.RollappId) + err := k.HardForkObsoleteDRSVersion(ctx, rollapp.RollappId) if err != nil { - // FIXME: should continue to other rollapps if one fails - return 0, fmt.Errorf("freeze rollapp: %w", err) + logger.With("rollapp_id", rollapp.RollappId).Error("mark rollapp as vulnerable", "error", err) } vulnerableNum++ } diff --git a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go index dfac07a7d..486eee4e9 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go +++ b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go @@ -13,8 +13,6 @@ import ( "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) -// FIXME: validate mark vulnerable causes hard fork - func (s *RollappTestSuite) TestMarkVulnerableRollapps() { type rollapp struct { name string @@ -144,22 +142,20 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { // 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)) s.AssertEventEmitted(s.Ctx, eventName, 0) // check non-vulnerable rollapps: all rollapps are still non-vulnerable - nonVulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterNonVulnerable) + nonVulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterNonForked) actualNonVulnRollappIDs := uslice.Map(nonVulnRa, func(r types.Rollapp) string { return r.RollappId }) allRollapps := slices.Concat(expectedVulnRollappIDs, expectedNonVulnRollappIDs) s.ElementsMatch(allRollapps, actualNonVulnRollappIDs) // check vulnerable rollapps: no vulnerable rollapps - vulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterVulnerable) + vulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterForked) s.Empty(vulnRa) // check the vulnerable version set is empty @@ -174,12 +170,12 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { s.AssertEventEmitted(s.Ctx, eventName, 1) // check non-vulnerable rollapps - nonVulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterNonVulnerable) + nonVulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterNonForked) actualNonVulnRollappIDs := uslice.Map(nonVulnRa, func(r types.Rollapp) string { return r.RollappId }) s.ElementsMatch(expectedNonVulnRollappIDs, actualNonVulnRollappIDs) // check vulnerable rollapps - vulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterVulnerable) + vulnRa := s.App.RollappKeeper.FilterRollapps(s.Ctx, FilterForked) actualVulnRollappIDs := uslice.Map(vulnRa, func(r types.Rollapp) string { return r.RollappId }) s.ElementsMatch(expectedVulnRollappIDs, actualVulnRollappIDs) @@ -192,10 +188,10 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { } } -func FilterVulnerable(b types.Rollapp) bool { +func FilterForked(b types.Rollapp) bool { return b.RevisionNumber > 0 } -func FilterNonVulnerable(b types.Rollapp) bool { +func FilterNonForked(b types.Rollapp) bool { return b.RevisionNumber == 0 } diff --git a/x/rollapp/keeper/msg_server_update_state.go b/x/rollapp/keeper/msg_server_update_state.go index 30723902e..77e1fa2e8 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -28,19 +28,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 @@ -85,12 +77,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, - }) - creationHeight := uint64(ctx.BlockHeight()) blockTime := ctx.BlockTime() stateInfo := types.NewStateInfo( @@ -104,9 +90,32 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) msg.BDs, blockTime, ) + + // verify the DRS version is not vulnerable + // check only last block descriptor DRS, since if that last is not vulnerable it means the rollapp already upgraded and is not vulnerable anymore + // Rollapp is using a vulnerable DRS version, hard fork it + // we must return non-error if we want the changes to be saved + if k.IsStateUpdateVulnerable(ctx, stateInfo) { + err := k.HardForkObsoleteDRSVersion(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", stateInfo.GetLatestBlockDescriptor().DrsVersion). + Info("rollapp tried to submit MsgUpdateState with the vulnerable DRS version, mark the rollapp as vulnerable") + + return &types.MsgUpdateStateResponse{}, nil + } + + // 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, "after update state") @@ -140,3 +149,8 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) return &types.MsgUpdateStateResponse{}, nil } + +// IsStateUpdateVulnerable checks if the given DRS version is vulnerable +func (k msgServer) IsStateUpdateVulnerable(ctx sdk.Context, stateInfo *types.StateInfo) bool { + return k.IsDRSVersionVulnerable(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 7ee78e670..9b94a4db1 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" @@ -111,50 +110,26 @@ func (s *RollappTestSuite) TestUpdateStateVulnerableRollapp() { 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) + expectedNextHeight, err := s.PostStateUpdateWithDRSVersion(s.Ctx, raName, proposer, 1, uint64(3), nonVulnerableVersion) 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, []string{vulnerableVersion}) + // mark a DRS version as vulnerable + err = s.App.RollappKeeper.SetVulnerableDRSVersion(s.Ctx, vulnerableVersion) 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) + _, err = s.PostStateUpdateWithDRSVersion(s.Ctx, raName, proposer, expectedNextHeight, uint64(3), vulnerableVersion) s.Require().NoError(err) - // the rollapp now is vulnerable - ok = s.IsRollappVulnerable(raName) - s.Require().True(ok) + s.assertFraudHandled(raName, expectedNextHeight) // 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) - 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) + s.Require().Equal(expectedNextHeight-1, actualLastHeight) } func (suite *RollappTestSuite) TestUpdateStateUnknownRollappId() { diff --git a/x/rollapp/keeper/rollapp.go b/x/rollapp/keeper/rollapp.go index c95e36b92..db197cf1e 100644 --- a/x/rollapp/keeper/rollapp.go +++ b/x/rollapp/keeper/rollapp.go @@ -227,10 +227,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.HardFork(ctx, rollappId, 0) // FIXME: use a proper hard fork height -} - 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{}) diff --git a/x/rollapp/keeper/rollapp_suite_test.go b/x/rollapp/keeper/rollapp_suite_test.go index 886112464..b2422effa 100644 --- a/x/rollapp/keeper/rollapp_suite_test.go +++ b/x/rollapp/keeper/rollapp_suite_test.go @@ -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.RevisionNumber > 0 +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/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/errors.go b/x/rollapp/types/errors.go index 77117affc..04b7cd3ab 100644 --- a/x/rollapp/types/errors.go +++ b/x/rollapp/types/errors.go @@ -55,4 +55,5 @@ var ( 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/tx.pb.go b/x/rollapp/types/tx.pb.go index a3da34554..af268fd5c 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 + 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 { } @@ -1023,73 +1032,74 @@ func init() { } var fileDescriptor_1a86300fb8647ecb = []byte{ - // 1041 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, 0xb2, 0x25, 0x1d, 0xaa, 0x62, 0xb2, 0x4b, 0xc8, 0xa6, 0x42, - 0x14, 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, 0xd5, 0xc6, 0x81, 0x4d, 0xb5, 0x69, 0x4a, 0x60, 0xf5, 0xa5, 0x2e, 0x61, 0x1e, 0x61, - 0x2d, 0x8f, 0xd9, 0xad, 0xc1, 0x66, 0xf8, 0x88, 0x88, 0xd5, 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, 0xda, 0xc4, 0x26, 0x62, 0xd9, 0x0a, 0x57, - 0x91, 0xb5, 0xf1, 0x43, 0x16, 0x2a, 0x6d, 0x66, 0xdf, 0xa7, 0xd8, 0xe4, 0xd8, 0x88, 0xd8, 0x48, - 0x87, 0xa5, 0x6e, 0x68, 0x20, 0x54, 0xd7, 0xea, 0xda, 0x46, 0xd1, 0x88, 0xb7, 0xe8, 0x15, 0x00, - 0x19, 0xa2, 0xe3, 0x58, 0x7a, 0x46, 0xbc, 0x2c, 0x4a, 0xcb, 0x23, 0x0b, 0xdd, 0x81, 0x15, 0xc7, - 0x77, 0xb8, 0x63, 0xba, 0x1d, 0x86, 0xbf, 0xec, 0x63, 0xbf, 0x8b, 0xa9, 0x5e, 0x12, 0xa8, 0x8a, - 0x7c, 0xf1, 0x24, 0xb6, 0xa3, 0x55, 0x58, 0x34, 0x5d, 0xc7, 0x64, 0x7a, 0x59, 0x00, 0xa2, 0x0d, - 0xfa, 0x18, 0x0a, 0x71, 0xad, 0xfa, 0x8d, 0xba, 0xb6, 0x51, 0xda, 0x6a, 0x35, 0xe7, 0x77, 0xae, - 0x29, 0xd3, 0x6e, 0x4b, 0x9a, 0xa1, 0x1c, 0xa0, 0x03, 0x28, 0x8f, 0x2b, 0xa1, 0x2f, 0x0b, 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, 0xd7, - 0x36, 0x96, 0xb7, 0x9a, 0x29, 0x33, 0x6c, 0x1e, 0xb6, 0x0f, 0x86, 0x01, 0x36, 0xf2, 0x03, 0x2f, - 0x7c, 0xee, 0x94, 0xbf, 0xf9, 0xe7, 0xd7, 0x37, 0x63, 0x6d, 0x3f, 0xca, 0x15, 0xb2, 0x95, 0x52, - 0xa3, 0x0a, 0xfa, 0xe5, 0x7e, 0x18, 0x98, 0x05, 0xc4, 0x67, 0xb8, 0xf1, 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, 0x34, 0x5e, 0x83, 0xf5, 0x39, 0xaa, 0x29, 0x75, 0x7f, 0xca, 0xc0, 0xb2, 0xc2, 0x3d, 0xe1, - 0x26, 0xc7, 0x73, 0x2e, 0xc2, 0x2d, 0x18, 0x49, 0x38, 0xa9, 0x69, 0x1d, 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, 0x20, 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, 0x75, 0x6d, 0xa3, 0x60, 0x88, 0xf5, 0xc4, 0x71, 0xcc, 0x57, 0x96, 0x1a, - 0x3a, 0xac, 0x5d, 0xd4, 0x44, 0xc9, 0xf5, 0xbd, 0x06, 0xab, 0x6d, 0x66, 0x1f, 0x50, 0xd3, 0x67, - 0xc7, 0x98, 0x3e, 0x0e, 0xa5, 0x66, 0x3d, 0x27, 0x40, 0xeb, 0x70, 0xa3, 0xdb, 0xa7, 0x14, 0xfb, - 0xbc, 0x33, 0x7e, 0x1a, 0xcb, 0xd2, 0x28, 0x80, 0xe8, 0x26, 0x14, 0x7d, 0x7c, 0x22, 0x01, 0x91, - 0x7e, 0x05, 0x1f, 0x9f, 0x3c, 0x9e, 0x72, 0x62, 0xb3, 0x97, 0xd4, 0xdd, 0x41, 0x61, 0x9e, 0x17, - 0x63, 0x34, 0x6a, 0x70, 0x6b, 0x5a, 0x32, 0x2a, 0xdb, 0xdf, 0x35, 0x28, 0xb6, 0x99, 0xbd, 0x6b, - 0x59, 0xbb, 0x73, 0x07, 0x1c, 0x82, 0x9c, 0x6f, 0x7a, 0x58, 0xa6, 0x24, 0xd6, 0x09, 0xe9, 0x84, - 0xcd, 0x8e, 0x87, 0xbf, 0x43, 0x7c, 0xd1, 0xcc, 0xa2, 0x31, 0x6e, 0x0a, 0xef, 0xa5, 0xe3, 0x99, - 0x36, 0x96, 0xdd, 0x8c, 0x36, 0xa8, 0x02, 0xd9, 0x3e, 0x75, 0xc5, 0x79, 0x2f, 0x1a, 0xe1, 0x52, - 0xdc, 0x5f, 0x6a, 0x61, 0x2a, 0x1a, 0xbc, 0x68, 0x44, 0x9b, 0x8b, 0x6d, 0x69, 0xbc, 0x08, 0x2b, - 0xaa, 0x0e, 0x55, 0xdd, 0x9f, 0x1a, 0x94, 0x55, 0x9b, 0xe6, 0x17, 0xb8, 0x0c, 0x19, 0x39, 0x05, - 0x72, 0x46, 0xc6, 0xb1, 0x54, 0xc1, 0xd9, 0x99, 0x05, 0xe7, 0x12, 0x0a, 0x5e, 0x9c, 0x53, 0x70, - 0x7e, 0x4a, 0xc1, 0x4b, 0x53, 0x0a, 0x2e, 0xcc, 0x2e, 0x78, 0x4d, 0x1c, 0x33, 0x55, 0x9a, 0xaa, - 0x19, 0x8b, 0x92, 0x0d, 0xec, 0x91, 0xc1, 0x15, 0x4b, 0x4e, 0x38, 0x5e, 0xd3, 0xc2, 0xab, 0x30, - 0x2a, 0xbc, 0x0b, 0x2f, 0xb7, 0x99, 0xdd, 0x36, 0xe9, 0xd3, 0xc3, 0xbe, 0xeb, 0x63, 0x6a, 0x1e, - 0xb9, 0xf1, 0x70, 0x61, 0xe1, 0xed, 0x36, 0xfb, 0xbc, 0x47, 0xa8, 0xc3, 0x87, 0x32, 0x9b, 0x91, - 0x01, 0xdd, 0x86, 0xb2, 0x45, 0x59, 0x67, 0x80, 0x69, 0x78, 0x5d, 0x99, 0x9e, 0xa9, 0x67, 0x85, - 0x80, 0x94, 0x1d, 0x4a, 0xd3, 0xce, 0x72, 0x98, 0xc3, 0x88, 0xd2, 0x58, 0x87, 0xdb, 0x33, 0xa3, - 0xc5, 0x29, 0x6d, 0x7d, 0x5b, 0x80, 0x6c, 0x9b, 0xd9, 0xe8, 0x6b, 0xb8, 0x71, 0xf1, 0x7b, 0x9e, - 0x38, 0x29, 0x2e, 0x7f, 0x71, 0xaa, 0xef, 0x5d, 0x95, 0x11, 0x27, 0x81, 0x7e, 0xd1, 0x40, 0x9f, - 0xf9, 0x81, 0xfa, 0x20, 0x85, 0xdb, 0x59, 0xe4, 0xea, 0xfd, 0xff, 0x40, 0x56, 0xe9, 0xf5, 0xa1, - 0x34, 0x3e, 0xe0, 0x9b, 0xa9, 0x7d, 0x0a, 0x7c, 0xf5, 0xdd, 0xab, 0xe1, 0x55, 0xd8, 0xef, 0x34, - 0x58, 0x99, 0x9c, 0x94, 0xdb, 0x29, 0xbc, 0x4d, 0xb0, 0xaa, 0x1f, 0x5e, 0x87, 0xa5, 0x32, 0x39, - 0x86, 0xbc, 0x1c, 0x82, 0x6f, 0xa4, 0xf0, 0x13, 0x41, 0xab, 0x9b, 0xa9, 0xa1, 0x2a, 0x0e, 0x81, - 0xe2, 0x68, 0x1c, 0xdd, 0x4d, 0x2d, 0x5b, 0x18, 0x6d, 0xfb, 0x2a, 0xe8, 0xf1, 0x80, 0xa3, 0x61, - 0x90, 0x26, 0xa0, 0x42, 0xa7, 0x0a, 0x38, 0x31, 0x01, 0xd0, 0xcf, 0x1a, 0xac, 0xcd, 0xb8, 0xff, - 0xef, 0xa7, 0x70, 0x38, 0x9d, 0x5a, 0xdd, 0xbd, 0x36, 0x35, 0x4e, 0x6c, 0xef, 0x93, 0x67, 0x67, - 0x35, 0xed, 0xf9, 0x59, 0x4d, 0xfb, 0xfb, 0xac, 0xa6, 0xfd, 0x78, 0x5e, 0x5b, 0x78, 0x7e, 0x5e, - 0x5b, 0xf8, 0xe3, 0xbc, 0xb6, 0xf0, 0xc5, 0xb6, 0xed, 0xf0, 0x5e, 0xff, 0xa8, 0xd9, 0x25, 0x5e, - 0x6b, 0xc6, 0x1f, 0xc4, 0xe0, 0x5e, 0xeb, 0x74, 0xf4, 0xf3, 0x34, 0x0c, 0x30, 0x3b, 0xca, 0x8b, - 0x5f, 0x85, 0x7b, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xdf, 0x56, 0xf3, 0x18, 0x6b, 0x0d, 0x00, - 0x00, + // 1060 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0x4f, 0x6f, 0x1b, 0x45, + 0x14, 0xcf, 0xda, 0x8e, 0x63, 0x3f, 0x3b, 0xa9, 0x33, 0x44, 0x61, 0x71, 0x8b, 0x71, 0x1d, 0x21, + 0x52, 0x5a, 0x6c, 0x92, 0x06, 0x04, 0x81, 0x4b, 0xd2, 0x48, 0x6d, 0x41, 0xa6, 0xb0, 0x0d, 0x39, + 0x70, 0xb1, 0x36, 0xde, 0xc9, 0x66, 0x55, 0xef, 0x8e, 0x99, 0x19, 0x3b, 0x31, 0xdc, 0x90, 0x10, + 0x07, 0x24, 0xc4, 0x89, 0x13, 0x1f, 0x82, 0x03, 0x57, 0xae, 0xa8, 0xc7, 0x1e, 0xe1, 0x82, 0x50, + 0x72, 0xe0, 0x6b, 0xa0, 0x99, 0x9d, 0x1d, 0x3b, 0xf1, 0x9f, 0xdd, 0x04, 0x4e, 0x3b, 0xf3, 0xe6, + 0xf7, 0xfe, 0xfd, 0xde, 0x9b, 0x37, 0x5a, 0x78, 0xc3, 0x19, 0xf8, 0x38, 0x60, 0x1e, 0x09, 0x4e, + 0x07, 0x5f, 0x35, 0xf4, 0xa6, 0x41, 0x49, 0xa7, 0x63, 0x77, 0xbb, 0x0d, 0x7e, 0x5a, 0xef, 0x52, + 0xc2, 0x09, 0xaa, 0x8c, 0x02, 0xeb, 0x7a, 0x53, 0x57, 0xc0, 0xf2, 0xcb, 0x6d, 0xc2, 0x7c, 0xc2, + 0x1a, 0x3e, 0x73, 0x1b, 0xfd, 0x0d, 0xf1, 0x09, 0x15, 0xcb, 0xef, 0xc4, 0x78, 0x38, 0xec, 0x90, + 0xf6, 0xb3, 0x96, 0x83, 0x59, 0x9b, 0x7a, 0x5d, 0x4e, 0xa8, 0x52, 0xbb, 0x17, 0xa3, 0xa6, 0xbe, + 0x0a, 0xfd, 0x56, 0x0c, 0xda, 0xc7, 0xdc, 0x76, 0x6c, 0x6e, 0x2b, 0xf8, 0x46, 0x0c, 0xdc, 0xc5, + 0x01, 0x66, 0x1e, 0x6b, 0x79, 0xc1, 0x11, 0x51, 0x2a, 0x2b, 0x2e, 0x71, 0x89, 0x5c, 0x36, 0xc4, + 0x2a, 0x94, 0xd6, 0x7e, 0x48, 0x43, 0xa9, 0xc9, 0xdc, 0x07, 0x14, 0xdb, 0x1c, 0x5b, 0xa1, 0x36, + 0x32, 0x61, 0xa1, 0x2d, 0x04, 0x84, 0x9a, 0x46, 0xd5, 0x58, 0xcf, 0x5b, 0xd1, 0x16, 0xbd, 0x0a, + 0xa0, 0x5c, 0xb4, 0x3c, 0xc7, 0x4c, 0xc9, 0xc3, 0xbc, 0x92, 0x3c, 0x76, 0xd0, 0x5d, 0x58, 0xf6, + 0x02, 0x8f, 0x7b, 0x76, 0xa7, 0xc5, 0xf0, 0x97, 0x3d, 0x1c, 0xb4, 0x31, 0x35, 0x0b, 0x12, 0x55, + 0x52, 0x07, 0x4f, 0x23, 0x39, 0x5a, 0x81, 0x79, 0xbb, 0xe3, 0xd9, 0xcc, 0x2c, 0x4a, 0x40, 0xb8, + 0x41, 0x1f, 0x43, 0x2e, 0xca, 0xd5, 0x5c, 0xac, 0x1a, 0xeb, 0x85, 0xcd, 0x46, 0x7d, 0x76, 0xe5, + 0xea, 0x2a, 0xec, 0xa6, 0x52, 0xb3, 0xb4, 0x01, 0xb4, 0x0f, 0xc5, 0x51, 0x26, 0xcc, 0x25, 0x69, + 0xf0, 0x6e, 0x9c, 0xc1, 0x87, 0xa1, 0xce, 0xe3, 0xe0, 0x88, 0xec, 0x66, 0x9e, 0xff, 0xf5, 0x9a, + 0x61, 0x15, 0xdc, 0xa1, 0x08, 0x3d, 0x84, 0x85, 0xbe, 0xdf, 0xe2, 0x83, 0x2e, 0x36, 0x6f, 0x54, + 0x8d, 0xf5, 0xa5, 0xcd, 0x7a, 0xc2, 0x08, 0xeb, 0x07, 0xcd, 0xfd, 0x41, 0x17, 0x5b, 0xd9, 0xbe, + 0x2f, 0xbe, 0xdb, 0xc5, 0x6f, 0xfe, 0xf9, 0xe5, 0xcd, 0x88, 0xdb, 0x8f, 0x32, 0xb9, 0x74, 0xa9, + 0x50, 0x2b, 0x83, 0x79, 0xb9, 0x1e, 0x16, 0x66, 0x5d, 0x12, 0x30, 0x5c, 0xfb, 0x35, 0x05, 0x37, + 0x9b, 0xcc, 0xfd, 0xbc, 0xeb, 0x0c, 0x0f, 0x45, 0x44, 0xd4, 0xb7, 0xb9, 0x47, 0x02, 0xc1, 0x28, + 0x39, 0x09, 0x70, 0x54, 0xb5, 0x70, 0x73, 0xad, 0x9a, 0xa5, 0xa7, 0xd4, 0xec, 0xb3, 0x91, 0xea, + 0xcc, 0x5f, 0xab, 0x3a, 0x8a, 0xd0, 0xe9, 0x35, 0xca, 0xfe, 0x1f, 0x35, 0xda, 0x06, 0x41, 0x6d, + 0x48, 0x40, 0xed, 0x75, 0x58, 0x9b, 0xc1, 0x9a, 0x66, 0xf7, 0xb7, 0x14, 0x2c, 0x69, 0xdc, 0x53, + 0x6e, 0x73, 0x3c, 0xe3, 0x22, 0xdc, 0x82, 0x21, 0x85, 0xe3, 0x9c, 0x56, 0xa1, 0xc0, 0xb8, 0x4d, + 0xf9, 0x23, 0xec, 0xb9, 0xc7, 0x5c, 0xb2, 0x99, 0xb1, 0x46, 0x45, 0x42, 0x3f, 0xe8, 0xf9, 0xbb, + 0x62, 0x74, 0x30, 0x33, 0x23, 0xcf, 0x87, 0x02, 0xb4, 0x0a, 0xd9, 0xbd, 0x9d, 0x4f, 0x6d, 0x7e, + 0x2c, 0x49, 0xce, 0x5b, 0x6a, 0x87, 0x1e, 0x41, 0x7a, 0x77, 0x8f, 0x99, 0x0b, 0x92, 0xa2, 0xb7, + 0xe3, 0x28, 0x92, 0xc6, 0xf6, 0xf4, 0x5c, 0x62, 0x92, 0xa7, 0x39, 0x4b, 0x98, 0x40, 0x08, 0x32, + 0x1d, 0x9b, 0x71, 0x33, 0x57, 0x35, 0xd6, 0x73, 0x96, 0x5c, 0xa3, 0x3b, 0x50, 0x8a, 0x1a, 0x85, + 0xe2, 0xbe, 0x27, 0x6c, 0x99, 0x79, 0x19, 0xda, 0x0d, 0x1a, 0x75, 0x62, 0x28, 0x1e, 0xeb, 0xdc, + 0x6c, 0x69, 0xa1, 0x66, 0xc2, 0xea, 0x45, 0xfa, 0x34, 0xb3, 0xdf, 0x1b, 0xb0, 0xd2, 0x64, 0xee, + 0x3e, 0xb5, 0x03, 0x76, 0x84, 0xe9, 0x13, 0x51, 0x15, 0x76, 0xec, 0x75, 0xd1, 0x1a, 0x2c, 0xb6, + 0x7b, 0x94, 0xe2, 0x80, 0xb7, 0x46, 0x1b, 0xb7, 0xa8, 0x84, 0x12, 0x88, 0x6e, 0x42, 0x3e, 0xc0, + 0x27, 0x0a, 0x10, 0x52, 0x9d, 0x0b, 0xf0, 0xc9, 0x93, 0x09, 0xcd, 0x9d, 0xbe, 0x54, 0x88, 0x6d, + 0x24, 0xe2, 0xbc, 0xe8, 0xa3, 0x56, 0x81, 0x5b, 0x93, 0x82, 0xd1, 0xd1, 0xfe, 0x6e, 0x40, 0xbe, + 0xc9, 0xdc, 0x1d, 0xc7, 0xd9, 0x99, 0x39, 0x0b, 0x11, 0x64, 0x02, 0xdb, 0xc7, 0x2a, 0x24, 0xb9, + 0x8e, 0x09, 0x47, 0xf4, 0x45, 0xf4, 0x4e, 0x08, 0x72, 0x33, 0xf2, 0x7c, 0x54, 0x24, 0xae, 0xb0, + 0xe7, 0xdb, 0x2e, 0x56, 0x85, 0x0f, 0x37, 0xa8, 0x04, 0xe9, 0x1e, 0xed, 0xc8, 0xab, 0x91, 0xb7, + 0xc4, 0x52, 0x5e, 0x75, 0xea, 0x60, 0x2a, 0x7b, 0x61, 0xde, 0x0a, 0x37, 0x17, 0xcb, 0x52, 0x7b, + 0x09, 0x96, 0x75, 0x1e, 0x3a, 0xbb, 0x3f, 0x0d, 0x28, 0xea, 0x32, 0xcd, 0x4e, 0x70, 0x09, 0x52, + 0x6a, 0x60, 0x64, 0xac, 0x94, 0xe7, 0xe8, 0x84, 0xd3, 0x53, 0x13, 0xce, 0xc4, 0x24, 0x3c, 0x3f, + 0x23, 0xe1, 0xec, 0x84, 0x84, 0x17, 0x26, 0x24, 0x9c, 0x9b, 0x9e, 0xf0, 0xaa, 0x6c, 0x33, 0x9d, + 0x9a, 0xce, 0x19, 0xcb, 0x94, 0x2d, 0xec, 0x93, 0xfe, 0x15, 0x53, 0x8e, 0x69, 0xaf, 0x49, 0xee, + 0xb5, 0x1b, 0xed, 0xbe, 0x03, 0xaf, 0x34, 0x99, 0xdb, 0xb4, 0xe9, 0xb3, 0x83, 0x5e, 0x27, 0xc0, + 0xd4, 0x3e, 0xec, 0x44, 0x73, 0x88, 0x89, 0x41, 0x60, 0xf7, 0xf8, 0x31, 0xa1, 0x1e, 0x1f, 0xa8, + 0x68, 0x86, 0x02, 0x74, 0x1b, 0x8a, 0x0e, 0x65, 0xad, 0x3e, 0xa6, 0xe2, 0xda, 0x31, 0x33, 0x55, + 0x4d, 0x4b, 0x02, 0x29, 0x3b, 0x50, 0xa2, 0xed, 0x25, 0x11, 0xc3, 0x50, 0xa5, 0xb6, 0x06, 0xb7, + 0xa7, 0x7a, 0x8b, 0x42, 0xda, 0xfc, 0x36, 0x07, 0xe9, 0x26, 0x73, 0xd1, 0xd7, 0xb0, 0x78, 0xf1, + 0xe9, 0x8f, 0x1d, 0x2a, 0x97, 0x1f, 0xa7, 0xf2, 0x7b, 0x57, 0xd5, 0x88, 0x82, 0x40, 0x3f, 0x1b, + 0x60, 0x4e, 0x7d, 0xcb, 0x3e, 0x48, 0x60, 0x76, 0x9a, 0x72, 0xf9, 0xc1, 0x7f, 0x50, 0xd6, 0xe1, + 0xf5, 0xa0, 0x30, 0xfa, 0x16, 0xd4, 0x13, 0xdb, 0x94, 0xf8, 0xf2, 0xbb, 0x57, 0xc3, 0x6b, 0xb7, + 0xdf, 0x19, 0xb0, 0x3c, 0x3e, 0x29, 0xb7, 0x12, 0x58, 0x1b, 0xd3, 0x2a, 0x7f, 0x78, 0x1d, 0x2d, + 0x1d, 0xc9, 0x11, 0x64, 0xd5, 0x10, 0xbc, 0x93, 0xc0, 0x4e, 0x08, 0x2d, 0x6f, 0x24, 0x86, 0x6a, + 0x3f, 0x04, 0xf2, 0xc3, 0x71, 0x74, 0x2f, 0x31, 0x6d, 0xc2, 0xdb, 0xd6, 0x55, 0xd0, 0xa3, 0x0e, + 0x87, 0xc3, 0x20, 0x89, 0x43, 0x8d, 0x4e, 0xe4, 0x70, 0x6c, 0x02, 0xa0, 0x9f, 0x0c, 0x58, 0x9d, + 0x72, 0xff, 0xdf, 0x4f, 0x60, 0x70, 0xb2, 0x6a, 0x79, 0xe7, 0xda, 0xaa, 0x51, 0x60, 0xbb, 0x9f, + 0x3c, 0x3f, 0xab, 0x18, 0x2f, 0xce, 0x2a, 0xc6, 0xdf, 0x67, 0x15, 0xe3, 0xc7, 0xf3, 0xca, 0xdc, + 0x8b, 0xf3, 0xca, 0xdc, 0x1f, 0xe7, 0x95, 0xb9, 0x2f, 0xb6, 0x5c, 0x8f, 0x1f, 0xf7, 0x0e, 0xeb, + 0x6d, 0xe2, 0x37, 0xa6, 0xfc, 0x6c, 0xf4, 0xef, 0x37, 0x4e, 0x87, 0xff, 0x59, 0x83, 0x2e, 0x66, + 0x87, 0x59, 0xf9, 0x57, 0x71, 0xff, 0xdf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4e, 0xab, 0xd1, 0xc6, + 0x96, 0x0d, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -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 { @@ -2223,6 +2238,9 @@ func (m *MsgUpdateState) Size() (n int) { if m.Last { n += 2 } + if m.RollappRevision != 0 { + n += 1 + sovTx(uint64(m.RollappRevision)) + } return n } @@ -3224,6 +3242,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:]) From fe49c1c7416c90bf298a45cc860f6ed42ae53c34 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Sun, 3 Nov 2024 10:06:24 +0200 Subject: [PATCH 15/68] feat(hard_fork): rollapp fraud proposal (#1371) --- app/keepers/keepers.go | 2 - app/keepers/modules.go | 2 - .../dymension/rollapp/fraud_proposal.proto | 32 + .../dymension/rollapp/proposal.proto | 26 - .../client/cli/tx_submit_fraud_proposal.go | 62 -- x/rollapp/client/proposal_handler.go | 9 - x/rollapp/keeper/fraud_proposal.go | 51 ++ .../keeper/{fraud_handler.go => hard_fork.go} | 5 +- x/rollapp/keeper/liveness_test.go | 5 + .../msg_server_mark_vulnerable_rollapps.go | 2 +- x/rollapp/keeper/msg_server_update_state.go | 2 +- x/rollapp/keeper/state_info.go | 11 +- x/rollapp/proposal_handler.go | 35 -- x/rollapp/types/codec.go | 5 +- x/rollapp/types/expected_keepers.go | 1 + x/rollapp/types/fraud_proposal.pb.go | 549 +++++++++++++++++ x/rollapp/types/hooks.go | 1 - x/rollapp/types/message_fraud_proposal.go | 34 ++ x/rollapp/types/proposal.pb.go | 567 ------------------ x/rollapp/types/proposal_submit_fraud.go | 74 --- x/rollapp/types/state_info.go | 5 +- x/sequencer/keeper/slashing.go | 17 + 22 files changed, 709 insertions(+), 788 deletions(-) create mode 100644 proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto delete mode 100644 proto/dymensionxyz/dymension/rollapp/proposal.proto delete mode 100644 x/rollapp/client/cli/tx_submit_fraud_proposal.go delete mode 100644 x/rollapp/client/proposal_handler.go create mode 100644 x/rollapp/keeper/fraud_proposal.go rename x/rollapp/keeper/{fraud_handler.go => hard_fork.go} (97%) delete mode 100644 x/rollapp/proposal_handler.go create mode 100644 x/rollapp/types/fraud_proposal.pb.go create mode 100644 x/rollapp/types/message_fraud_proposal.go delete mode 100644 x/rollapp/types/proposal.pb.go delete mode 100644 x/rollapp/types/proposal_submit_fraud.go diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index dff448404..003fdbfd3 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" @@ -495,7 +494,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)) diff --git a/app/keepers/modules.go b/app/keepers/modules.go index 43ce2f1c8..f70b5cb9e 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/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto new file mode 100644 index 000000000..95b1fc8be --- /dev/null +++ b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto @@ -0,0 +1,32 @@ +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"; + + +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; + + // hard fork required? + bool hard_fork = 5; + + // sequencer address to jail. optional + string slash_sequencer_address = 6; +} + +// TODO: add slashing only proposal? \ No newline at end of file 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/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/keeper/fraud_proposal.go b/x/rollapp/keeper/fraud_proposal.go new file mode 100644 index 000000000..72fd19434 --- /dev/null +++ b/x/rollapp/keeper/fraud_proposal.go @@ -0,0 +1,51 @@ +package keeper + +import ( + 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" +) + +// FraudProposalHandler handles the submission of a fraud proposal +// The fraud proposal can be submitted by the gov module +func (k Keeper) FraudProposalHandler(ctx sdk.Context, msg types.MsgRollappFraudProposal) error { + if msg.Authority != k.authority { + return errorsmod.Wrap(gerrc.ErrUnauthenticated, "only the gov module can submit fraud proposals") + } + + if err := msg.ValidateBasic(); err != nil { + return errorsmod.Wrap(gerrc.ErrInvalidArgument, "invalid msg") + } + + rollapp, found := k.GetRollapp(ctx, msg.RollappId) + if !found { + return errorsmod.Wrap(gerrc.ErrNotFound, "rollapp not found") + } + // check revision number + if rollapp.RevisionNumber != msg.RollappRevision { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "revision number mismatch") + } + + // validate the fraud height is already committed + sinfo, found := k.GetLatestStateInfo(ctx, msg.RollappId) + if !found || sinfo.GetLatestHeight() < msg.FraudHeight { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height not committed") + } + + // check wether the fraud height is already finalized + sinfo, found = k.GetLatestFinalizedStateInfo(ctx, msg.RollappId) + if found && sinfo.GetLatestHeight() >= msg.FraudHeight { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height already finalized") + } + + // jail the sequencer if needed + if msg.SlashSequencerAddress != "" { + err := k.sequencerKeeper.JailByAddr(ctx, msg.SlashSequencerAddress) + if err != nil { + return errorsmod.Wrap(err, "jail sequencer") + } + } + return k.HardFork(ctx, msg.RollappId, msg.FraudHeight) +} diff --git a/x/rollapp/keeper/fraud_handler.go b/x/rollapp/keeper/hard_fork.go similarity index 97% rename from x/rollapp/keeper/fraud_handler.go rename to x/rollapp/keeper/hard_fork.go index e019717d7..2a7af1e07 100644 --- a/x/rollapp/keeper/fraud_handler.go +++ b/x/rollapp/keeper/hard_fork.go @@ -150,12 +150,11 @@ func (k Keeper) TruncStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, frau k.SetStateInfo(ctx, *stateInfo) } -func (k Keeper) HardForkObsoleteDRSVersion(ctx sdk.Context, rollappID string) error { +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 before the first state info is created") + 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) } diff --git a/x/rollapp/keeper/liveness_test.go b/x/rollapp/keeper/liveness_test.go index 870403b6c..a56617786 100644 --- a/x/rollapp/keeper/liveness_test.go +++ b/x/rollapp/keeper/liveness_test.go @@ -190,6 +190,11 @@ type livenessMockSequencerKeeper struct { jails map[string]int } +// JailByAddr implements types.SequencerKeeper. +func (l livenessMockSequencerKeeper) JailByAddr(ctx sdk.Context, seqAddr string) error { + panic("unimplemented") +} + func newLivenessMockSequencerKeeper() livenessMockSequencerKeeper { return livenessMockSequencerKeeper{ make(map[string]int), diff --git a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go index c79d23bbd..3b906e8e4 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go +++ b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go @@ -72,7 +72,7 @@ func (k Keeper) MarkVulnerableRollapps(ctx sdk.Context, drsVersions []string) (i _, vulnerable := vulnerableVersions[bd.DrsVersion] if vulnerable { - err := k.HardForkObsoleteDRSVersion(ctx, rollapp.RollappId) + err := k.HardForkToLatest(ctx, rollapp.RollappId) if err != nil { logger.With("rollapp_id", rollapp.RollappId).Error("mark rollapp as vulnerable", "error", err) } diff --git a/x/rollapp/keeper/msg_server_update_state.go b/x/rollapp/keeper/msg_server_update_state.go index 77e1fa2e8..166ec8fa0 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -96,7 +96,7 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) // Rollapp is using a vulnerable DRS version, hard fork it // we must return non-error if we want the changes to be saved if k.IsStateUpdateVulnerable(ctx, stateInfo) { - err := k.HardForkObsoleteDRSVersion(ctx, msg.RollappId) + err := k.HardForkToLatest(ctx, msg.RollappId) if err != nil { return nil, fmt.Errorf("mark rollapp vulnerable: %w", err) } 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/proposal_handler.go b/x/rollapp/proposal_handler.go deleted file mode 100644 index ef9290199..000000000 --- a/x/rollapp/proposal_handler.go +++ /dev/null @@ -1,35 +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" -) - -// FIXME: refactor the proposal handler to support different types of proposals - -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 { - // FIXME: jail the sequencer - - err := k.HardFork(ctx, p.RollappId, p.FraudelentHeight) - if err != nil { - return err - } - return nil -} diff --git a/x/rollapp/types/codec.go b/x/rollapp/types/codec.go index 47b7c57d1..a94700c6c 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,6 +16,7 @@ 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(&MsgRollappFraudProposal{}, "rollapp/RollappFraudProposal", nil) } func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { @@ -29,8 +28,8 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { &MsgAddApp{}, &MsgUpdateApp{}, &MsgRemoveApp{}, + &MsgRollappFraudProposal{}, ) - registry.RegisterImplementations((*govtypes.Content)(nil), &SubmitFraudProposal{}) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } diff --git a/x/rollapp/types/expected_keepers.go b/x/rollapp/types/expected_keepers.go index 5286cb3d1..b43678e52 100644 --- a/x/rollapp/types/expected_keepers.go +++ b/x/rollapp/types/expected_keepers.go @@ -21,6 +21,7 @@ type ChannelKeeper interface { type SequencerKeeper interface { SlashLiveness(ctx sdk.Context, rollappID string) error JailLiveness(ctx sdk.Context, rollappID string) error + JailByAddr(ctx sdk.Context, seqAddr string) error } // BankKeeper defines the expected interface needed to retrieve account balances. diff --git a/x/rollapp/types/fraud_proposal.pb.go b/x/rollapp/types/fraud_proposal.pb.go new file mode 100644 index 000000000..39e4a467a --- /dev/null +++ b/x/rollapp/types/fraud_proposal.pb.go @@ -0,0 +1,549 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: dymensionxyz/dymension/rollapp/fraud_proposal.proto + +package types + +import ( + fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" + _ "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 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"` + // hard fork required? + HardFork bool `protobuf:"varint,5,opt,name=hard_fork,json=hardFork,proto3" json:"hard_fork,omitempty"` + // sequencer address to jail. optional + SlashSequencerAddress string `protobuf:"bytes,6,opt,name=slash_sequencer_address,json=slashSequencerAddress,proto3" json:"slash_sequencer_address,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) GetHardFork() bool { + if m != nil { + return m.HardFork + } + return false +} + +func (m *MsgRollappFraudProposal) GetSlashSequencerAddress() string { + if m != nil { + return m.SlashSequencerAddress + } + return "" +} + +func init() { + proto.RegisterType((*MsgRollappFraudProposal)(nil), "dymensionxyz.dymension.rollapp.MsgRollappFraudProposal") +} + +func init() { + proto.RegisterFile("dymensionxyz/dymension/rollapp/fraud_proposal.proto", fileDescriptor_120f0332aea0a45b) +} + +var fileDescriptor_120f0332aea0a45b = []byte{ + // 345 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x31, 0x4f, 0xc2, 0x40, + 0x14, 0xc7, 0x29, 0x22, 0x81, 0xd3, 0xa8, 0xb9, 0x68, 0x68, 0x50, 0x2f, 0xe8, 0x84, 0x0e, 0xbd, + 0x18, 0x8c, 0x83, 0x9b, 0x0e, 0x44, 0x07, 0x8d, 0xa9, 0x9b, 0x4b, 0x73, 0x70, 0x47, 0xdb, 0xd0, + 0xf2, 0xea, 0x5d, 0x4b, 0xa8, 0xa3, 0x9b, 0x9b, 0x1f, 0xc5, 0x8f, 0xe1, 0xc8, 0xe8, 0x68, 0x60, + 0xf0, 0x6b, 0x98, 0x5e, 0x0b, 0xb8, 0x38, 0xb5, 0xef, 0xf7, 0x7f, 0xff, 0xfc, 0xdf, 0xbb, 0x87, + 0x3a, 0x3c, 0x0d, 0xc5, 0x48, 0xf9, 0x30, 0x9a, 0xa4, 0x2f, 0x74, 0x59, 0x50, 0x09, 0x41, 0xc0, + 0xa2, 0x88, 0x0e, 0x24, 0x4b, 0xb8, 0x13, 0x49, 0x88, 0x40, 0xb1, 0xc0, 0x8a, 0x24, 0xc4, 0x80, + 0xc9, 0x5f, 0x93, 0xb5, 0x2c, 0xac, 0xc2, 0xd4, 0xdc, 0x75, 0xc1, 0x05, 0xdd, 0x4a, 0xb3, 0xbf, + 0xdc, 0xd5, 0x6c, 0xf4, 0x41, 0x85, 0xa0, 0x68, 0xa8, 0x5c, 0x3a, 0x3e, 0xcb, 0x3e, 0xb9, 0x70, + 0xfc, 0x56, 0x46, 0x8d, 0x3b, 0xe5, 0xda, 0xb9, 0xbb, 0x9b, 0x25, 0x3e, 0x14, 0x81, 0xf8, 0x00, + 0xd5, 0x59, 0x12, 0x7b, 0x20, 0xfd, 0x38, 0x35, 0x8d, 0x96, 0xd1, 0xae, 0xdb, 0x2b, 0x80, 0x0f, + 0x11, 0x2a, 0x32, 0x1d, 0x9f, 0x9b, 0xe5, 0x5c, 0x2e, 0xc8, 0x2d, 0xc7, 0x27, 0x68, 0x67, 0x21, + 0x4b, 0x31, 0xf6, 0xb3, 0x19, 0xcd, 0xb5, 0x96, 0xd1, 0xae, 0xd8, 0xdb, 0x05, 0xb7, 0x0b, 0x8c, + 0x8f, 0xd0, 0x66, 0xbe, 0xaa, 0x27, 0x7c, 0xd7, 0x8b, 0xcd, 0x8a, 0x6e, 0xdb, 0xd0, 0xec, 0x46, + 0x23, 0xbc, 0x8f, 0xea, 0x1e, 0x93, 0xdc, 0x19, 0x80, 0x1c, 0x9a, 0xeb, 0x2d, 0xa3, 0x5d, 0xb3, + 0x6b, 0x19, 0xe8, 0x82, 0x1c, 0xe2, 0x0b, 0xd4, 0x50, 0x01, 0x53, 0x9e, 0xa3, 0xc4, 0x73, 0x22, + 0x46, 0x7d, 0x21, 0x1d, 0xc6, 0xb9, 0x14, 0x4a, 0x99, 0x55, 0x3d, 0xd6, 0x9e, 0x96, 0x1f, 0x17, + 0xea, 0x55, 0x2e, 0x5e, 0x6e, 0xbd, 0xfe, 0x7c, 0x9c, 0xae, 0x36, 0xba, 0xbe, 0xff, 0x9c, 0x11, + 0x63, 0x3a, 0x23, 0xc6, 0xf7, 0x8c, 0x18, 0xef, 0x73, 0x52, 0x9a, 0xce, 0x49, 0xe9, 0x6b, 0x4e, + 0x4a, 0x4f, 0xe7, 0xae, 0x1f, 0x7b, 0x49, 0xcf, 0xea, 0x43, 0x48, 0xff, 0x39, 0xda, 0xb8, 0x43, + 0x27, 0xcb, 0xcb, 0xc5, 0x69, 0x24, 0x54, 0xaf, 0xaa, 0x9f, 0xb8, 0xf3, 0x1b, 0x00, 0x00, 0xff, + 0xff, 0x04, 0x9f, 0x23, 0x1a, 0xe8, 0x01, 0x00, 0x00, +} + +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.SlashSequencerAddress) > 0 { + i -= len(m.SlashSequencerAddress) + copy(dAtA[i:], m.SlashSequencerAddress) + i = encodeVarintFraudProposal(dAtA, i, uint64(len(m.SlashSequencerAddress))) + i-- + dAtA[i] = 0x32 + } + if m.HardFork { + i-- + if m.HardFork { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x28 + } + 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 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)) + } + if m.HardFork { + n += 2 + } + l = len(m.SlashSequencerAddress) + if l > 0 { + n += 1 + l + sovFraudProposal(uint64(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 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field HardFork", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowFraudProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.HardFork = bool(v != 0) + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SlashSequencerAddress", 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.SlashSequencerAddress = 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 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/hooks.go b/x/rollapp/types/hooks.go index 2f247eac6..220c6f844 100644 --- a/x/rollapp/types/hooks.go +++ b/x/rollapp/types/hooks.go @@ -18,7 +18,6 @@ type RollappHooks interface { AfterTransfersEnabled(ctx sdk.Context, rollappID, rollappIBCDenom string) error OnHardFork(ctx sdk.Context, rollappID string, height uint64) error - // OnHardFork(ctx, rollappID string, newValidHeight uint64, revisionNumber uint64) error } var _ RollappHooks = MultiRollappHooks{} diff --git a/x/rollapp/types/message_fraud_proposal.go b/x/rollapp/types/message_fraud_proposal.go new file mode 100644 index 000000000..14794f6be --- /dev/null +++ b/x/rollapp/types/message_fraud_proposal.go @@ -0,0 +1,34 @@ +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, + ) + } + + return nil +} + +// 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/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/state_info.go b/x/rollapp/types/state_info.go index b724eb545..8f1b23486 100644 --- a/x/rollapp/types/state_info.go +++ b/x/rollapp/types/state_info.go @@ -44,7 +44,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/sequencer/keeper/slashing.go b/x/sequencer/keeper/slashing.go index 3e2dc1206..35028f511 100644 --- a/x/sequencer/keeper/slashing.go +++ b/x/sequencer/keeper/slashing.go @@ -90,3 +90,20 @@ func (k Keeper) Jail(ctx sdk.Context, seq types.Sequencer) error { return nil } + +// Jail sets the sequencer status to Jailed and unbonds the sequencer +func (k Keeper) JailByAddr(ctx sdk.Context, seqAddr string) error { + err := k.unbondSequencerAndJail(ctx, seqAddr) + if err != nil { + return errorsmod.Wrap(err, "unbond and jail") + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeJailed, + sdk.NewAttribute(types.AttributeKeySequencer, seqAddr), + ), + ) + + return nil +} From 209f91e039d4d4587ce23dde530b7da375797861 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Sun, 3 Nov 2024 10:07:59 +0200 Subject: [PATCH 16/68] feat(hard_fork): revision start height (#1373) --- .../dymension/rollapp/rollapp.proto | 1 + x/rollapp/keeper/hard_fork.go | 16 ++- x/rollapp/types/rollapp.go | 3 +- x/rollapp/types/rollapp.pb.go | 136 +++++++++++------- 4 files changed, 99 insertions(+), 57 deletions(-) diff --git a/proto/dymensionxyz/dymension/rollapp/rollapp.proto b/proto/dymensionxyz/dymension/rollapp/rollapp.proto index 5529e9e4f..ae019f241 100644 --- a/proto/dymensionxyz/dymension/rollapp/rollapp.proto +++ b/proto/dymensionxyz/dymension/rollapp/rollapp.proto @@ -78,6 +78,7 @@ message Rollapp { // The revision number of the rollapp. starts always with 0 revision uint64 revision_number = 19; + uint64 revision_start_height = 20; } // Rollapp summary is a compact representation of Rollapp diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index 2a7af1e07..e92943254 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -27,14 +27,14 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) } */ - err := k.RevertPendingStates(ctx, rollappID, fraudHeight) + lastCommittedHeight, err := k.RevertPendingStates(ctx, rollappID, fraudHeight) if err != nil { return errorsmod.Wrap(err, "revert pending states") } // update revision number rollapp.RevisionNumber += 1 - // FIXME: set liveness height + rollapp.RevisionStartHeight = lastCommittedHeight + 1 k.SetRollapp(ctx, rollapp) // handle the sequencers, clean delayed packets, handle light client @@ -55,19 +55,21 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) } // removes state updates until the one specified and included -func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeight uint64) error { +// returns the latest height of the state info +func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeight uint64) (uint64, error) { // find the affected state info index // skip if not found (fraud height is not committed yet) stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, fraudHeight) if errorsmod.IsOf(err, gerrc.ErrNotFound) { - return nil + sinfo, _ := k.GetLatestStateInfo(ctx, rollappID) + return sinfo.GetLatestHeight(), nil } else if err != nil { - return err + return 0, 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) + return 0, errorsmod.Wrapf(types.ErrDisputeAlreadyFinalized, "state info for height %d is already finalized", fraudHeight) } lastStateIdxToKeep := stateInfo.StateInfoIndex.Index @@ -133,7 +135,7 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig ctx.Logger().Info(fmt.Sprintf("Reverted state updates for rollapp: %s, count: %d", rollappID, revertedStatesCount)) - return nil + return fraudHeight - 1, nil } // TruncStateInfo truncates the state info to the last valid block before the fraud height. diff --git a/x/rollapp/types/rollapp.go b/x/rollapp/types/rollapp.go index d0001ed08..21916cfb5 100644 --- a/x/rollapp/types/rollapp.go +++ b/x/rollapp/types/rollapp.go @@ -46,7 +46,8 @@ func NewRollapp( GenesisState: RollappGenesisState{ TransfersEnabled: transfersEnabled, }, - RevisionNumber: 0, + RevisionNumber: 0, + RevisionStartHeight: 0, } } diff --git a/x/rollapp/types/rollapp.pb.go b/x/rollapp/types/rollapp.pb.go index 47fe08d19..32db4bb9b 100644 --- a/x/rollapp/types/rollapp.pb.go +++ b/x/rollapp/types/rollapp.pb.go @@ -148,7 +148,8 @@ type Rollapp struct { // 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"` + RevisionNumber uint64 `protobuf:"varint,19,opt,name=revision_number,json=revisionNumber,proto3" json:"revision_number,omitempty"` + RevisionStartHeight uint64 `protobuf:"varint,20,opt,name=revision_start_height,json=revisionStartHeight,proto3" json:"revision_start_height,omitempty"` } func (m *Rollapp) Reset() { *m = Rollapp{} } @@ -275,6 +276,13 @@ func (m *Rollapp) GetRevisionNumber() uint64 { 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,54 +376,55 @@ func init() { } var fileDescriptor_d4ef2bec3aea5528 = []byte{ - // 742 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x54, 0xcd, 0x4e, 0xdb, 0x4a, - 0x14, 0x8e, 0x13, 0x93, 0x38, 0x93, 0x90, 0x98, 0x01, 0x74, 0x7d, 0xa3, 0x4b, 0x88, 0xb2, 0xb9, - 0x91, 0xe0, 0xda, 0xe2, 0x47, 0xba, 0xeb, 0x22, 0x51, 0x48, 0xda, 0xb0, 0x70, 0x80, 0x4a, 0x2c, - 0x6a, 0x39, 0xf1, 0x89, 0x33, 0x92, 0x3d, 0x76, 0x6d, 0x27, 0x25, 0x3c, 0x05, 0xea, 0x53, 0xb1, - 0x44, 0x5d, 0x75, 0xd5, 0x56, 0xf0, 0x22, 0x95, 0xc7, 0xe3, 0x90, 0x16, 0x68, 0x50, 0x57, 0xe3, - 0x73, 0xbe, 0xf3, 0x7d, 0xe7, 0x67, 0xe6, 0x18, 0x6d, 0x5b, 0x53, 0x17, 0x68, 0x48, 0x3c, 0x7a, - 0x39, 0xbd, 0xd2, 0x66, 0x86, 0x16, 0x78, 0x8e, 0x63, 0xfa, 0x7e, 0x7a, 0xaa, 0x7e, 0xe0, 0x45, - 0x1e, 0xae, 0xcf, 0x47, 0xab, 0x33, 0x43, 0xe5, 0x51, 0xb5, 0x35, 0xdb, 0xb3, 0x3d, 0x16, 0xaa, - 0xc5, 0x5f, 0x09, 0xab, 0xb6, 0x69, 0x7b, 0x9e, 0xed, 0x80, 0xc6, 0xac, 0xfe, 0x78, 0xa8, 0x45, - 0xc4, 0x85, 0x30, 0x32, 0x5d, 0x2e, 0x5b, 0xfb, 0x6b, 0xe0, 0x85, 0xae, 0x17, 0x6a, 0x6e, 0x68, - 0x6b, 0x93, 0x9d, 0xf8, 0xe0, 0x80, 0xb6, 0xa0, 0xba, 0x30, 0x32, 0x23, 0x30, 0x08, 0x1d, 0xa6, - 0xa9, 0xfe, 0x5b, 0x40, 0x70, 0x21, 0x32, 0x2d, 0x33, 0x32, 0x79, 0xf8, 0xce, 0x82, 0x70, 0x1b, - 0x28, 0x84, 0x24, 0x9c, 0xcb, 0xd0, 0x3c, 0x46, 0xab, 0x7a, 0x82, 0x1e, 0x25, 0x60, 0x2f, 0xae, - 0x01, 0x6f, 0xa1, 0x95, 0x28, 0x30, 0x69, 0x38, 0x84, 0x20, 0x34, 0x80, 0x9a, 0x7d, 0x07, 0x2c, - 0x25, 0xdb, 0x10, 0x5a, 0x92, 0x2e, 0xcf, 0x80, 0xc3, 0xc4, 0xdf, 0x11, 0x25, 0x41, 0xce, 0x36, - 0x3f, 0xe5, 0x51, 0x81, 0x4b, 0xe1, 0x0d, 0x84, 0x78, 0x4e, 0x83, 0x58, 0x8a, 0xd0, 0x10, 0x5a, - 0x45, 0xbd, 0xc8, 0x3d, 0x6d, 0x0b, 0xaf, 0xa1, 0x25, 0xef, 0x23, 0x85, 0x80, 0x29, 0x16, 0xf5, - 0xc4, 0xc0, 0xef, 0xd1, 0x72, 0x5a, 0x20, 0x1b, 0x84, 0x52, 0x68, 0x08, 0xad, 0xd2, 0xee, 0x9e, - 0xfa, 0xfb, 0x5b, 0x52, 0x9f, 0xa8, 0xff, 0x40, 0xbc, 0xf9, 0xba, 0x99, 0xd1, 0xcb, 0xf6, 0x7c, - 0x4f, 0x1b, 0x08, 0x0d, 0x46, 0x26, 0xa5, 0xe0, 0xc4, 0x45, 0x49, 0x49, 0x51, 0xdc, 0xd3, 0xb6, - 0xf0, 0x1b, 0x24, 0xa5, 0xe3, 0x54, 0x4a, 0x2c, 0xb3, 0xf6, 0xc2, 0xcc, 0x5d, 0x4e, 0xd3, 0x67, - 0x02, 0xf8, 0x14, 0x95, 0xe7, 0x87, 0xad, 0x94, 0x99, 0xe0, 0xd6, 0x22, 0x41, 0xde, 0x43, 0x9b, - 0x0e, 0x3d, 0xde, 0x42, 0xc9, 0x7e, 0x70, 0xc5, 0xb7, 0x42, 0x28, 0x89, 0x88, 0xe9, 0x18, 0x21, - 0x7c, 0x18, 0x03, 0x1d, 0x40, 0xa0, 0x2c, 0xb3, 0x46, 0x64, 0x0e, 0xf4, 0x52, 0x3f, 0x3e, 0x42, - 0x85, 0x89, 0x6b, 0x44, 0x53, 0x1f, 0x94, 0x4a, 0x43, 0x68, 0x55, 0x76, 0xd5, 0x17, 0xb6, 0xa3, - 0x9e, 0x77, 0x4f, 0xa7, 0x3e, 0xe8, 0xf9, 0x89, 0x1b, 0x9f, 0xb8, 0x86, 0x24, 0xc7, 0x1c, 0xd3, - 0xc1, 0x08, 0x2c, 0xa5, 0xca, 0x9e, 0xc0, 0xcc, 0xc6, 0xc7, 0xa8, 0xea, 0x07, 0x60, 0x24, 0xb6, - 0x11, 0x2f, 0x82, 0x22, 0xb3, 0x56, 0x6b, 0x6a, 0xb2, 0x25, 0x6a, 0xba, 0x25, 0xea, 0x69, 0xba, - 0x25, 0x07, 0xe2, 0xf5, 0xb7, 0x4d, 0x41, 0x5f, 0xf6, 0x03, 0x78, 0xcb, 0x78, 0x31, 0x82, 0x77, - 0xd1, 0xba, 0x43, 0x26, 0x71, 0xb3, 0xa1, 0x01, 0x13, 0xa0, 0x91, 0x31, 0x02, 0x62, 0x8f, 0x22, - 0x65, 0xa5, 0x21, 0xb4, 0x72, 0xfa, 0x6a, 0x0a, 0x1e, 0xc6, 0xd8, 0x31, 0x83, 0xf0, 0xff, 0x48, - 0x71, 0xcc, 0x30, 0x4a, 0x9e, 0x8b, 0x31, 0xf6, 0xad, 0xf8, 0xe0, 0x34, 0xcc, 0x68, 0xeb, 0x31, - 0xce, 0xae, 0xff, 0x8c, 0xa1, 0x9c, 0xf8, 0x2f, 0xaa, 0x06, 0x30, 0x21, 0x71, 0xf7, 0x06, 0x1d, - 0xbb, 0x7d, 0x08, 0x94, 0xd5, 0x86, 0xd0, 0x12, 0xf5, 0x4a, 0xea, 0x3e, 0x61, 0xde, 0xe6, 0x36, - 0xca, 0x27, 0xd3, 0xc0, 0x55, 0x54, 0x3a, 0xa3, 0xa1, 0x0f, 0x03, 0x32, 0x24, 0x60, 0xc9, 0x19, - 0x5c, 0x40, 0xb9, 0xc3, 0xf3, 0xae, 0x2c, 0x60, 0x09, 0x89, 0xef, 0x5e, 0xf5, 0xba, 0x72, 0xb6, - 0x23, 0x4a, 0x39, 0xb9, 0xd0, 0x11, 0xa5, 0xa2, 0x8c, 0x3a, 0xa2, 0x84, 0xe4, 0x52, 0xf3, 0x73, - 0x16, 0x55, 0xf8, 0x58, 0x7b, 0x63, 0xd7, 0x35, 0x83, 0x29, 0xfe, 0x07, 0x3d, 0x6c, 0xc2, 0xe3, - 0xd5, 0xb8, 0x40, 0xb2, 0x63, 0x46, 0xc0, 0x8b, 0x6e, 0x53, 0x0b, 0x2e, 0xd9, 0x96, 0x94, 0x16, - 0x5f, 0x1f, 0x67, 0x0c, 0x3d, 0xc6, 0xd2, 0x1f, 0xe9, 0x60, 0x07, 0xfd, 0x9d, 0xf8, 0x5e, 0x13, - 0x6a, 0x3a, 0xe4, 0x0a, 0xac, 0xb9, 0x24, 0xb9, 0x3f, 0x4a, 0xf2, 0xbc, 0x20, 0x6e, 0xa2, 0x72, - 0x02, 0x26, 0x33, 0x57, 0x44, 0x36, 0xe0, 0x9f, 0x7c, 0x78, 0x1f, 0xad, 0xff, 0x22, 0xc0, 0x83, - 0x97, 0x58, 0xf0, 0xd3, 0xe0, 0xc1, 0xc9, 0xcd, 0x5d, 0x5d, 0xb8, 0xbd, 0xab, 0x0b, 0xdf, 0xef, - 0xea, 0xc2, 0xf5, 0x7d, 0x3d, 0x73, 0x7b, 0x5f, 0xcf, 0x7c, 0xb9, 0xaf, 0x67, 0x2e, 0xf6, 0x6d, - 0x12, 0x8d, 0xc6, 0x7d, 0x75, 0xe0, 0xb9, 0xcf, 0xfd, 0x6b, 0x27, 0x7b, 0xda, 0xe5, 0xec, 0x87, - 0x18, 0x6f, 0x47, 0xd8, 0xcf, 0xb3, 0x37, 0xba, 0xf7, 0x23, 0x00, 0x00, 0xff, 0xff, 0xe9, 0x06, - 0x28, 0xa6, 0x3d, 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) { @@ -471,6 +480,13 @@ 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-- @@ -718,6 +734,9 @@ func (m *Rollapp) Size() (n int) { if m.RevisionNumber != 0 { n += 2 + sovRollapp(uint64(m.RevisionNumber)) } + if m.RevisionStartHeight != 0 { + n += 2 + sovRollapp(uint64(m.RevisionStartHeight)) + } return n } @@ -1215,6 +1234,25 @@ func (m *Rollapp) Unmarshal(dAtA []byte) error { 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:]) From 8e943b81a536976823f24986cff5f417d0814946 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 3 Nov 2024 11:11:13 +0200 Subject: [PATCH 17/68] cleanup --- proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto | 2 +- proto/dymensionxyz/dymension/rollapp/rollapp.proto | 4 ++-- x/delayedack/keeper/fraud.go | 1 + x/lightclient/ante/ibc_msgs_test.go | 2 +- x/rollapp/keeper/msg_server_update_state.go | 2 +- x/rollapp/types/rollapp.pb.go | 3 ++- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto index 95b1fc8be..819bb3edd 100644 --- a/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto +++ b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto @@ -29,4 +29,4 @@ message MsgRollappFraudProposal { string slash_sequencer_address = 6; } -// TODO: add slashing only proposal? \ No newline at end of file +// TODO: add slashing only proposal (e.g for double signing) \ No newline at end of file diff --git a/proto/dymensionxyz/dymension/rollapp/rollapp.proto b/proto/dymensionxyz/dymension/rollapp/rollapp.proto index ae019f241..37c245e84 100644 --- a/proto/dymensionxyz/dymension/rollapp/rollapp.proto +++ b/proto/dymensionxyz/dymension/rollapp/rollapp.proto @@ -42,8 +42,7 @@ message Rollapp { // channel_id will be set to the canonical IBC channel of the rollapp. string channel_id = 8; - reserved 9; - reserved 10; + reserved 9,10; // metadata is the rollapp metadata RollappMetadata metadata = 11; @@ -78,6 +77,7 @@ message Rollapp { // 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; } diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 790fcb54e..6b063dddf 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -28,6 +28,7 @@ func (k Keeper) HandleHardFork(ctx sdk.Context, rollappID string, height uint64, // refund all pending outgoing packets if rollappPacket.Type == commontypes.RollappPacket_ON_ACK || rollappPacket.Type == commontypes.RollappPacket_ON_TIMEOUT { + // FIXME: #1380 create packet commitments instead // 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 { diff --git a/x/lightclient/ante/ibc_msgs_test.go b/x/lightclient/ante/ibc_msgs_test.go index fcc1019cf..6eeed99d6 100644 --- a/x/lightclient/ante/ibc_msgs_test.go +++ b/x/lightclient/ante/ibc_msgs_test.go @@ -19,7 +19,7 @@ type MockRollappKeeper struct { // GetLatestStateInfo implements types.RollappKeeperExpected. func (m *MockRollappKeeper) GetLatestStateInfo(ctx sdk.Context, rollappId string) (rollapptypes.StateInfo, bool) { - panic("unimplemented") + return rollapptypes.StateInfo{}, false } func NewMockRollappKeeper(rollapps map[string]rollapptypes.Rollapp, stateInfos map[string]map[uint64]rollapptypes.StateInfo) *MockRollappKeeper { diff --git a/x/rollapp/keeper/msg_server_update_state.go b/x/rollapp/keeper/msg_server_update_state.go index 166ec8fa0..fc61a59d7 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -94,7 +94,6 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) // verify the DRS version is not vulnerable // check only last block descriptor DRS, since if that last is not vulnerable it means the rollapp already upgraded and is not vulnerable anymore // Rollapp is using a vulnerable DRS version, hard fork it - // we must return non-error if we want the changes to be saved if k.IsStateUpdateVulnerable(ctx, stateInfo) { err := k.HardForkToLatest(ctx, msg.RollappId) if err != nil { @@ -103,6 +102,7 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) k.Logger(ctx).With("rollapp_id", msg.RollappId, "drs_version", stateInfo.GetLatestBlockDescriptor().DrsVersion). Info("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 } diff --git a/x/rollapp/types/rollapp.pb.go b/x/rollapp/types/rollapp.pb.go index 32db4bb9b..663aae685 100644 --- a/x/rollapp/types/rollapp.pb.go +++ b/x/rollapp/types/rollapp.pb.go @@ -148,7 +148,8 @@ type Rollapp struct { // 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"` + 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"` } From 9f298af25dd7a161386dac5219701b4a2f29b9fb Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 3 Nov 2024 11:58:14 +0200 Subject: [PATCH 18/68] lightClient doesn't trigger hard fork --- x/lightclient/keeper/canonical_client.go | 2 +- x/lightclient/keeper/hook_listener.go | 15 +----------- x/lightclient/keeper/rollback.go | 31 ++++++++++-------------- 3 files changed, 15 insertions(+), 33 deletions(-) diff --git a/x/lightclient/keeper/canonical_client.go b/x/lightclient/keeper/canonical_client.go index d4b2f743b..c30978bf7 100644 --- a/x/lightclient/keeper/canonical_client.go +++ b/x/lightclient/keeper/canonical_client.go @@ -83,7 +83,7 @@ func (k Keeper) validClient(ctx sdk.Context, clientID string, cs exported.Client return errorsmod.Wrap(err, "params") } - // FIXME: can be refactored using iterators + // FIXME: No need to get all consensus states. should iterate over the consensus states in reverse order res, err := k.ibcClientKeeper.ConsensusStateHeights(ctx, &ibcclienttypes.QueryConsensusStateHeightsRequest{ ClientId: clientID, Pagination: &query.PageRequest{Limit: maxHeight}, diff --git a/x/lightclient/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index 5160ac65f..40a04f83c 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -95,20 +95,7 @@ func (hook rollappHook) checkStateForHeight(ctx sdk.Context, rollappId string, b } err := types.CheckCompatibility(*tmConsensusState, rollappState) if err != nil { - // If the state is not compatible, - // Take this state update as source of truth over the IBC update - // Punish the block proposer of the IBC signed header - sequencerAddress, err := hook.k.GetSequencerFromValHash(ctx, rollappId, blockValHash) - if err != nil { - return err - } - // FIXME: punish the sequencer - hook.k.sequencerKeeper.JailSequencerOnFraud(ctx, sequencerAddress) - - err = hook.k.rollappKeeper.HardFork(ctx, rollappId, bd.GetHeight()) - if err != nil { - return err - } + return err } hook.k.RemoveConsensusStateValHash(ctx, canonicalClient, bd.GetHeight()) return nil diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index 187664048..63a81ddda 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -11,12 +11,12 @@ import ( ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ) -func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappId string, height uint64) error { - hook.k.RollbackCanonicalClient(ctx, rollappId, height) +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappId string, fraudHeight uint64) error { + hook.k.RollbackCanonicalClient(ctx, rollappId, fraudHeight) return nil } -func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, height uint64) { +func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraudHeight uint64) { client, found := k.GetCanonicalClient(ctx, rollappId) if !found { k.Logger(ctx).Error("Canonical client not found", "rollappId", rollappId) @@ -25,9 +25,10 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, heigh cs := k.ibcClientKeeper.ClientStore(ctx, client) // iterate over all consensus states and metadata in the client store + // FIXME: iterate descending ibctm.IterateConsensusStateAscending(cs, func(h exported.Height) bool { // if the height is lower than the target height, continue - if h.GetRevisionHeight() < height { + if h.GetRevisionHeight() < fraudHeight { return false } @@ -36,7 +37,7 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, heigh deleteConsensusMetadata(cs, h) // clean the optimistic updates valset - k.RemoveConsensusStateValHash(ctx, client, height) + k.RemoveConsensusStateValHash(ctx, client, h.GetRevisionHeight()) return false }) @@ -45,7 +46,7 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, heigh // freeze the client // it will be released after the hardfork is resolved (on the next state update) - k.freezeClient(cs, height) + k.freezeClient(cs, fraudHeight) } // set latest IBC consensus state nextValHash to the current proposing sequencer. @@ -57,11 +58,13 @@ func (k Keeper) ResolveHardFork(ctx sdk.Context, rollappID string) { height := stateinfo.GetLatestHeight() bd := stateinfo.GetLatestBlockDescriptor() + // get the valHash of this sequencer + proposer, _ := k.sequencerKeeper.GetSequencer(ctx, stateinfo.Sequencer) + valHash, _ := proposer.GetDymintPubKeyHash() + // unfreeze the client and set the latest height k.resetClientToValidState(clientStore, height) - // add consensus states based on the block descriptors - valHash := k.getValidatorHashForHeight(ctx, rollappID, height) cs := ibctm.ConsensusState{ Timestamp: bd.Timestamp, Root: commitmenttypes.NewMerkleRoot(bd.StateRoot), @@ -76,7 +79,7 @@ func (k Keeper) ResolveHardFork(ctx sdk.Context, rollappID string) { // 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) + tmClientState, _ := c.(*ibctm.ClientState) // freeze the client tmClientState.FrozenHeight = clienttypes.NewHeight(1, height) @@ -86,7 +89,7 @@ func (k Keeper) freezeClient(clientStore sdk.KVStore, height uint64) { // 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) + tmClientState, _ := c.(*ibctm.ClientState) // unfreeze the client and set the latest height tmClientState.FrozenHeight = clienttypes.ZeroHeight() @@ -95,14 +98,6 @@ func (k Keeper) resetClientToValidState(clientStore sdk.KVStore, height uint64) setClientState(clientStore, k.cdc, tmClientState) } -// FIXME: assure there's no case with no proposer -func (k Keeper) getValidatorHashForHeight(ctx sdk.Context, rollappId string, height uint64) []byte { - proposer, _ := k.sequencerKeeper.GetProposer(ctx, rollappId) - proposerHash, _ := proposer.GetDymintPubKeyHash() - - return proposerHash -} - func (k Keeper) setHardForkInProgress(ctx sdk.Context, rollappID string) { ctx.KVStore(k.storeKey).Set(types.HardForkKey(rollappID), []byte{0x01}) } From 67ec46ac34407ec33fcfcc84ec4eeb6529186fe5 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 3 Nov 2024 12:10:08 +0200 Subject: [PATCH 19/68] clearing consesnsus state in descending order --- x/lightclient/keeper/client_store.go | 31 +++++++------------- x/lightclient/keeper/keeper.go | 14 ++++++++++ x/lightclient/keeper/rollback.go | 42 ++++++++++++++++++---------- 3 files changed, 52 insertions(+), 35 deletions(-) diff --git a/x/lightclient/keeper/client_store.go b/x/lightclient/keeper/client_store.go index 70f45c7a2..0fc1f760a 100644 --- a/x/lightclient/keeper/client_store.go +++ b/x/lightclient/keeper/client_store.go @@ -4,7 +4,6 @@ import ( "encoding/binary" "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/prefix" 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" @@ -12,6 +11,9 @@ import ( 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()) @@ -35,26 +37,6 @@ func setConsensusState(clientStore sdk.KVStore, cdc codec.BinaryCodec, height ex clientStore.Set(key, val) } -func GetPreviousConsensusStateHeight(clientStore sdk.KVStore, cdc codec.BinaryCodec, height exported.Height) (exported.Height, bool) { - iterateStore := prefix.NewStore(clientStore, []byte(ibctm.KeyIterateConsensusStatePrefix)) - iterator := iterateStore.ReverseIterator(nil, bigEndianHeightBytes(height)) - defer iterator.Close() - - if !iterator.Valid() { - return nil, false - } - - prevHeight := ibctm.GetHeightFromIterationKey(iterator.Key()) - return prevHeight, true -} - -func bigEndianHeightBytes(height exported.Height) []byte { - heightBytes := make([]byte, 16) - binary.BigEndian.PutUint64(heightBytes, height.GetRevisionNumber()) - binary.BigEndian.PutUint64(heightBytes[8:], height.GetRevisionHeight()) - return heightBytes -} - // deleteConsensusMetadata deletes the metadata stored for a particular consensus state. func deleteConsensusMetadata(clientStore sdk.KVStore, height exported.Height) { deleteProcessedTime(clientStore, height) @@ -85,3 +67,10 @@ func deleteIterationKey(clientStore sdk.KVStore, height exported.Height) { key := ibctm.IterationKey(height) clientStore.Delete(key) } + +func bigEndianHeightBytes(height exported.Height) []byte { + heightBytes := make([]byte, 16) + binary.BigEndian.PutUint64(heightBytes, height.GetRevisionNumber()) + binary.BigEndian.PutUint64(heightBytes[8:], height.GetRevisionHeight()) + return heightBytes +} diff --git a/x/lightclient/keeper/keeper.go b/x/lightclient/keeper/keeper.go index 8d8e704c4..aa47c5388 100644 --- a/x/lightclient/keeper/keeper.go +++ b/x/lightclient/keeper/keeper.go @@ -138,3 +138,17 @@ func (k Keeper) ExpectedClientState(goCtx context.Context, req *types.QueryExpec } 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)) +} diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index 63a81ddda..351469cd4 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -1,9 +1,10 @@ package keeper import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" - "github.com/dymensionxyz/dymension/v3/x/lightclient/types" clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" @@ -25,11 +26,10 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraud cs := k.ibcClientKeeper.ClientStore(ctx, client) // iterate over all consensus states and metadata in the client store - // FIXME: iterate descending - ibctm.IterateConsensusStateAscending(cs, func(h exported.Height) bool { - // if the height is lower than the target height, continue + IterateConsensusStateDescending(cs, func(h exported.Height) bool { + // iterate until we pass the fraud height if h.GetRevisionHeight() < fraudHeight { - return false + return true } // delete consensus state and metadata @@ -98,16 +98,30 @@ func (k Keeper) resetClientToValidState(clientStore sdk.KVStore, height uint64) setClientState(clientStore, k.cdc, tmClientState) } -func (k Keeper) setHardForkInProgress(ctx sdk.Context, rollappID string) { - ctx.KVStore(k.storeKey).Set(types.HardForkKey(rollappID), []byte{0x01}) -} +func GetPreviousConsensusStateHeight(clientStore sdk.KVStore, cdc codec.BinaryCodec, height exported.Height) (exported.Height, bool) { + iterateStore := prefix.NewStore(clientStore, []byte(ibctm.KeyIterateConsensusStatePrefix)) + iterator := iterateStore.ReverseIterator(nil, bigEndianHeightBytes(height)) + defer iterator.Close() // nolint: errcheck + + if !iterator.Valid() { + return nil, false + } -// remove the hardfork key from the store -func (k Keeper) setHardForkResolved(ctx sdk.Context, rollappID string) { - ctx.KVStore(k.storeKey).Delete(types.HardForkKey(rollappID)) + prevHeight := ibctm.GetHeightFromIterationKey(iterator.Key()) + return prevHeight, true } -// 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)) +// 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 + } + } } From 3fda55ac200e7584200cbc3117a1db4e61ada753 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 3 Nov 2024 12:15:49 +0200 Subject: [PATCH 20/68] fix UT --- ibctesting/light_client_test.go | 8 -------- x/lightclient/keeper/hook_listener_test.go | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/ibctesting/light_client_test.go b/ibctesting/light_client_test.go index 27f8a9ea6..c04d9448a 100644 --- a/ibctesting/light_client_test.go +++ b/ibctesting/light_client_test.go @@ -343,14 +343,6 @@ func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_NotCompat ) _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) s.Error(err) - - // Assert that hard fork was triggered - rollapp, _ := s.hubApp().RollappKeeper.GetRollapp(s.hubCtx(), s.rollappChain().ChainID) - s.Equal(uint64(1), rollapp.RevisionNumber) - - // The optimistic update valhash should be removed as part of fraud handling - _, found = s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) - s.False(found) } // Test the rollback flow for a light client diff --git a/x/lightclient/keeper/hook_listener_test.go b/x/lightclient/keeper/hook_listener_test.go index 722ccb10a..79bcdf1e2 100644 --- a/x/lightclient/keeper/hook_listener_test.go +++ b/x/lightclient/keeper/hook_listener_test.go @@ -94,7 +94,7 @@ func TestAfterUpdateState(t *testing.T) { }, } }, - expectErr: false, + expectErr: true, }, { name: "state is compatible", From 612a673aabd5e91e975c36fbc12a235ea110779a Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 3 Nov 2024 12:16:16 +0200 Subject: [PATCH 21/68] fraud proposal validates genesis bridge completed --- x/rollapp/keeper/fraud_proposal.go | 5 +++++ x/rollapp/keeper/hard_fork.go | 8 -------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/x/rollapp/keeper/fraud_proposal.go b/x/rollapp/keeper/fraud_proposal.go index 72fd19434..d44739857 100644 --- a/x/rollapp/keeper/fraud_proposal.go +++ b/x/rollapp/keeper/fraud_proposal.go @@ -28,6 +28,11 @@ func (k Keeper) FraudProposalHandler(ctx sdk.Context, msg types.MsgRollappFraudP return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "revision number mismatch") } + // validate the rollapp is past it's genesis bridge phase + if !rollapp.IsTransferEnabled() { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "rollapp is not past genesis bridge phase") + } + // validate the fraud height is already committed sinfo, found := k.GetLatestStateInfo(ctx, msg.RollappId) if !found || sinfo.GetLatestHeight() < msg.FraudHeight { diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index e92943254..ea27e9c4d 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -19,14 +19,6 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) return gerrc.ErrNotFound } - // FIXME: enable later on - /* - // enforce the assumption that genesis transfer is completed before hard fork - if !rollapp.IsTransferEnabled() { - return errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "can't hard fork before transfer is enabled") - } - */ - lastCommittedHeight, err := k.RevertPendingStates(ctx, rollappID, fraudHeight) if err != nil { return errorsmod.Wrap(err, "revert pending states") From 4078e39e772e11ac00d67685ecd9a8b20aacf153 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 3 Nov 2024 12:27:05 +0200 Subject: [PATCH 22/68] validate revision in header.Header.Version.App --- ibctesting/utils_test.go | 3 +++ x/lightclient/ante/ibc_msg_update_client.go | 18 ++++++++++-------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/ibctesting/utils_test.go b/ibctesting/utils_test.go index 484db77bb..064204c78 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" @@ -109,6 +110,8 @@ func (s *utilSuite) rollappMsgServer() rollapptypes.MsgServer { // SetupTest creates a coordinator with 2 test chains. func (s *utilSuite) SetupTest() { + simapp.DefaultAppVersion = 0 + s.coordinator = ibctesting.NewCoordinator(s.T(), 2) // initializes test chains s.coordinator.Chains[rollappChainID()] = s.newTestChainWithSingleValidator(s.T(), s.coordinator, rollappChainID()) } diff --git a/x/lightclient/ante/ibc_msg_update_client.go b/x/lightclient/ante/ibc_msg_update_client.go index 6a232c23a..76dfd6840 100644 --- a/x/lightclient/ante/ibc_msg_update_client.go +++ b/x/lightclient/ante/ibc_msg_update_client.go @@ -45,14 +45,16 @@ func (i IBCMessagesDecorator) HandleMsgUpdateClient(ctx sdk.Context, msg *ibccli return nil } - // FIXME: enable later on - /* - // 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 != i.rollappKeeper.GetRevision(ctx, rollappID) { - return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "client is not compatible with the rollapp") - } - */ + ra, ok := i.rollappKeeper.GetRollapp(ctx, rollappID) + if !ok { + return errorsmod.Wrap(gerrc.ErrInternal, "rollapp not found") + } + + // 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 != ra.RevisionNumber { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "client update revision mismatch") + } // Check if there are existing block descriptors for the given height of client state height := uint64(header.Header.Height) From e57988ad89e801942c02625bcc090afd468be626 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 3 Nov 2024 14:46:04 +0200 Subject: [PATCH 23/68] linter --- testutil/keeper/delayedack.go | 2 -- x/delayedack/keeper/fraud.go | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/testutil/keeper/delayedack.go b/testutil/keeper/delayedack.go index 88789414c..4c69a5d44 100644 --- a/testutil/keeper/delayedack.go +++ b/testutil/keeper/delayedack.go @@ -28,9 +28,7 @@ import ( type ChannelKeeperStub struct{} -// SetPacketReceipt implements types.ChannelKeeper. func (c ChannelKeeperStub) SetPacketReceipt(ctx sdk.Context, portID string, channelID string, sequence uint64) { - return } func (ChannelKeeperStub) LookupModuleByChannel(ctx sdk.Context, portID, channelID string) (string, *capabilitytypes.Capability, error) { diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 6b063dddf..5ab64f4ae 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -41,7 +41,7 @@ func (k Keeper) HandleHardFork(ctx sdk.Context, rollappID string, height uint64, } // delete the packet - k.DeleteRollappPacket(ctx, &rollappPacket) + k.DeleteRollappPacket(ctx, &rollappPacket) // nolint: errcheck logger.Debug("reverted IBC rollapp packet", logContext...) } From 13a56a59f2640c2618d759c520e47e4ec6e49263 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 3 Nov 2024 15:05:12 +0200 Subject: [PATCH 24/68] linter --- x/delayedack/keeper/fraud.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 5ab64f4ae..9067fc337 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -41,7 +41,10 @@ func (k Keeper) HandleHardFork(ctx sdk.Context, rollappID string, height uint64, } // delete the packet - k.DeleteRollappPacket(ctx, &rollappPacket) // nolint: errcheck + err := k.DeleteRollappPacket(ctx, &rollappPacket) + if err != nil { + logger.Error("failed to delete reverted packet", append(logContext, "error", err.Error())...) + } logger.Debug("reverted IBC rollapp packet", logContext...) } From e6122d1fde4ea1d92d7dc6a340bce01e5d48e153 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Sun, 3 Nov 2024 20:19:07 +0200 Subject: [PATCH 25/68] feat(hard_fork): delayed ack should create commitment after rolling back acks (#1383) --- app/keepers/keepers.go | 2 +- ibctesting/delayed_ack_test.go | 112 ++++++++++++++++++++++++- testutil/keeper/delayedack.go | 3 + x/delayedack/keeper/fraud.go | 20 ++--- x/delayedack/keeper/fraud_test.go | 12 +-- x/delayedack/keeper/invariants_test.go | 10 +-- x/delayedack/keeper/keeper.go | 3 + x/delayedack/keeper/rollapp_packet.go | 1 + x/delayedack/rollapp_hooks.go | 13 --- x/delayedack/types/expected_keepers.go | 1 + 10 files changed, 132 insertions(+), 45 deletions(-) delete mode 100644 x/delayedack/rollapp_hooks.go diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 003fdbfd3..1d748073f 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -617,7 +617,7 @@ 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(), diff --git a/ibctesting/delayed_ack_test.go b/ibctesting/delayed_ack_test.go index a6d1d649f..691d55821 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" ) @@ -236,4 +241,109 @@ func (s *delayedAckSuite) TestHubToRollappTimeout() { s.Require().Equal(preSendBalance.Amount, postFinalizeBalance.Amount) } -// FIXME: test refunds due to hard fork + receipt deletion +// 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/testutil/keeper/delayedack.go b/testutil/keeper/delayedack.go index 4c69a5d44..4046647a7 100644 --- a/testutil/keeper/delayedack.go +++ b/testutil/keeper/delayedack.go @@ -28,6 +28,9 @@ 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) { } diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 9067fc337..93fdd38b3 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -4,17 +4,20 @@ import ( "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) HandleHardFork(ctx sdk.Context, rollappID string, height uint64, ibc porttypes.IBCModule) error { +var _ rollapptypes.RollappHooks = &Keeper{} + +func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error { logger := ctx.Logger().With("module", "DelayedAckMiddleware") // Get all the pending packets from fork height inclusive - rollappPendingPackets := k.ListRollappPackets(ctx, types.PendingByRollappIDFromHeight(rollappID, height)) + rollappPendingPackets := k.ListRollappPackets(ctx, types.PendingByRollappIDFromHeight(rollappID, fraudHeight)) // Iterate over all the pending packets and revert them for _, rollappPacket := range rollappPendingPackets { @@ -26,14 +29,11 @@ func (k Keeper) HandleHardFork(ctx sdk.Context, rollappID string, height uint64, "sequence", rollappPacket.Packet.Sequence, } - // refund all pending outgoing packets if rollappPacket.Type == commontypes.RollappPacket_ON_ACK || rollappPacket.Type == commontypes.RollappPacket_ON_TIMEOUT { - // FIXME: #1380 create packet commitments instead - // 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 + commitment := channeltypes.CommitPacket(k.cdc, rollappPacket.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 diff --git a/x/delayedack/keeper/fraud_test.go b/x/delayedack/keeper/fraud_test.go index 7d3f5ec99..43449fc89 100644 --- a/x/delayedack/keeper/fraud_test.go +++ b/x/delayedack/keeper/fraud_test.go @@ -1,22 +1,14 @@ package keeper_test import ( - ibctransfer "github.com/cosmos/ibc-go/v7/modules/apps/transfer" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" - damodule "github.com/dymensionxyz/dymension/v3/x/delayedack" "github.com/dymensionxyz/dymension/v3/x/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 := generatePackets(rollappId, 10) rollappId2 := "testRollappId2" @@ -40,7 +32,7 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { suite.Require().Nil(err) // call fraud on the 4 packet - err = keeper.HandleHardFork(ctx, rollappId, 4, transferStack) + err = keeper.OnHardFork(ctx, rollappId, 4) suite.Require().Nil(err) // expected result: @@ -59,8 +51,6 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { suite.Require().Equal(9, len(keeper.ListRollappPackets(ctx, prefixPending2))) } -// TODO: test refunds of pending packets - /* ---------------------------------- utils --------------------------------- */ func generatePackets(rollappId string, num uint64) []commontypes.RollappPacket { diff --git a/x/delayedack/keeper/invariants_test.go b/x/delayedack/keeper/invariants_test.go index f128e0c94..d7d351590 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -2,12 +2,10 @@ package keeper_test import ( "github.com/cometbft/cometbft/libs/rand" - ibctransfer "github.com/cosmos/ibc-go/v7/modules/apps/transfer" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" - damodule "github.com/dymensionxyz/dymension/v3/x/delayedack" dakeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) @@ -15,12 +13,6 @@ import ( func (suite *DelayedAckTestSuite) TestInvariants() { suite.T().Skip("skipping TestInvariants as it's not supported with lazy finalization feature") - transferStack := damodule.NewIBCMiddleware( - damodule.WithIBCModule(ibctransfer.NewIBCModule(suite.App.TransferKeeper)), - damodule.WithKeeper(suite.App.DelayedAckKeeper), - damodule.WithRollappKeeper(suite.App.RollappKeeper), - ) - initialHeight := int64(10) suite.Ctx = suite.Ctx.WithBlockHeight(initialHeight) @@ -82,7 +74,7 @@ func (suite *DelayedAckTestSuite) TestInvariants() { // test fraud for rollapp := range seqPerRollapp { - err := suite.App.DelayedAckKeeper.HandleHardFork(suite.Ctx, rollapp, uint64(suite.Ctx.BlockHeight()), transferStack) + err := suite.App.DelayedAckKeeper.OnHardFork(suite.Ctx, rollapp, uint64(suite.Ctx.BlockHeight())) suite.Require().NoError(err) break } diff --git a/x/delayedack/keeper/keeper.go b/x/delayedack/keeper/keeper.go index 5288adb12..49018bbd6 100644 --- a/x/delayedack/keeper/keeper.go +++ b/x/delayedack/keeper/keeper.go @@ -12,9 +12,12 @@ import ( porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) type Keeper struct { + rollapptypes.StubRollappCreatedHooks + cdc codec.BinaryCodec storeKey storetypes.StoreKey channelKeeperStoreKey storetypes.StoreKey // we need direct access to the IBC channel store diff --git a/x/delayedack/keeper/rollapp_packet.go b/x/delayedack/keeper/rollapp_packet.go index 4e56e7ace..35b5bce5a 100644 --- a/x/delayedack/keeper/rollapp_packet.go +++ b/x/delayedack/keeper/rollapp_packet.go @@ -174,6 +174,7 @@ func (k Keeper) DeleteRollappPacket(ctx sdk.Context, rollappPacket *commontypes. store.Delete(rollappPacketKey) keeperHooks := k.GetHooks() + // TODO: can call eIBC directly. shouldn't return error anyway err := keeperHooks.AfterPacketDeleted(ctx, rollappPacket) if err != nil { return err diff --git a/x/delayedack/rollapp_hooks.go b/x/delayedack/rollapp_hooks.go deleted file mode 100644 index ab9b01e5c..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) OnHardFork(ctx sdk.Context, rollappID string, height uint64) error { - return w.HandleHardFork(ctx, rollappID, height, w.IBCModule) -} diff --git a/x/delayedack/types/expected_keepers.go b/x/delayedack/types/expected_keepers.go index 552fab58c..e5607934e 100644 --- a/x/delayedack/types/expected_keepers.go +++ b/x/delayedack/types/expected_keepers.go @@ -14,6 +14,7 @@ import ( type ChannelKeeper interface { LookupModuleByChannel(ctx sdk.Context, portID, channelID string) (string, *capabilitytypes.Capability, error) SetPacketReceipt(ctx sdk.Context, portID, channelID string, sequence uint64) + SetPacketCommitment(ctx sdk.Context, portID, channelID string, sequence uint64, commitmentHash []byte) } type RollappKeeper interface { From ef4afb1a101a0aa80c7438f926ec56c5bcadf381 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Mon, 4 Nov 2024 14:56:27 +0200 Subject: [PATCH 26/68] register proposal handler --- .../dymension/rollapp/fraud_proposal.proto | 7 + x/rollapp/keeper/fraud_proposal.go | 32 ++- ...raud_handler_test.go => hard_fork_test.go} | 0 x/rollapp/module.go | 1 + x/rollapp/types/fraud_proposal.pb.go | 254 ++++++++++++++++-- 5 files changed, 260 insertions(+), 34 deletions(-) rename x/rollapp/keeper/{fraud_handler_test.go => hard_fork_test.go} (100%) diff --git a/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto index 819bb3edd..893987c46 100644 --- a/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto +++ b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto @@ -8,6 +8,10 @@ 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"; @@ -29,4 +33,7 @@ message MsgRollappFraudProposal { string slash_sequencer_address = 6; } +message MsgRollappFraudProposalResponse { +} + // TODO: add slashing only proposal (e.g for double signing) \ No newline at end of file diff --git a/x/rollapp/keeper/fraud_proposal.go b/x/rollapp/keeper/fraud_proposal.go index d44739857..6e9e4b4d2 100644 --- a/x/rollapp/keeper/fraud_proposal.go +++ b/x/rollapp/keeper/fraud_proposal.go @@ -1,56 +1,66 @@ package keeper import ( + "context" + errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" "github.com/dymensionxyz/gerr-cosmos/gerrc" ) // FraudProposalHandler handles the submission of a fraud proposal // The fraud proposal can be submitted by the gov module -func (k Keeper) FraudProposalHandler(ctx sdk.Context, msg types.MsgRollappFraudProposal) error { +func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappFraudProposal) (*types.MsgRollappFraudProposalResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + if msg.Authority != k.authority { - return errorsmod.Wrap(gerrc.ErrUnauthenticated, "only the gov module can submit fraud proposals") + return nil, errorsmod.Wrap(gerrc.ErrUnauthenticated, "only the gov module can submit fraud proposals") } if err := msg.ValidateBasic(); err != nil { - return errorsmod.Wrap(gerrc.ErrInvalidArgument, "invalid msg") + return nil, errorsmod.Wrap(gerrc.ErrInvalidArgument, "invalid msg") } rollapp, found := k.GetRollapp(ctx, msg.RollappId) if !found { - return errorsmod.Wrap(gerrc.ErrNotFound, "rollapp not found") + return nil, errorsmod.Wrap(gerrc.ErrNotFound, "rollapp not found") } // check revision number if rollapp.RevisionNumber != msg.RollappRevision { - return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "revision number mismatch") + return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "revision number mismatch") } // validate the rollapp is past it's genesis bridge phase if !rollapp.IsTransferEnabled() { - return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "rollapp is not past genesis bridge phase") + return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "rollapp is not past genesis bridge phase") } // validate the fraud height is already committed sinfo, found := k.GetLatestStateInfo(ctx, msg.RollappId) if !found || sinfo.GetLatestHeight() < msg.FraudHeight { - return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height not committed") + return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height not committed") } // check wether the fraud height is already finalized sinfo, found = k.GetLatestFinalizedStateInfo(ctx, msg.RollappId) if found && sinfo.GetLatestHeight() >= msg.FraudHeight { - return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height already finalized") + return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height already finalized") } // jail the sequencer if needed if msg.SlashSequencerAddress != "" { err := k.sequencerKeeper.JailByAddr(ctx, msg.SlashSequencerAddress) if err != nil { - return errorsmod.Wrap(err, "jail sequencer") + return nil, errorsmod.Wrap(err, "jail sequencer") } } - return k.HardFork(ctx, msg.RollappId, msg.FraudHeight) + + err := k.HardFork(ctx, msg.RollappId, msg.FraudHeight) + if err != nil { + return nil, errorsmod.Wrap(err, "hard fork") + } + + return &types.MsgRollappFraudProposalResponse{}, nil } diff --git a/x/rollapp/keeper/fraud_handler_test.go b/x/rollapp/keeper/hard_fork_test.go similarity index 100% rename from x/rollapp/keeper/fraud_handler_test.go rename to x/rollapp/keeper/hard_fork_test.go diff --git a/x/rollapp/module.go b/x/rollapp/module.go index 82a504d21..d686b75cb 100644 --- a/x/rollapp/module.go +++ b/x/rollapp/module.go @@ -127,6 +127,7 @@ 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.RegisterProposalMsgServer(cfg.MsgServer(), am.keeper) types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(*am.keeper)) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) } diff --git a/x/rollapp/types/fraud_proposal.pb.go b/x/rollapp/types/fraud_proposal.pb.go index 39e4a467a..3af1d9822 100644 --- a/x/rollapp/types/fraud_proposal.pb.go +++ b/x/rollapp/types/fraud_proposal.pb.go @@ -4,10 +4,15 @@ 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" @@ -114,8 +119,45 @@ func (m *MsgRollappFraudProposal) GetSlashSequencerAddress() string { 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() { @@ -123,29 +165,113 @@ func init() { } var fileDescriptor_120f0332aea0a45b = []byte{ - // 345 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x31, 0x4f, 0xc2, 0x40, - 0x14, 0xc7, 0x29, 0x22, 0x81, 0xd3, 0xa8, 0xb9, 0x68, 0x68, 0x50, 0x2f, 0xe8, 0x84, 0x0e, 0xbd, - 0x18, 0x8c, 0x83, 0x9b, 0x0e, 0x44, 0x07, 0x8d, 0xa9, 0x9b, 0x4b, 0x73, 0x70, 0x47, 0xdb, 0xd0, - 0xf2, 0xea, 0x5d, 0x4b, 0xa8, 0xa3, 0x9b, 0x9b, 0x1f, 0xc5, 0x8f, 0xe1, 0xc8, 0xe8, 0x68, 0x60, - 0xf0, 0x6b, 0x98, 0x5e, 0x0b, 0xb8, 0x38, 0xb5, 0xef, 0xf7, 0x7f, 0xff, 0xfc, 0xdf, 0xbb, 0x87, - 0x3a, 0x3c, 0x0d, 0xc5, 0x48, 0xf9, 0x30, 0x9a, 0xa4, 0x2f, 0x74, 0x59, 0x50, 0x09, 0x41, 0xc0, - 0xa2, 0x88, 0x0e, 0x24, 0x4b, 0xb8, 0x13, 0x49, 0x88, 0x40, 0xb1, 0xc0, 0x8a, 0x24, 0xc4, 0x80, - 0xc9, 0x5f, 0x93, 0xb5, 0x2c, 0xac, 0xc2, 0xd4, 0xdc, 0x75, 0xc1, 0x05, 0xdd, 0x4a, 0xb3, 0xbf, - 0xdc, 0xd5, 0x6c, 0xf4, 0x41, 0x85, 0xa0, 0x68, 0xa8, 0x5c, 0x3a, 0x3e, 0xcb, 0x3e, 0xb9, 0x70, - 0xfc, 0x56, 0x46, 0x8d, 0x3b, 0xe5, 0xda, 0xb9, 0xbb, 0x9b, 0x25, 0x3e, 0x14, 0x81, 0xf8, 0x00, - 0xd5, 0x59, 0x12, 0x7b, 0x20, 0xfd, 0x38, 0x35, 0x8d, 0x96, 0xd1, 0xae, 0xdb, 0x2b, 0x80, 0x0f, - 0x11, 0x2a, 0x32, 0x1d, 0x9f, 0x9b, 0xe5, 0x5c, 0x2e, 0xc8, 0x2d, 0xc7, 0x27, 0x68, 0x67, 0x21, - 0x4b, 0x31, 0xf6, 0xb3, 0x19, 0xcd, 0xb5, 0x96, 0xd1, 0xae, 0xd8, 0xdb, 0x05, 0xb7, 0x0b, 0x8c, - 0x8f, 0xd0, 0x66, 0xbe, 0xaa, 0x27, 0x7c, 0xd7, 0x8b, 0xcd, 0x8a, 0x6e, 0xdb, 0xd0, 0xec, 0x46, - 0x23, 0xbc, 0x8f, 0xea, 0x1e, 0x93, 0xdc, 0x19, 0x80, 0x1c, 0x9a, 0xeb, 0x2d, 0xa3, 0x5d, 0xb3, - 0x6b, 0x19, 0xe8, 0x82, 0x1c, 0xe2, 0x0b, 0xd4, 0x50, 0x01, 0x53, 0x9e, 0xa3, 0xc4, 0x73, 0x22, - 0x46, 0x7d, 0x21, 0x1d, 0xc6, 0xb9, 0x14, 0x4a, 0x99, 0x55, 0x3d, 0xd6, 0x9e, 0x96, 0x1f, 0x17, - 0xea, 0x55, 0x2e, 0x5e, 0x6e, 0xbd, 0xfe, 0x7c, 0x9c, 0xae, 0x36, 0xba, 0xbe, 0xff, 0x9c, 0x11, - 0x63, 0x3a, 0x23, 0xc6, 0xf7, 0x8c, 0x18, 0xef, 0x73, 0x52, 0x9a, 0xce, 0x49, 0xe9, 0x6b, 0x4e, - 0x4a, 0x4f, 0xe7, 0xae, 0x1f, 0x7b, 0x49, 0xcf, 0xea, 0x43, 0x48, 0xff, 0x39, 0xda, 0xb8, 0x43, - 0x27, 0xcb, 0xcb, 0xc5, 0x69, 0x24, 0x54, 0xaf, 0xaa, 0x9f, 0xb8, 0xf3, 0x1b, 0x00, 0x00, 0xff, - 0xff, 0x04, 0x9f, 0x23, 0x1a, 0xe8, 0x01, 0x00, 0x00, + // 401 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xbf, 0x6e, 0xda, 0x50, + 0x14, 0xc6, 0xb9, 0x94, 0x22, 0xb8, 0x54, 0x6d, 0x75, 0xd5, 0x0a, 0x8b, 0xb6, 0x2e, 0x30, 0xd1, + 0x0e, 0xbe, 0x4a, 0x88, 0x12, 0x29, 0x4b, 0x94, 0x0c, 0x28, 0x19, 0x88, 0x22, 0xb3, 0x65, 0xb1, + 0x0c, 0xbe, 0xd8, 0x16, 0xb6, 0xaf, 0x73, 0x8f, 0x8d, 0x70, 0xc6, 0x6c, 0x59, 0xa2, 0x3c, 0x41, + 0x9e, 0x21, 0x8f, 0x91, 0x91, 0x31, 0x63, 0x04, 0x43, 0x5e, 0x23, 0xf2, 0x3f, 0x60, 0x21, 0x43, + 0x26, 0xfb, 0xfc, 0xbe, 0xf3, 0xe9, 0x3b, 0xc7, 0x3e, 0xb8, 0x6b, 0x44, 0x2e, 0xf3, 0xc0, 0xe6, + 0xde, 0x2c, 0xba, 0xa6, 0xab, 0x82, 0x0a, 0xee, 0x38, 0xba, 0xef, 0xd3, 0xb1, 0xd0, 0x43, 0x43, + 0xf3, 0x05, 0xf7, 0x39, 0xe8, 0x8e, 0xe2, 0x0b, 0x1e, 0x70, 0x22, 0x6f, 0x9a, 0x94, 0x55, 0xa1, + 0x64, 0xa6, 0xc6, 0x0f, 0x93, 0x9b, 0x3c, 0x69, 0xa5, 0xf1, 0x5b, 0xea, 0x6a, 0xd4, 0x47, 0x1c, + 0x5c, 0x0e, 0xd4, 0x05, 0x93, 0x4e, 0x77, 0xe2, 0x47, 0x2a, 0xb4, 0x6f, 0x8b, 0xb8, 0xde, 0x07, + 0x53, 0x4d, 0xdd, 0xbd, 0x38, 0xf1, 0x22, 0x0b, 0x24, 0xbf, 0x71, 0x55, 0x0f, 0x03, 0x8b, 0x0b, + 0x3b, 0x88, 0x24, 0xd4, 0x44, 0x9d, 0xaa, 0xba, 0x06, 0xe4, 0x0f, 0xc6, 0x59, 0xa6, 0x66, 0x1b, + 0x52, 0x31, 0x95, 0x33, 0x72, 0x66, 0x90, 0x7f, 0xf8, 0x7b, 0x2e, 0x0b, 0x36, 0xb5, 0xe3, 0x19, + 0xa5, 0x4f, 0x4d, 0xd4, 0x29, 0xa9, 0xdf, 0x32, 0xae, 0x66, 0x98, 0xb4, 0xf0, 0x97, 0x74, 0x55, + 0x8b, 0xd9, 0xa6, 0x15, 0x48, 0xa5, 0xa4, 0xad, 0x96, 0xb0, 0xd3, 0x04, 0x91, 0x5f, 0xb8, 0x6a, + 0xe9, 0xc2, 0xd0, 0xc6, 0x5c, 0x4c, 0xa4, 0xcf, 0x4d, 0xd4, 0xa9, 0xa8, 0x95, 0x18, 0xf4, 0xb8, + 0x98, 0x90, 0x7d, 0x5c, 0x07, 0x47, 0x07, 0x4b, 0x03, 0x76, 0x15, 0x32, 0x6f, 0xc4, 0x84, 0xa6, + 0x1b, 0x86, 0x60, 0x00, 0x52, 0x39, 0x19, 0xeb, 0x67, 0x22, 0x0f, 0x72, 0xf5, 0x38, 0x15, 0x0f, + 0xbf, 0xde, 0xbc, 0x3e, 0xfe, 0x5f, 0x6f, 0xd4, 0x6e, 0xe1, 0xbf, 0x5b, 0x3e, 0x85, 0xca, 0xc0, + 0xe7, 0x1e, 0xb0, 0xdd, 0x07, 0x84, 0x6b, 0x39, 0xec, 0x83, 0x49, 0xee, 0x10, 0x26, 0x83, 0x70, + 0xe8, 0xda, 0xc1, 0xa6, 0x8d, 0x1c, 0x28, 0xef, 0xff, 0x25, 0x65, 0x4b, 0x4e, 0xe3, 0xe8, 0x83, + 0xc6, 0x7c, 0xc0, 0x93, 0xf3, 0xa7, 0x85, 0x8c, 0xe6, 0x0b, 0x19, 0xbd, 0x2c, 0x64, 0x74, 0xbf, + 0x94, 0x0b, 0xf3, 0xa5, 0x5c, 0x78, 0x5e, 0xca, 0x85, 0xcb, 0x3d, 0xd3, 0x0e, 0xac, 0x70, 0xa8, + 0x8c, 0xb8, 0x4b, 0xb7, 0x1c, 0xde, 0xb4, 0x4b, 0x67, 0xab, 0xeb, 0x0b, 0x22, 0x9f, 0xc1, 0xb0, + 0x9c, 0x9c, 0x49, 0xf7, 0x2d, 0x00, 0x00, 0xff, 0xff, 0xab, 0xb2, 0xbc, 0xaf, 0xac, 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) { @@ -212,6 +338,29 @@ func (m *MsgRollappFraudProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) 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 @@ -253,6 +402,15 @@ func (m *MsgRollappFraudProposal) Size() (n int) { 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 } @@ -463,6 +621,56 @@ func (m *MsgRollappFraudProposal) Unmarshal(dAtA []byte) error { } 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 From d2f8152947651f834df0ae9a9c17e1311f9891ba Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Mon, 4 Nov 2024 14:57:56 +0200 Subject: [PATCH 27/68] updating next proposer on state infos --- x/rollapp/keeper/hard_fork.go | 48 ++++++++++++------- .../keeper/msg_server_create_sequencer.go | 8 ++++ x/sequencer/types/expected_keepers.go | 5 ++ 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index ea27e9c4d..608e31c33 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -53,8 +53,11 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig // skip if not found (fraud height is not committed yet) stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, fraudHeight) if errorsmod.IsOf(err, gerrc.ErrNotFound) { - sinfo, _ := k.GetLatestStateInfo(ctx, rollappID) - return sinfo.GetLatestHeight(), nil + 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 if err != nil { return 0, err } @@ -64,14 +67,12 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig return 0, errorsmod.Wrapf(types.ErrDisputeAlreadyFinalized, "state info for height %d is already finalized", fraudHeight) } - lastStateIdxToKeep := stateInfo.StateInfoIndex.Index - // trunc the state info if needed - if stateInfo.StartHeight == fraudHeight { - // If fraud height is at the beginning of the state info, return the previous index to keep - lastStateIdxToKeep -= 1 - } else { - // otherwise, truncate the state info - k.TruncStateInfo(ctx, stateInfo, fraudHeight) + // 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 + lastStateIdxToKeep, err := k.UpdateLastStateInfo(ctx, stateInfo, fraudHeight) + if err != nil { + return 0, errorsmod.Wrap(err, "update last state info") } // clear state info @@ -130,18 +131,31 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig return fraudHeight - 1, nil } -// TruncStateInfo truncates the state info to the last valid block before the fraud height. +// UpdateLastStateInfo truncates the state info to the last valid block before the fraud height. // It returns the index of the last state info to keep. -func (k Keeper) TruncStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) { - // Remove block descriptors until the one we need to rollback to - truncatedBDs := stateInfo.BDs.BD[:fraudHeight-stateInfo.StartHeight] +func (k Keeper) UpdateLastStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) (uint64, error) { + 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 0, 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 to reflect truncated data + stateInfo.NumBlocks = uint64(len(truncatedBDs)) + stateInfo.BDs.BD = truncatedBDs + } else { + return 0, errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "state info start height is greater than fraud height") + } // Update the state info in the keeper + stateInfo.NextProposer = "" k.SetStateInfo(ctx, *stateInfo) + return stateInfo.StateInfoIndex.Index, nil } func (k Keeper) HardForkToLatest(ctx sdk.Context, rollappID string) error { diff --git a/x/sequencer/keeper/msg_server_create_sequencer.go b/x/sequencer/keeper/msg_server_create_sequencer.go index 94535a53a..c64d3cd1c 100644 --- a/x/sequencer/keeper/msg_server_create_sequencer.go +++ b/x/sequencer/keeper/msg_server_create_sequencer.go @@ -105,6 +105,14 @@ func (k msgServer) CreateSequencer(goCtx context.Context, msg *types.MsgCreateSe _, proposerExists := k.GetProposer(ctx, msg.RollappId) if !proposerExists { k.SetProposer(ctx, sequencer.RollappId, sequencer.Address) + + // recover from hard fork + // if the rollapp has a state info, set the next proposer to this sequencer + sInfo, ok := k.rollappKeeper.GetLatestStateInfo(ctx, sequencer.RollappId) + if ok { + sInfo.NextProposer = sequencer.Address + k.rollappKeeper.SetStateInfo(ctx, sInfo) + } } k.SetSequencer(ctx, sequencer) diff --git a/x/sequencer/types/expected_keepers.go b/x/sequencer/types/expected_keepers.go index cf7047f26..fdeaed14a 100644 --- a/x/sequencer/types/expected_keepers.go +++ b/x/sequencer/types/expected_keepers.go @@ -14,6 +14,11 @@ type RollappKeeper interface { GetAllRollapps(ctx sdk.Context) (list []rollapptypes.Rollapp) SetRollappAsLaunched(ctx sdk.Context, rollapp *rollapptypes.Rollapp) error GetParams(ctx sdk.Context) rollapptypes.Params + + // FIXME: remove after merge (will have hooks) + SetStateInfo(ctx sdk.Context, stateInfo rollapptypes.StateInfo) + GetLatestStateInfo(ctx sdk.Context, rollappId string) (val rollapptypes.StateInfo, found bool) + GetStateInfo(ctx sdk.Context, rollappId string, index uint64) (val rollapptypes.StateInfo, found bool) } // AccountKeeper defines the expected account keeper used for simulations (noalias) From d5933ff4b64a11282802a436aa4e96dd7decac1b Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Wed, 6 Nov 2024 10:52:23 +0200 Subject: [PATCH 28/68] feat(hard_fork): update hard fork to support new `x/sequencer` updates (#1406) Co-authored-by: keruch <53012408+keruch@users.noreply.github.com> Co-authored-by: zale144 Co-authored-by: Daniel T <30197399+danwt@users.noreply.github.com> Co-authored-by: Omri Co-authored-by: Sergi Rene Co-authored-by: Itzhak Bokris --- .gitignore | 3 +- app/ante/ante_options.go | 5 +- app/ante/handlers.go | 15 +- app/ante/reject_msgs.go | 118 +- app/ante/reject_msgs_test.go | 204 ++++ app/apptesting/delayedack.go | 53 + app/apptesting/test_suite.go | 10 +- app/keepers/keepers.go | 18 +- app/upgrades/v4/upgrade.go | 28 +- app/upgrades/v4/upgrade_test.go | 36 +- go.mod | 7 +- go.sum | 8 +- ibctesting/bridging_fee_test.go | 11 +- ibctesting/delayed_ack_test.go | 6 +- ibctesting/eibc_test.go | 8 +- ibctesting/genesis_bridge_test.go | 2 + ibctesting/light_client_test.go | 23 +- ibctesting/utils_test.go | 13 +- .../dymension/delayedack/events.proto | 25 - .../dymension/delayedack/query.proto | 13 +- .../dymension/lightclient/genesis.proto | 20 +- .../dymension/rollapp/genesis.proto | 8 + .../dymension/rollapp/liveness.proto | 3 +- .../dymension/rollapp/params.proto | 4 +- .../dymension/sequencer/events.proto | 42 +- .../dymension/sequencer/genesis.proto | 11 +- .../sequencer/operating_status.proto | 4 +- .../dymension/sequencer/params.proto | 19 +- .../dymension/sequencer/sequencer.proto | 41 +- .../dymensionxyz/dymension/sequencer/tx.proto | 34 +- testutil/keeper/dymns.go | 1 + testutil/keeper/iro.go | 4 +- testutil/keeper/lightclient.go | 85 +- testutil/keeper/rollapp.go | 2 +- testutil/keeper/sequencer.go | 2 + utils/denom/ibc.go | 37 + utils/denom/ibc_test.go | 40 + x/bridgingfee/ibc_module.go | 26 +- x/common/types/events.go | 14 +- x/common/types/rollapp_packet.go | 45 + x/delayedack/client/cli/query.go | 15 +- x/delayedack/genesis.go | 11 + x/delayedack/ibc_middleware.go | 11 +- x/delayedack/keeper/finalize_test.go | 8 +- x/delayedack/keeper/fraud_test.go | 29 +- x/delayedack/keeper/grpc_query.go | 25 +- x/delayedack/keeper/hooks_test.go | 3 +- x/delayedack/keeper/invariants_test.go | 53 +- x/delayedack/keeper/keeper.go | 43 +- x/delayedack/keeper/keeper_test.go | 5 +- x/delayedack/keeper/rollapp_packet.go | 105 +- x/delayedack/keeper/rollapp_packet_test.go | 148 ++- x/delayedack/types/codec.go | 21 +- x/delayedack/types/events.pb.go | 692 +---------- x/delayedack/types/keys.go | 4 +- x/delayedack/types/msgs.go | 38 + x/delayedack/types/query.pb.go | 281 ++--- x/delayedack/types/query.pb.gw.go | 72 +- x/dymns/keeper/keeper_suite_test.go | 1 + x/eibc/keeper/hooks_test.go | 8 +- x/eibc/types/codec.go | 16 +- x/eibc/types/tx.go | 5 + x/gamm/amm_test.go | 6 +- x/incentives/keeper/msg_server.go | 11 +- x/incentives/keeper/msg_server_test.go | 8 +- x/incentives/types/expected_keepers.go | 1 + x/iro/keeper/create_plan.go | 4 +- x/iro/keeper/create_plan_test.go | 2 +- x/iro/keeper/keeper.go | 3 + x/iro/keeper/keeper_test.go | 4 + x/iro/keeper/trade.go | 37 +- x/iro/keeper/trade_test.go | 68 +- x/iro/types/expected_keepers.go | 8 +- x/iro/types/plan.go | 15 +- x/iro/types/plan_test.go | 41 + .../ante/ibc_msg_channel_open_ack.go | 6 +- .../ante/ibc_msg_channel_open_ack_test.go | 14 +- .../ante/ibc_msg_submit_misbehaviour.go | 19 +- .../ante/ibc_msg_submit_misbehaviour_test.go | 11 +- x/lightclient/ante/ibc_msg_update_client.go | 176 ++- .../ante/ibc_msg_update_client_test.go | 430 ++----- x/lightclient/ante/ibc_msgs.go | 30 +- x/lightclient/keeper/canonical_client.go | 7 +- x/lightclient/keeper/genesis.go | 27 +- x/lightclient/keeper/genesis_test.go | 57 +- x/lightclient/keeper/hook_listener.go | 140 ++- x/lightclient/keeper/hook_listener_test.go | 44 +- x/lightclient/keeper/keeper.go | 191 ++- x/lightclient/keeper/keeper_test.go | 115 ++ x/lightclient/keeper/rollback.go | 11 +- x/lightclient/types/expected_keepers.go | 10 +- x/lightclient/types/genesis.go | 15 +- x/lightclient/types/genesis.pb.go | 453 ++++---- x/lightclient/types/genesis_test.go | 23 +- x/lightclient/types/keys.go | 35 +- x/lightclient/types/params.go | 7 +- x/lightclient/types/state.go | 32 +- x/lightclient/types/state_test.go | 10 +- x/rollapp/genesis.go | 33 + x/rollapp/genesis_test.go | 24 + x/rollapp/genesisbridge/ibc_module.go | 11 +- .../block_height_to_finalization_queue.go | 48 + ...block_height_to_finalization_queue_test.go | 33 + x/rollapp/keeper/expected_keepers.go | 12 +- x/rollapp/keeper/fraud_proposal.go | 6 +- x/rollapp/keeper/grpc_query_state_info.go | 2 +- x/rollapp/keeper/hard_fork.go | 21 +- x/rollapp/keeper/hard_fork_test.go | 5 +- x/rollapp/keeper/invariants.go | 2 +- x/rollapp/keeper/keeper.go | 17 +- x/rollapp/keeper/liveness.go | 60 +- x/rollapp/keeper/liveness_test.go | 39 +- .../msg_server_mark_vulnerable_rollapps.go | 10 +- .../keeper/msg_server_update_rollapp_test.go | 14 +- x/rollapp/keeper/msg_server_update_state.go | 12 +- .../keeper/msg_server_update_state_test.go | 8 +- x/rollapp/keeper/params.go | 6 - x/rollapp/keeper/rollapp.go | 60 + x/rollapp/keeper/sequencer_hooks.go | 38 + x/rollapp/types/errors.go | 2 +- x/rollapp/types/genesis.go | 10 + x/rollapp/types/genesis.pb.go | 457 +++++++- x/rollapp/types/genesis_test.go | 24 +- x/rollapp/types/keys.go | 4 + x/rollapp/types/liveness.go | 9 +- x/rollapp/types/liveness.pb.go | 77 +- x/rollapp/types/params.go | 22 +- x/rollapp/types/params.pb.go | 91 +- x/rollapp/types/rollapp.go | 4 - x/sequencer/client/cli/tx.go | 53 +- x/sequencer/genesis.go | 46 +- x/sequencer/genesis_test.go | 118 +- x/sequencer/handler.go | 6 +- x/sequencer/keeper/bond.go | 69 ++ x/sequencer/keeper/bond_reductions.go | 160 --- x/sequencer/keeper/bond_reductions_test.go | 141 --- x/sequencer/keeper/bond_test.go | 26 + x/sequencer/keeper/fraud.go | 110 ++ x/sequencer/keeper/fraud_test.go | 113 ++ x/sequencer/keeper/funds.go | 55 + x/sequencer/keeper/get_and_set.go | 191 +++ x/sequencer/keeper/get_and_set_test.go | 57 + x/sequencer/keeper/grpc_query_params_test.go | 1 - x/sequencer/keeper/grpc_query_sequencer.go | 24 +- .../keeper/grpc_query_sequencer_test.go | 19 +- .../grpc_query_sequencers_by_rollapp.go | 56 +- .../grpc_query_sequencers_by_rollapp_test.go | 129 +- x/sequencer/keeper/hook_listener.go | 39 +- x/sequencer/keeper/hooks_test.go | 59 - x/sequencer/keeper/invariants.go | 80 +- x/sequencer/keeper/invariants_test.go | 68 +- x/sequencer/keeper/keeper.go | 43 +- x/sequencer/keeper/msg_server.go | 4 +- x/sequencer/keeper/msg_server_bond.go | 98 ++ x/sequencer/keeper/msg_server_bond_test.go | 180 +++ x/sequencer/keeper/msg_server_create.go | 124 ++ .../keeper/msg_server_create_sequencer.go | 131 --- .../msg_server_create_sequencer_test.go | 575 --------- x/sequencer/keeper/msg_server_create_test.go | 287 +++++ .../keeper/msg_server_decrease_bond.go | 52 - .../keeper/msg_server_decrease_bond_test.go | 122 -- .../keeper/msg_server_increase_bond.go | 54 - .../keeper/msg_server_increase_bond_test.go | 90 -- .../keeper/msg_server_kick_proposer.go | 25 + .../keeper/msg_server_kick_proposer_test.go | 48 + x/sequencer/keeper/msg_server_unbond.go | 54 - x/sequencer/keeper/msg_server_unbond_test.go | 80 -- x/sequencer/keeper/msg_server_update.go | 63 + .../msg_server_update_reward_address.go | 16 +- .../msg_server_update_reward_address_test.go | 20 +- .../keeper/msg_server_update_sequencer.go | 40 - ...ncer_test.go => msg_server_update_test.go} | 68 +- .../msg_server_update_whitelisted_relayers.go | 16 +- ...server_update_whitelisted_relayers_test.go | 20 +- x/sequencer/keeper/params.go | 33 +- x/sequencer/keeper/params_test.go | 13 - x/sequencer/keeper/proposer.go | 130 +++ x/sequencer/keeper/proposer_test.go | 83 ++ x/sequencer/keeper/rotation.go | 159 +-- x/sequencer/keeper/rotation_test.go | 291 ++--- x/sequencer/keeper/sequencer.go | 274 +---- x/sequencer/keeper/sequencer_suite_test.go | 108 -- x/sequencer/keeper/sequencer_test.go | 70 -- x/sequencer/keeper/slashing.go | 109 -- x/sequencer/keeper/slashing_fraud_test.go | 99 -- x/sequencer/keeper/slashing_test.go | 16 - x/sequencer/keeper/unbond.go | 187 --- x/sequencer/keeper/unbond_test.go | 124 -- x/sequencer/keeper/util_test.go | 241 ++++ x/sequencer/migrations.go | 4 +- x/sequencer/migrations_test.go | 5 - x/sequencer/module.go | 23 +- x/sequencer/types/codec.go | 9 +- x/sequencer/types/errors.go | 42 +- x/sequencer/types/events.go | 9 +- x/sequencer/types/events.pb.go | 1035 +++++++++++++++-- x/sequencer/types/expected_keepers.go | 5 - x/sequencer/types/genesis.go | 28 +- x/sequencer/types/genesis.pb.go | 127 +- x/sequencer/types/hooks.go | 38 + x/sequencer/types/keys.go | 70 +- x/sequencer/types/metadata.go | 5 +- .../types/{msg_bond_change.go => msg_bond.go} | 31 +- ...{msg_create_sequencer.go => msg_create.go} | 6 +- ...e_sequencer_test.go => msg_create_test.go} | 6 +- x/sequencer/types/msg_kick_proposer.go | 33 + x/sequencer/types/msg_unbond.go | 31 - ...{msg_update_sequencer.go => msg_update.go} | 29 +- .../types/msg_update_reward_address.go | 6 +- .../types/msg_update_reward_address_test.go | 3 +- ...e_sequencer_test.go => msg_update_test.go} | 0 .../types/msg_update_whitelisted_relayers.go | 6 +- .../msg_update_whitelisted_relayers_test.go | 3 +- x/sequencer/types/operating_status.pb.go | 33 +- x/sequencer/types/params.go | 36 +- x/sequencer/types/params.pb.go | 202 ++-- x/sequencer/types/params_legacy.go | 15 +- x/sequencer/types/params_test.go | 27 +- x/sequencer/types/sequencer.go | 201 +++- x/sequencer/types/sequencer.pb.go | 520 ++------- x/sequencer/types/status.go | 6 + x/sequencer/types/tx.pb.go | 972 ++++++++++++---- x/sponsorship/keeper/votes.go | 2 +- x/sponsorship/keeper/votes_test.go | 12 +- x/sponsorship/types/expected_keepers.go | 2 +- 225 files changed, 8232 insertions(+), 6991 deletions(-) create mode 100644 app/ante/reject_msgs_test.go create mode 100644 app/apptesting/delayedack.go create mode 100644 utils/denom/ibc.go create mode 100644 utils/denom/ibc_test.go create mode 100644 x/iro/types/plan_test.go create mode 100644 x/lightclient/keeper/keeper_test.go create mode 100644 x/rollapp/keeper/sequencer_hooks.go create mode 100644 x/sequencer/keeper/bond.go delete mode 100644 x/sequencer/keeper/bond_reductions.go delete mode 100644 x/sequencer/keeper/bond_reductions_test.go create mode 100644 x/sequencer/keeper/bond_test.go create mode 100644 x/sequencer/keeper/fraud.go create mode 100644 x/sequencer/keeper/fraud_test.go create mode 100644 x/sequencer/keeper/funds.go create mode 100644 x/sequencer/keeper/get_and_set.go create mode 100644 x/sequencer/keeper/get_and_set_test.go delete mode 100644 x/sequencer/keeper/hooks_test.go create mode 100644 x/sequencer/keeper/msg_server_bond.go create mode 100644 x/sequencer/keeper/msg_server_bond_test.go create mode 100644 x/sequencer/keeper/msg_server_create.go delete mode 100644 x/sequencer/keeper/msg_server_create_sequencer.go delete mode 100644 x/sequencer/keeper/msg_server_create_sequencer_test.go create mode 100644 x/sequencer/keeper/msg_server_create_test.go delete mode 100644 x/sequencer/keeper/msg_server_decrease_bond.go delete mode 100644 x/sequencer/keeper/msg_server_decrease_bond_test.go delete mode 100644 x/sequencer/keeper/msg_server_increase_bond.go delete mode 100644 x/sequencer/keeper/msg_server_increase_bond_test.go create mode 100644 x/sequencer/keeper/msg_server_kick_proposer.go create mode 100644 x/sequencer/keeper/msg_server_kick_proposer_test.go delete mode 100644 x/sequencer/keeper/msg_server_unbond.go delete mode 100644 x/sequencer/keeper/msg_server_unbond_test.go create mode 100644 x/sequencer/keeper/msg_server_update.go delete mode 100644 x/sequencer/keeper/msg_server_update_sequencer.go rename x/sequencer/keeper/{msg_server_update_sequencer_test.go => msg_server_update_test.go} (73%) create mode 100644 x/sequencer/keeper/proposer.go create mode 100644 x/sequencer/keeper/proposer_test.go delete mode 100644 x/sequencer/keeper/sequencer_suite_test.go delete mode 100644 x/sequencer/keeper/sequencer_test.go delete mode 100644 x/sequencer/keeper/slashing.go delete mode 100644 x/sequencer/keeper/slashing_fraud_test.go delete mode 100644 x/sequencer/keeper/slashing_test.go delete mode 100644 x/sequencer/keeper/unbond.go delete mode 100644 x/sequencer/keeper/unbond_test.go create mode 100644 x/sequencer/keeper/util_test.go create mode 100644 x/sequencer/types/hooks.go rename x/sequencer/types/{msg_bond_change.go => msg_bond.go} (68%) rename x/sequencer/types/{msg_create_sequencer.go => msg_create.go} (94%) rename x/sequencer/types/{msg_create_sequencer_test.go => msg_create_test.go} (99%) create mode 100644 x/sequencer/types/msg_kick_proposer.go delete mode 100644 x/sequencer/types/msg_unbond.go rename x/sequencer/types/{msg_update_sequencer.go => msg_update.go} (70%) rename x/sequencer/types/{msg_update_sequencer_test.go => msg_update_test.go} (100%) create mode 100644 x/sequencer/types/status.go diff --git a/.gitignore b/.gitignore index 5643f32c5..9cedeba58 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ build/ .DS_Store proposal.json .go-version -**/testdata/rapid/ \ No newline at end of file +**/testdata/rapid/ +**/__debug_bin* \ No newline at end of file diff --git a/app/ante/ante_options.go b/app/ante/ante_options.go index aee765fb2..84bf48b64 100644 --- a/app/ante/ante_options.go +++ b/app/ante/ante_options.go @@ -1,14 +1,15 @@ package ante import ( - ante "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/cosmos/cosmos-sdk/x/auth/ante" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" + ethante "github.com/evmos/ethermint/app/ante" + lightclientkeeper "github.com/dymensionxyz/dymension/v3/x/lightclient/keeper" rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" - ethante "github.com/evmos/ethermint/app/ante" errorsmod "cosmossdk.io/errors" errortypes "github.com/cosmos/cosmos-sdk/types/errors" diff --git a/app/ante/handlers.go b/app/ante/handlers.go index 98a85c35d..469de2aa6 100644 --- a/app/ante/handlers.go +++ b/app/ante/handlers.go @@ -2,7 +2,7 @@ package ante import ( sdk "github.com/cosmos/cosmos-sdk/types" - ante "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/cosmos/cosmos-sdk/x/auth/ante" ibcante "github.com/cosmos/ibc-go/v7/modules/core/ante" ethante "github.com/evmos/ethermint/app/ante" txfeesante "github.com/osmosis-labs/osmosis/v15/x/txfees/ante" @@ -10,7 +10,7 @@ import ( vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" evmtypes "github.com/evmos/ethermint/x/evm/types" - delayedack "github.com/dymensionxyz/dymension/v3/x/delayedack" + "github.com/dymensionxyz/dymension/v3/x/delayedack" lightclientante "github.com/dymensionxyz/dymension/v3/x/lightclient/ante" "github.com/dymensionxyz/dymension/v3/x/rollapp/genesisbridge" ) @@ -45,13 +45,12 @@ func newLegacyCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler { See https://jumpcrypto.com/writing/bypassing-ethermint-ante-handlers/ for an explanation of these message blocking decorators */ - NewRejectMessagesDecorator(), // reject MsgEthereumTxs - ethante.NewAuthzLimiterDecorator([]string{ // disable the Msg types that cannot be included on an authz.MsgExec msgs field + NewRejectMessagesDecorator( + // reject MsgEthereumTxs and disable the Msg types that cannot be included on an authz.MsgExec msgs field sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{}), sdk.MsgTypeURL(&vestingtypes.MsgCreateVestingAccount{}), sdk.MsgTypeURL(&vestingtypes.MsgCreatePeriodicVestingAccount{}), sdk.MsgTypeURL(&vestingtypes.MsgCreatePermanentLockedAccount{}), - }, ), ante.NewSetUpContextDecorator(), @@ -84,14 +83,12 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { deductFeeDecorator := txfeesante.NewDeductFeeDecorator(*options.TxFeesKeeper, options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper) return sdk.ChainAnteDecorators( - - NewRejectMessagesDecorator(), // reject MsgEthereumTxs and vesting msgs - ethante.NewAuthzLimiterDecorator([]string{ // disable the Msg types that cannot be included on an authz.MsgExec msgs field + NewRejectMessagesDecorator( + // reject MsgEthereumTxs and disable the Msg types that cannot be included on an authz.MsgExec msgs field sdk.MsgTypeURL(&evmtypes.MsgEthereumTx{}), sdk.MsgTypeURL(&vestingtypes.MsgCreateVestingAccount{}), sdk.MsgTypeURL(&vestingtypes.MsgCreatePeriodicVestingAccount{}), sdk.MsgTypeURL(&vestingtypes.MsgCreatePermanentLockedAccount{}), - }, ), ante.NewSetUpContextDecorator(), ante.NewExtensionOptionsDecorator(options.ExtensionOptionChecker), diff --git a/app/ante/reject_msgs.go b/app/ante/reject_msgs.go index 15cb9e041..00fb75271 100644 --- a/app/ante/reject_msgs.go +++ b/app/ante/reject_msgs.go @@ -1,48 +1,120 @@ package ante import ( + "fmt" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/authz" + govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/cosmos/cosmos-sdk/x/group" evmtypes "github.com/evmos/ethermint/x/evm/types" ) // RejectMessagesDecorator prevents invalid msg types from being executed type RejectMessagesDecorator struct { - disabledMsgTypeURLs []string + disabledMsgTypeURLs map[string]struct{} } var _ sdk.AnteDecorator = RejectMessagesDecorator{} -// NewRejectMessagesDecorator creates a decorator to block vesting messages from reaching the mempool -func NewRejectMessagesDecorator() RejectMessagesDecorator { +// NewRejectMessagesDecorator creates a decorator to block provided messages from reaching the mempool +func NewRejectMessagesDecorator(disabledMsgTypeURLs ...string) RejectMessagesDecorator { + disabledMsgsMap := make(map[string]struct{}) + for _, url := range disabledMsgTypeURLs { + disabledMsgsMap[url] = struct{}{} + } + return RejectMessagesDecorator{ - disabledMsgTypeURLs: []string{}, + disabledMsgTypeURLs: disabledMsgsMap, } } -// AnteHandle rejects messages that requires ethereum-specific authentication. -// For example `MsgEthereumTx` requires fee to be deducted in the antehandler in +// AnteHandle recursively rejects messages such as those that requires ethereum-specific authentication. +// For example `MsgEthereumTx` requires fee to be deducted in the ante handler in // order to perform the refund. -func (rmd RejectMessagesDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { - for _, msg := range tx.GetMsgs() { - if _, ok := msg.(*evmtypes.MsgEthereumTx); ok { - return ctx, errorsmod.Wrapf( - sdkerrors.ErrInvalidType, - "MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option", - ) +func (rmd RejectMessagesDecorator) AnteHandle( + ctx sdk.Context, + tx sdk.Tx, + simulate bool, + 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 next(ctx, tx, simulate) +} + +const maxNestedMsgs = 6 + +func (rmd RejectMessagesDecorator) checkMsgs(ctx sdk.Context, msgs []sdk.Msg, nestedMsgs int) error { + for _, msg := range msgs { + if err := rmd.checkMsg(ctx, msg, nestedMsgs); err != nil { + return err } + } + return nil +} + +func (rmd RejectMessagesDecorator) checkMsg(ctx sdk.Context, msg sdk.Msg, nestedMsgs int) error { + typeURL := sdk.MsgTypeURL(msg) + if _, ok := rmd.disabledMsgTypeURLs[typeURL]; ok { + return fmt.Errorf("found disabled msg type: %s", typeURL) + } + + if _, ok := msg.(*evmtypes.MsgEthereumTx); ok { + return errorsmod.Wrapf( + sdkerrors.ErrInvalidType, + "MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option", + ) + } - typeURL := sdk.MsgTypeURL(msg) - for _, disabledTypeURL := range rmd.disabledMsgTypeURLs { - if typeURL == disabledTypeURL { - return ctx, errorsmod.Wrapf( - sdkerrors.ErrUnauthorized, - "MsgTypeURL %s not supported", - typeURL, - ) - } + if nestedMsgs >= maxNestedMsgs { + return fmt.Errorf("found more nested msgs than permitted. Limit is : %d", maxNestedMsgs) + } + + innerMsgs, err := extractMsgs(msg) + if err != nil { + return err + } + switch concreteMsg := msg.(type) { + case *authz.MsgExec: + nestedMsgs++ + if err := rmd.checkMsgs(ctx, innerMsgs, nestedMsgs); err != nil { + return err + } + case *authz.MsgGrant: + authorization, err := concreteMsg.GetAuthorization() + if err != nil { + return err + } + url := authorization.MsgTypeURL() + if _, ok := rmd.disabledMsgTypeURLs[url]; ok { + return fmt.Errorf("granting disabled msg type: %s is not allowed", url) + } + case *govtypesv1.MsgSubmitProposal: + nestedMsgs++ + if err := rmd.checkMsgs(ctx, innerMsgs, nestedMsgs); err != nil { + return err + } + case *group.MsgSubmitProposal: + nestedMsgs++ + if err := rmd.checkMsgs(ctx, innerMsgs, nestedMsgs); err != nil { + return err } + default: } - return next(ctx, tx, simulate) + + return nil +} + +func extractMsgs(msg any) ([]sdk.Msg, error) { + if msgWithMsgs, ok := msg.(interface{ GetMsgs() ([]sdk.Msg, error) }); ok { + return msgWithMsgs.GetMsgs() + } + if msgWithMessages, ok := msg.(interface{ GetMessages() ([]sdk.Msg, error) }); ok { + return msgWithMessages.GetMessages() + } + return nil, nil } diff --git a/app/ante/reject_msgs_test.go b/app/ante/reject_msgs_test.go new file mode 100644 index 000000000..53e54d8c5 --- /dev/null +++ b/app/ante/reject_msgs_test.go @@ -0,0 +1,204 @@ +package ante_test + +import ( + "testing" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + govtypesv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/stretchr/testify/require" + + "github.com/dymensionxyz/dymension/v3/app/ante" +) + +func (suite *AnteTestSuite) TestRejectMessagesDecorator() { + suite.SetupTestCheckTx(false) + + disabledMsgTypes := []string{ + sdk.MsgTypeURL(&banktypes.MsgSend{}), + sdk.MsgTypeURL(&types.MsgDelegate{}), + } + + decorator := ante.NewRejectMessagesDecorator(disabledMsgTypes...) + + testCases := []struct { + name string + msgs []sdk.Msg + expectPass bool + expectedError string + }{ + { + name: "Transaction with direct disabled message (MsgSend)", + msgs: []sdk.Msg{ + &banktypes.MsgSend{ + FromAddress: "cosmos1...", + ToAddress: "cosmos1...", + Amount: sdk.NewCoins(sdk.NewInt64Coin("stake", 1000)), + }, + }, + expectPass: false, + expectedError: "found disabled msg type: /cosmos.bank.v1beta1.MsgSend", + }, + { + name: "Transaction with allowed message (MsgMultiSend)", + msgs: []sdk.Msg{ + &banktypes.MsgMultiSend{ + Inputs: []banktypes.Input{}, + Outputs: []banktypes.Output{}, + }, + }, + expectPass: true, + }, + { + name: "Transaction with disabled message nested in MsgExec", + msgs: []sdk.Msg{ + &authz.MsgExec{ + Grantee: "cosmos1...", + Msgs: []*codectypes.Any{ + packMsg(suite.T(), &banktypes.MsgSend{ + FromAddress: "cosmos1...", + ToAddress: "cosmos1...", + Amount: sdk.NewCoins(sdk.NewInt64Coin("stake", 1000)), + }), + }, + }, + }, + expectPass: false, + expectedError: "found disabled msg type: /cosmos.bank.v1beta1.MsgSend", + }, + { + name: "Transaction with allowed message nested in MsgExec", + msgs: []sdk.Msg{ + &authz.MsgExec{ + Grantee: "cosmos1...", + Msgs: []*codectypes.Any{ + packMsg(suite.T(), &banktypes.MsgMultiSend{ + Inputs: []banktypes.Input{}, + Outputs: []banktypes.Output{}, + }), + }, + }, + }, + expectPass: true, + }, + { + name: "Transaction with disabled message in gov v1 MsgSubmitProposal", + msgs: []sdk.Msg{ + &govtypesv1.MsgSubmitProposal{ + Messages: []*codectypes.Any{ + packMsg(suite.T(), &banktypes.MsgSend{ + FromAddress: "cosmos1...", + ToAddress: "cosmos1...", + Amount: sdk.NewCoins(sdk.NewInt64Coin("stake", 1000)), + }), + }, + InitialDeposit: sdk.NewCoins(sdk.NewInt64Coin("stake", 1000)), + Proposer: "cosmos1...", + }, + }, + expectPass: false, + expectedError: "found disabled msg type: /cosmos.bank.v1beta1.MsgSend", + }, + { + name: "Transaction exceeding max nested messages", + msgs: []sdk.Msg{ + generateDeeplyNestedMsgExec(suite.T(), 7), // exceeds maxNestedMsgs (6) + }, + expectPass: false, + expectedError: "found more nested msgs than permitted. Limit is : 6", + }, + { + name: "Transaction with authz.MsgGrant granting disabled message", + msgs: []sdk.Msg{ + &authz.MsgGrant{ + Granter: "cosmos1...", + Grantee: "cosmos1...", + Grant: authz.Grant{ + Authorization: packAuthorization(suite.T(), &authz.GenericAuthorization{ + Msg: sdk.MsgTypeURL(&banktypes.MsgSend{}), + }), + Expiration: nil, + }, + }, + }, + expectPass: false, + expectedError: "granting disabled msg type: /cosmos.bank.v1beta1.MsgSend is not allowed", + }, + { + name: "Transaction with authz.MsgGrant granting allowed message", + msgs: []sdk.Msg{ + &authz.MsgGrant{ + Granter: "cosmos1...", + Grantee: "cosmos1...", + Grant: authz.Grant{ + Authorization: packAuthorization(suite.T(), &authz.GenericAuthorization{ + Msg: sdk.MsgTypeURL(&banktypes.MsgMultiSend{}), + }), + Expiration: nil, + }, + }, + }, + expectPass: true, + }, + } + + for _, tc := range testCases { + suite.Run(tc.name, func() { + tx := &mockTx{msgs: tc.msgs} + + ctx := suite.ctx.WithBlockHeight(1) + _, err := decorator.AnteHandle(ctx, tx, false, func(sdk.Context, sdk.Tx, bool) (sdk.Context, error) { return ctx, nil }) + + if tc.expectPass { + suite.NoError(err, "Test case %s failed unexpectedly", tc.name) + } else { + suite.Error(err, "Test case %s expected error but got none", tc.name) + suite.Contains(err.Error(), tc.expectedError, "Test case %s error message mismatch", tc.name) + } + }) + } +} + +func packMsg(t *testing.T, msg sdk.Msg) *codectypes.Any { + a, err := codectypes.NewAnyWithValue(msg) + require.NoError(t, err) + return a +} + +func packAuthorization(t *testing.T, authorization authz.Authorization) *codectypes.Any { + a, err := codectypes.NewAnyWithValue(authorization) + require.NoError(t, err) + return a +} + +type mockTx struct { + msgs []sdk.Msg +} + +func (tx *mockTx) GetMsgs() []sdk.Msg { + return tx.msgs +} + +func (tx *mockTx) ValidateBasic() error { + return nil +} + +func generateDeeplyNestedMsgExec(t *testing.T, depth int) sdk.Msg { + if depth <= 0 { + return &banktypes.MsgMultiSend{ + Inputs: []banktypes.Input{}, + Outputs: []banktypes.Output{}, + } + } + + innerMsg := generateDeeplyNestedMsgExec(t, depth-1) + anyMsg := packMsg(t, innerMsg) + + return &authz.MsgExec{ + Grantee: "cosmos1...", + Msgs: []*codectypes.Any{anyMsg}, + } +} diff --git a/app/apptesting/delayedack.go b/app/apptesting/delayedack.go new file mode 100644 index 000000000..4722b2db5 --- /dev/null +++ b/app/apptesting/delayedack.go @@ -0,0 +1,53 @@ +package apptesting + +import ( + "testing" + + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + "github.com/stretchr/testify/require" + + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" +) + +const ( + TestPacketReceiver = "testReceiver" + TestPacketSender = "testSender" +) + +func GenerateTestPacketData(t *testing.T) []byte { + t.Helper() + data := &transfertypes.FungibleTokenPacketData{ + Receiver: TestPacketReceiver, + Sender: TestPacketSender, + } + pd, err := transfertypes.ModuleCdc.MarshalJSON(data) + require.NoError(t, err) + return pd +} + +func GenerateTestPacket(t *testing.T, sequence uint64) *channeltypes.Packet { + t.Helper() + return &channeltypes.Packet{ + SourcePort: "testSourcePort", + SourceChannel: "testSourceChannel", + DestinationPort: "testDestinationPort", + DestinationChannel: "testDestinationChannel", + Data: GenerateTestPacketData(t), + Sequence: sequence, + } +} + +func GenerateRollappPackets(t *testing.T, rollappId string, num uint64) []commontypes.RollappPacket { + t.Helper() + var packets []commontypes.RollappPacket + for i := uint64(1); i <= num; i++ { + packets = append(packets, commontypes.RollappPacket{ + RollappId: rollappId, + Packet: GenerateTestPacket(t, i), + Status: commontypes.Status_PENDING, + ProofHeight: i, + }) + } + return packets +} diff --git a/app/apptesting/test_suite.go b/app/apptesting/test_suite.go index 9e407bf13..cb30fee66 100644 --- a/app/apptesting/test_suite.go +++ b/app/apptesting/test_suite.go @@ -44,7 +44,6 @@ func (s *KeeperTestHelper) CreateDefaultRollappAndProposer() (string, string) { return rollappId, proposer } -// creates a rollapp and return its rollappID func (s *KeeperTestHelper) CreateDefaultRollapp() string { rollappId := urand.RollappID() s.CreateRollappByName(rollappId) @@ -183,13 +182,12 @@ func FundForAliasRegistration( ) } -func (s *KeeperTestHelper) FinalizeAllPendingPackets(rollappID, receiver string) int { +func (s *KeeperTestHelper) FinalizeAllPendingPackets(address string) int { s.T().Helper() - // Query all pending packets by receiver + // Query all pending packets by address querier := delayedackkeeper.NewQuerier(s.App.DelayedAckKeeper) - resp, err := querier.GetPendingPacketsByReceiver(s.Ctx, &delayedacktypes.QueryPendingPacketsByReceiverRequest{ - RollappId: rollappID, - Receiver: receiver, + resp, err := querier.GetPendingPacketsByAddress(s.Ctx, &delayedacktypes.QueryPendingPacketsByAddressRequest{ + Address: address, }) s.Require().NoError(err) // Finalize all packets and return the num of finalized diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 1d748073f..dd2f266d8 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -143,7 +143,7 @@ type AppKeepers struct { ScopedTransferKeeper capabilitykeeper.ScopedKeeper RollappKeeper *rollappmodulekeeper.Keeper - SequencerKeeper sequencermodulekeeper.Keeper + SequencerKeeper *sequencermodulekeeper.Keeper SponsorshipKeeper sponsorshipkeeper.Keeper StreamerKeeper streamermodulekeeper.Keeper EIBCKeeper eibckeeper.Keeper @@ -310,7 +310,8 @@ func (a *AppKeepers) InitKeepers( appCodec, a.keys[gammtypes.StoreKey], a.GetSubspace(gammtypes.ModuleName), a.AccountKeeper, - a.BankKeeper, a.DistrKeeper, + a.BankKeeper, + a.DistrKeeper, ) a.GAMMKeeper = &gammKeeper @@ -329,6 +330,7 @@ func (a *AppKeepers) InitKeepers( a.BankKeeper, a.PoolManagerKeeper, a.GAMMKeeper, + a.DistrKeeper, ) a.TxFeesKeeper = &txFeesKeeper @@ -358,11 +360,14 @@ func (a *AppKeepers) InitKeepers( a.IBCKeeper.ClientKeeper, nil, a.BankKeeper, + a.TransferKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), nil, ) - a.SequencerKeeper = *sequencermodulekeeper.NewKeeper( + a.GAMMKeeper.SetRollapp(a.RollappKeeper) + + a.SequencerKeeper = sequencermodulekeeper.NewKeeper( appCodec, a.keys[sequencermoduletypes.StoreKey], a.BankKeeper, @@ -378,6 +383,9 @@ func (a *AppKeepers) InitKeepers( a.RollappKeeper, ) + a.SequencerKeeper.SetUnbondBlockers(a.RollappKeeper, a.LightClientKeeper) + a.SequencerKeeper.SetHooks(sequencermoduletypes.MultiHooks{rollappmodulekeeper.SequencerHooks{Keeper: a.RollappKeeper}}) + groupConfig := grouptypes.Config{ MaxExecutionPeriod: 0, MaxMetadataLen: 0, @@ -415,6 +423,7 @@ func (a *AppKeepers) InitKeepers( a.GAMMKeeper, a.IncentivesKeeper, a.PoolManagerKeeper, + a.TxFeesKeeper, ) a.SponsorshipKeeper = sponsorshipkeeper.NewKeeper( @@ -526,10 +535,11 @@ func (a *AppKeepers) InitTransferStack() { a.TransferStack = ibctransfer.NewIBCModule(a.TransferKeeper) a.TransferStack = bridgingfee.NewIBCModule( a.TransferStack.(ibctransfer.IBCModule), + *a.RollappKeeper, a.DelayedAckKeeper, a.TransferKeeper, + *a.TxFeesKeeper, a.AccountKeeper.GetModuleAddress(txfeestypes.ModuleName), - *a.RollappKeeper, ) a.TransferStack = packetforwardmiddleware.NewIBCMiddleware( a.TransferStack, diff --git a/app/upgrades/v4/upgrade.go b/app/upgrades/v4/upgrade.go index bb68de0e6..554ebc925 100644 --- a/app/upgrades/v4/upgrade.go +++ b/app/upgrades/v4/upgrade.go @@ -19,13 +19,13 @@ import ( upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" ibctransfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" ibcchannelkeeper "github.com/cosmos/ibc-go/v7/modules/core/04-channel/keeper" - evmtypes "github.com/evmos/ethermint/x/evm/types" feemarkettypes "github.com/evmos/ethermint/x/feemarket/types" epochskeeper "github.com/osmosis-labs/osmosis/v15/x/epochs/keeper" "github.com/dymensionxyz/dymension/v3/app/keepers" "github.com/dymensionxyz/dymension/v3/app/upgrades" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" delayedackkeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" delayedacktypes "github.com/dymensionxyz/dymension/v3/x/delayedack/types" incentiveskeeper "github.com/dymensionxyz/dymension/v3/x/incentives/keeper" @@ -69,6 +69,10 @@ func CreateUpgradeHandler( return nil, err } + if err := migrateDelayedAckPacketIndex(ctx, keepers.DelayedAckKeeper); err != nil { + return nil, err + } + // Start running the module migrations logger.Debug("running module migrations ...") return mm.RunMigrations(ctx, configurator, fromVM) @@ -164,8 +168,8 @@ func migrateRollapps(ctx sdk.Context, rollappkeeper *rollappkeeper.Keeper) error return nil } -func migrateSequencers(ctx sdk.Context, sequencerkeeper sequencerkeeper.Keeper) { - list := sequencerkeeper.GetAllSequencers(ctx) +func migrateSequencers(ctx sdk.Context, sequencerkeeper *sequencerkeeper.Keeper) { + list := sequencerkeeper.AllSequencers(ctx) for _, oldSequencer := range list { newSequencer := ConvertOldSequencerToNew(oldSequencer) sequencerkeeper.SetSequencer(ctx, newSequencer) @@ -215,6 +219,24 @@ func migrateIncentivesParams(ctx sdk.Context, ik *incentiveskeeper.Keeper) { ik.SetParams(ctx, params) } +func migrateDelayedAckPacketIndex(ctx sdk.Context, dk delayedackkeeper.Keeper) error { + pendingPackets := dk.ListRollappPackets(ctx, delayedacktypes.ByStatus(commontypes.Status_PENDING)) + for _, packet := range pendingPackets { + pd, err := packet.GetTransferPacketData() + if err != nil { + return err + } + + switch packet.Type { + case commontypes.RollappPacket_ON_RECV: + dk.MustSetPendingPacketByAddress(ctx, pd.Receiver, packet.RollappPacketKey()) + case commontypes.RollappPacket_ON_ACK, commontypes.RollappPacket_ON_TIMEOUT: + dk.MustSetPendingPacketByAddress(ctx, pd.Sender, packet.RollappPacketKey()) + } + } + return nil +} + func ConvertOldRollappToNew(oldRollapp rollapptypes.Rollapp) rollapptypes.Rollapp { return rollapptypes.Rollapp{ RollappId: oldRollapp.RollappId, diff --git a/app/upgrades/v4/upgrade_test.go b/app/upgrades/v4/upgrade_test.go index f04b6cd85..34facd781 100644 --- a/app/upgrades/v4/upgrade_test.go +++ b/app/upgrades/v4/upgrade_test.go @@ -19,6 +19,8 @@ import ( "github.com/dymensionxyz/dymension/v3/app/apptesting" v4 "github.com/dymensionxyz/dymension/v3/app/upgrades/v4" "github.com/dymensionxyz/dymension/v3/testutil/sample" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" + delayedacktypes "github.com/dymensionxyz/dymension/v3/x/delayedack/types" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" streamertypes "github.com/dymensionxyz/dymension/v3/x/streamer/types" @@ -74,6 +76,8 @@ func (s *UpgradeTestSuite) TestUpgrade() { // Create and store sequencers s.seedAndStoreSequencers(numRollapps) + s.seedPendingRollappPackets() + return nil }, upgrade: func() { @@ -126,6 +130,11 @@ func (s *UpgradeTestSuite) TestUpgrade() { return } + // Check rollapp packets + if err = s.validateDelayedAckIndexMigration(); err != nil { + return + } + s.validateStreamerMigration() return @@ -234,7 +243,7 @@ func (s *UpgradeTestSuite) validateSequencersMigration(numSeq int) error { for i, sequencer := range testSeqs { expectSequencers[i] = v4.ConvertOldSequencerToNew(sequencer) } - sequencers := s.App.SequencerKeeper.GetAllSequencers(s.Ctx) + sequencers := s.App.SequencerKeeper.AllSequencers(s.Ctx) s.Require().Len(sequencers, len(expectSequencers)) sort.Slice(sequencers, func(i, j int) bool { @@ -247,9 +256,9 @@ func (s *UpgradeTestSuite) validateSequencersMigration(numSeq int) error { for i, sequencer := range sequencers { // check that the sequencer can be retrieved by address - _, ok := s.App.SequencerKeeper.GetSequencer(s.Ctx, sequencer.Address) - if !ok { - return fmt.Errorf("sequencer by address not migrated") + _, err := s.App.SequencerKeeper.RealSequencer(s.Ctx, sequencer.Address) + if err != nil { + return err } seq := s.App.AppCodec().MustMarshalJSON(&sequencer) @@ -260,8 +269,8 @@ func (s *UpgradeTestSuite) validateSequencersMigration(numSeq int) error { // check proposer for _, rollapp := range s.App.RollappKeeper.GetAllRollapps(s.Ctx) { - _, found := s.App.SequencerKeeper.GetProposer(s.Ctx, rollapp.RollappId) - s.Assert().True(found) + p := s.App.SequencerKeeper.GetProposer(s.Ctx, rollapp.RollappId) + s.Require().False(p.Sentinel()) } return nil @@ -282,6 +291,14 @@ func (s *UpgradeTestSuite) validateStreamerMigration() { s.Require().Equal(expected, pointers) } +func (s *UpgradeTestSuite) validateDelayedAckIndexMigration() error { + packets := s.App.DelayedAckKeeper.ListRollappPackets(s.Ctx, delayedacktypes.ByStatus(commontypes.Status_PENDING)) + actual, err := s.App.DelayedAckKeeper.GetPendingPacketsByAddress(s.Ctx, apptesting.TestPacketReceiver) + s.Require().NoError(err) + s.Require().Equal(len(packets), len(actual)) + return nil +} + func (s *UpgradeTestSuite) seedAndStoreRollapps(numRollapps int) { for _, rollapp := range s.seedRollapps(numRollapps) { s.App.RollappKeeper.SetRollapp(s.Ctx, rollapp) @@ -340,3 +357,10 @@ func (s *UpgradeTestSuite) seedSequencers(numRollapps int) []sequencertypes.Sequ func rollappIDFromIdx(idx int) string { return fmt.Sprintf("roll%spp_123%d-1", string(rune(idx+'a')), idx+1) } + +func (s *UpgradeTestSuite) seedPendingRollappPackets() { + packets := apptesting.GenerateRollappPackets(s.T(), "testrollappid_1-1", 20) + for _, packet := range packets { + s.App.DelayedAckKeeper.SetRollappPacket(s.Ctx, packet) + } +} diff --git a/go.mod b/go.mod index 3cec47b75..cf523f3ec 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/decred/dcrd/dcrec/edwards v1.0.0 github.com/dustin/go-humanize v1.0.1 github.com/dymensionxyz/gerr-cosmos v1.1.0 - github.com/dymensionxyz/sdk-utils v0.2.10 + github.com/dymensionxyz/sdk-utils v0.2.12 github.com/ethereum/go-ethereum v1.10.26 github.com/evmos/ethermint v0.22.0 github.com/gogo/protobuf v1.3.3 @@ -237,14 +237,15 @@ require ( replace ( // for collections cosmossdk.io/api => cosmossdk.io/api v0.3.1 + // use dymension forks github.com/evmos/ethermint => github.com/dymensionxyz/ethermint v0.22.0-dymension-v0.4.1.0.20241013112411-5ef491708a2d github.com/gogo/protobuf => github.com/regen-network/protobuf v1.3.3-alpha.regen.1 github.com/osmosis-labs/osmosis/osmomath => github.com/dymensionxyz/osmosis/osmomath v0.0.6-dymension-v0.1.0.20240820121212-c0e21fa21e43 - github.com/osmosis-labs/osmosis/v15 => github.com/dymensionxyz/osmosis/v15 v15.2.1-0.20241030075435-24ccb7025a59 + github.com/osmosis-labs/osmosis/v15 => github.com/dymensionxyz/osmosis/v15 v15.2.1-0.20241104151037-91342c9a4f57 // broken goleveldb github.com/syndtr/goleveldb => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - + github.com/tendermint/tendermint => github.com/cometbft/cometbft v0.34.29 golang.org/x/exp => golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb ) diff --git a/go.sum b/go.sum index c578484c6..e7d34c04f 100644 --- a/go.sum +++ b/go.sum @@ -506,10 +506,10 @@ github.com/dymensionxyz/gerr-cosmos v1.1.0 h1:IW/P7HCB/iP9kgk3VXaWUoMoyx3vD76YO6 github.com/dymensionxyz/gerr-cosmos v1.1.0/go.mod h1:n+0olxPogzWqFKba45mCpvrHLGmeS8W9UZjggHnWk6c= github.com/dymensionxyz/osmosis/osmomath v0.0.6-dymension-v0.1.0.20240820121212-c0e21fa21e43 h1:EskhZ6ILN3vwJ6l8gPWPZ49RFSB52WghT5v+pmzrNCI= github.com/dymensionxyz/osmosis/osmomath v0.0.6-dymension-v0.1.0.20240820121212-c0e21fa21e43/go.mod h1:SdGCL9CZb14twRAJUSzb7bRE0OoopRpF2Hnd1UhJpFU= -github.com/dymensionxyz/osmosis/v15 v15.2.1-0.20241030075435-24ccb7025a59 h1:xuo5OCex6XT3HmL8O9l/+jsbT0D+Ib0LzTXQbNrDOOQ= -github.com/dymensionxyz/osmosis/v15 v15.2.1-0.20241030075435-24ccb7025a59/go.mod h1:2rsnXAdjYfXtyEw0mNwAdOiAccALYjAPvINGUf9Qg7Y= -github.com/dymensionxyz/sdk-utils v0.2.10 h1:dvUVzIpsdWGr5Ex+ltl/x1Abi+7sliwsGM1xAx/0p0k= -github.com/dymensionxyz/sdk-utils v0.2.10/go.mod h1:it9owYOpnIe17+ftTATQNDN4z+mBQx20/2Jm8SK15Rk= +github.com/dymensionxyz/osmosis/v15 v15.2.1-0.20241104151037-91342c9a4f57 h1:OOf6LO3dyMp6eJTJM/of6HAVVNBR9daW9MuycPQzmfk= +github.com/dymensionxyz/osmosis/v15 v15.2.1-0.20241104151037-91342c9a4f57/go.mod h1:sXttKj99Ke160CvjID+5hvOG3TEF/K1k/Eqa37EhRCc= +github.com/dymensionxyz/sdk-utils v0.2.12 h1:wrcof+IP0AJQ7vvMRVpSekNNwa6B7ghAspHRjp/k+Lk= +github.com/dymensionxyz/sdk-utils v0.2.12/go.mod h1:it9owYOpnIe17+ftTATQNDN4z+mBQx20/2Jm8SK15Rk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= diff --git a/ibctesting/bridging_fee_test.go b/ibctesting/bridging_fee_test.go index dcc031414..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()) @@ -97,7 +102,7 @@ func (s *bridgingFeeSuite) TestBridgingFee() { s.Require().NoError(err) // manually finalize packets through x/delayedack - s.finalizeRollappPacketsByReceiver(s.hubChain().SenderAccount.GetAddress().String()) + s.finalizeRollappPacketsByAddress(s.hubChain().SenderAccount.GetAddress().String()) // check balance after finalization expectedFee := s.hubApp().DelayedAckKeeper.BridgingFeeFromAmt(s.hubCtx(), transferredCoins.Amount) @@ -105,8 +110,8 @@ func (s *bridgingFeeSuite) TestBridgingFee() { finalBalance := s.hubApp().BankKeeper.SpendableCoins(s.hubCtx(), recipient) s.Equal(expectedBalance, finalBalance) - // check fees + // check fees are burned addr := s.hubApp().AccountKeeper.GetModuleAccount(s.hubCtx(), txfees.ModuleName) txFeesBalance := s.hubApp().BankKeeper.GetBalance(s.hubCtx(), addr.GetAddress(), denom) - s.Equal(expectedFee, txFeesBalance.Amount) + s.True(txFeesBalance.IsZero()) } diff --git a/ibctesting/delayed_ack_test.go b/ibctesting/delayed_ack_test.go index 691d55821..95e7d9969 100644 --- a/ibctesting/delayed_ack_test.go +++ b/ibctesting/delayed_ack_test.go @@ -30,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, }) @@ -179,7 +181,7 @@ func (s *delayedAckSuite) TestTransferRollappToHubFinalization() { s.Require().NoError(err) // manually finalize packets through x/delayedack - s.finalizeRollappPacketsByReceiver(s.hubChain().SenderAccount.GetAddress().String()) + s.finalizeRollappPacketsByAddress(s.hubChain().SenderAccount.GetAddress().String()) // Validate ack is found found = hubIBCKeeper.ChannelKeeper.HasPacketAcknowledgement(s.hubCtx(), packet.GetDestPort(), packet.GetDestChannel(), packet.GetSequence()) @@ -235,7 +237,7 @@ func (s *delayedAckSuite) TestHubToRollappTimeout() { _, err = s.finalizeRollappState(1, currentRollappBlockHeight) s.Require().NoError(err) // manually finalize packets through x/delayedack - s.finalizeRollappPacketsByReceiver(receiverAccount.String()) + s.finalizeRollappPacketsByAddress(senderAccount.String()) // Validate funds are returned to the sender postFinalizeBalance := bankKeeper.GetBalance(s.hubCtx(), senderAccount, sdk.DefaultBondDenom) s.Require().Equal(preSendBalance.Amount, postFinalizeBalance.Amount) diff --git a/ibctesting/eibc_test.go b/ibctesting/eibc_test.go index aca048633..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, }) @@ -262,7 +264,7 @@ func (s *eibcSuite) TestEIBCDemandOrderFulfillment() { s.Require().NoError(err) // manually finalize packets through x/delayedack - s.finalizeRollappPacketsByReceiver(fulfiller.String()) + s.finalizeRollappPacketsByAddress(fulfiller.String()) // Check the fulfiller balance was updated fully with the IBC amount isUpdated := false @@ -346,7 +348,7 @@ func (s *eibcSuite) TestEIBCDemandOrderFulfillment() { s.Require().NoError(err) // manually finalize packets through x/delayedack - evts := s.finalizeRollappPacketsByReceiver(fulfiller.String()) + evts := s.finalizeRollappPacketsByAddress(fulfiller.String()) ack, err := ibctesting.ParseAckFromEvents(evts) s.Require().NoError(err) @@ -509,7 +511,7 @@ func (s *eibcSuite) TestTimeoutEIBCDemandOrderFulfillment() { _, err = s.finalizeRollappState(1, currentRollappBlockHeight) s.Require().NoError(err) // manually finalize packets through x/delayedack - s.finalizeRollappPacketsByReceiver(receiverAccount.String()) + s.finalizeRollappPacketsByAddress(fulfillerAccount.String()) // Funds are passed to the fulfiller fulfillerAccountBalanceAfterTimeout := bankKeeper.GetBalance(s.hubCtx(), fulfillerAccount, sdk.DefaultBondDenom) s.Require().True(fulfillerAccountBalanceAfterTimeout.IsEqual(fulfillerInitialBalance.Add(lastDemandOrder.Fee[0]))) diff --git a/ibctesting/genesis_bridge_test.go b/ibctesting/genesis_bridge_test.go index 552c19cda..1e999e2ab 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 diff --git a/ibctesting/light_client_test.go b/ibctesting/light_client_test.go index c04d9448a..6f30fef60 100644 --- a/ibctesting/light_client_test.go +++ b/ibctesting/light_client_test.go @@ -13,14 +13,13 @@ import ( rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ibctesting "github.com/cosmos/ibc-go/v7/testing" - sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" "github.com/stretchr/testify/suite" ) var canonicalClientConfig = ibctesting.TendermintConfig{ TrustLevel: types.DefaultExpectedCanonicalClientParams().TrustLevel, TrustingPeriod: types.DefaultExpectedCanonicalClientParams().TrustingPeriod, - UnbondingPeriod: sequencertypes.DefaultUnbondingTime, + UnbondingPeriod: types.DefaultExpectedCanonicalClientParams().UnbondingPeriod, MaxClockDrift: types.DefaultExpectedCanonicalClientParams().MaxClockDrift, } @@ -124,9 +123,7 @@ func (s *lightClientSuite) TestMsgUpdateClient_StateUpdateDoesntExist() { s.NoError(s.path.EndpointA.UpdateClient()) // As there was no stateinfo found for the height, should have accepted the update optimistically. - seqValHash, found := s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, s.path.EndpointA.GetClientState().GetLatestHeight().GetRevisionHeight()) - s.True(found) - seqAddr, err := s.hubApp().LightClientKeeper.GetSequencerFromValHash(s.hubCtx(), s.rollappChain().ChainID, seqValHash) + 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) } @@ -177,8 +174,8 @@ func (s *lightClientSuite) TestMsgUpdateClient_StateUpdateExists_Compatible() { 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 - _, found := s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) - s.False(found) + _, err = s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) + s.Error(err) } func (s *lightClientSuite) TestMsgUpdateClient_StateUpdateExists_NotCompatible() { @@ -275,8 +272,8 @@ func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_Compatibl _, err = s.path.EndpointA.Chain.SendMsgs(msg) s.NoError(err) // There should be one optimistic update for the header height - _, found := s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) - s.True(found) + _, 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(), @@ -287,8 +284,8 @@ func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_Compatibl _, 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 - _, found = s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) - s.False(found) + _, 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) @@ -332,8 +329,8 @@ func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_NotCompat _, err = s.path.EndpointA.Chain.SendMsgs(msg) s.NoError(err) // There should be one optimistic update for the header height - _, found := s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) - s.True(found) + _, 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(), diff --git a/ibctesting/utils_test.go b/ibctesting/utils_test.go index 064204c78..2e1e3e079 100644 --- a/ibctesting/utils_test.go +++ b/ibctesting/utils_test.go @@ -141,7 +141,7 @@ func (s *utilSuite) createRollapp(transfersEnabled bool, channelID *string) { X: "https://x.dymension.xyz", }, &rollapptypes.GenesisInfo{ - GenesisChecksum: "somechecksum", + GenesisChecksum: "checksum", Bech32Prefix: "ethm", NativeDenom: rollapptypes.DenomMetadata{ Display: "DEN", @@ -376,16 +376,15 @@ func (s *utilSuite) newTestChainWithSingleValidator(t *testing.T, coord *ibctest return chain } -func (s *utilSuite) finalizeRollappPacketsByReceiver(receiver string) sdk.Events { +func (s *utilSuite) finalizeRollappPacketsByAddress(address string) sdk.Events { s.T().Helper() - // Query all pending packets by receiver + // Query all pending packets by address querier := delayedackkeeper.NewQuerier(s.hubApp().DelayedAckKeeper) - resp, err := querier.GetPendingPacketsByReceiver(s.hubCtx(), &delayedacktypes.QueryPendingPacketsByReceiverRequest{ - RollappId: rollappChainID(), - Receiver: receiver, + resp, err := querier.GetPendingPacketsByAddress(s.hubCtx(), &delayedacktypes.QueryPendingPacketsByAddressRequest{ + Address: address, }) s.Require().NoError(err) - // Finalize all packets are collect events + // Finalize all packets and collect events events := make(sdk.Events, 0) for _, packet := range resp.RollappPackets { k := common.EncodePacketKey(packet.RollappPacketKey()) diff --git a/proto/dymensionxyz/dymension/delayedack/events.proto b/proto/dymensionxyz/dymension/delayedack/events.proto index b6748b1fd..7969f70df 100644 --- a/proto/dymensionxyz/dymension/delayedack/events.proto +++ b/proto/dymensionxyz/dymension/delayedack/events.proto @@ -19,28 +19,3 @@ message EventFinalizePacket { // PacketSequence is a sequence number of the packet. uint64 packet_sequence = 6; } - -message EventFinalizePacketsUntilHeight { - // Sender is the signer of the message. - string sender = 1; - // RollappID is the ID of the rollapp. - string rollapp_id = 2; - // Height is a height until which packets are to be finalized. Height is inclusive. - uint64 height = 3; - // FinalizedNum is the number of finalized packets. - uint64 finalized_num = 4; -} - -message EventFinalizeRollappPacketsByReceiver { - // Sender is the signer of the message. - string sender = 1; - // RollappID is the ID of the rollapp. - string rollapp_id = 2; - // Receiver is the one who waits tokens after the finalization. - string receiver = 3; - // Height is a height until which packets are to be finalized. - uint64 height = 4; - // FinalizedNum is the number of finalized packets. - uint64 finalized_num = 5; - -} diff --git a/proto/dymensionxyz/dymension/delayedack/query.proto b/proto/dymensionxyz/dymension/delayedack/query.proto index 32b33fc6a..d4bf62945 100644 --- a/proto/dymensionxyz/dymension/delayedack/query.proto +++ b/proto/dymensionxyz/dymension/delayedack/query.proto @@ -23,8 +23,8 @@ service Query { } // Queries a list of pending RollappPacket items by rollappID and receiver. - rpc GetPendingPacketsByReceiver(QueryPendingPacketsByReceiverRequest) returns (QueryPendingPacketByReceiverListResponse) { - option (google.api.http).get = "/dymensionxyz/dymension/delayedack/pending-receiver-packets/{rollappId}/{receiver}"; + rpc GetPendingPacketsByAddress(QueryPendingPacketsByAddressRequest) returns (QueryPendingPacketByAddressListResponse) { + option (google.api.http).get = "/dymensionxyz/dymension/delayedack/pending-receiver-packets/{address}"; } } @@ -49,13 +49,12 @@ message QueryRollappPacketListResponse { cosmos.base.query.v1beta1.PageResponse pagination = 2; } -message QueryPendingPacketsByReceiverRequest { - string rollappId = 1; - string receiver = 2; - cosmos.base.query.v1beta1.PageRequest pagination = 3; +message QueryPendingPacketsByAddressRequest { + string address = 1; + cosmos.base.query.v1beta1.PageRequest pagination = 2; } -message QueryPendingPacketByReceiverListResponse { +message QueryPendingPacketByAddressListResponse { repeated common.RollappPacket rollappPackets = 1 [(gogoproto.nullable) = false]; cosmos.base.query.v1beta1.PageResponse pagination = 2; } \ No newline at end of file diff --git a/proto/dymensionxyz/dymension/lightclient/genesis.proto b/proto/dymensionxyz/dymension/lightclient/genesis.proto index 308a1ef4c..fb0b9c3e2 100644 --- a/proto/dymensionxyz/dymension/lightclient/genesis.proto +++ b/proto/dymensionxyz/dymension/lightclient/genesis.proto @@ -5,21 +5,21 @@ import "gogoproto/gogo.proto"; option go_package = "github.com/dymensionxyz/dymension/v3/x/lightclient/types"; +// Used for genesis import/export only +message HeaderSignerEntry { + // acc addr + string sequencer_address = 1; + string client_id = 2; + uint64 height = 3; +} + + message GenesisState { repeated CanonicalClient canonical_clients = 1 [ (gogoproto.nullable) = false ]; - repeated ConsensusStateSigner consensus_state_signers = 2 [ (gogoproto.nullable) = false ]; + repeated HeaderSignerEntry header_signers = 3 [ (gogoproto.nullable) = false ]; } message CanonicalClient { string rollapp_id = 1; string ibc_client_id = 2; } - -message ConsensusStateSigner { - // ibc_client_id is the canonical IBC client which has accepted a client update optimistically - string ibc_client_id = 1; - // height is the client height which was updated optimistically - uint64 height = 2; - // blockValHash is the valhash of the block which was updated optimistically - string blockValHash = 3; -} \ No newline at end of file diff --git a/proto/dymensionxyz/dymension/rollapp/genesis.proto b/proto/dymensionxyz/dymension/rollapp/genesis.proto index b9cc9ed19..6e179295c 100644 --- a/proto/dymensionxyz/dymension/rollapp/genesis.proto +++ b/proto/dymensionxyz/dymension/rollapp/genesis.proto @@ -22,6 +22,14 @@ message GenesisState { repeated LivenessEvent livenessEvents = 7 [(gogoproto.nullable) = false]; 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; +} + +message SequencerHeightPair { + string sequencer = 1; // sequencer addr to lookup in x/sequencer + uint64 height = 2; // rollapp chain height } message RollappRegisteredDenoms { diff --git a/proto/dymensionxyz/dymension/rollapp/liveness.proto b/proto/dymensionxyz/dymension/rollapp/liveness.proto index e9693e2a9..8f391fe7b 100644 --- a/proto/dymensionxyz/dymension/rollapp/liveness.proto +++ b/proto/dymensionxyz/dymension/rollapp/liveness.proto @@ -8,10 +8,9 @@ import "cosmos/base/v1beta1/coin.proto"; // LivenessEvent stores upcoming slash/jail actions on sequencers of rollapps message LivenessEvent { + reserved 3; // RollappId of relevant rollapp string rollapp_id = 1; // HubHeight when event will occur int64 hub_height = 2; - // IsJail is true iff the event is to jail rather than slash - bool is_jail = 3; } \ No newline at end of file diff --git a/proto/dymensionxyz/dymension/rollapp/params.proto b/proto/dymensionxyz/dymension/rollapp/params.proto index 7348d6e10..1dff15bca 100644 --- a/proto/dymensionxyz/dymension/rollapp/params.proto +++ b/proto/dymensionxyz/dymension/rollapp/params.proto @@ -16,14 +16,12 @@ message Params { uint64 dispute_period_in_blocks = 1 [ (gogoproto.moretags) = "yaml:\"dispute_period_in_blocks\"" ]; - reserved 2,3; + reserved 2,3,6; // The time (num hub blocks) a sequencer has to post a block, before he will be slashed uint64 liveness_slash_blocks = 4 [(gogoproto.moretags) = "yaml:\"liveness_slash_blocks\""]; // The min gap (num hub blocks) between a sequence of slashes if the sequencer continues to be down uint64 liveness_slash_interval = 5 [(gogoproto.moretags) = "yaml:\"liveness_slash_interval\""]; - // The time (num hub blocks) a sequencer can be down after which he will be jailed rather than slashed - uint64 liveness_jail_blocks = 6 [(gogoproto.moretags) = "yaml:\"liveness_jail_blocks\""]; // app_registration_fee is the fee for registering an App cosmos.base.v1beta1.Coin app_registration_fee = 7 [ (gogoproto.nullable) = false, diff --git a/proto/dymensionxyz/dymension/sequencer/events.proto b/proto/dymensionxyz/dymension/sequencer/events.proto index 9fdb5cd3b..ad22aca37 100644 --- a/proto/dymensionxyz/dymension/sequencer/events.proto +++ b/proto/dymensionxyz/dymension/sequencer/events.proto @@ -10,12 +10,12 @@ option go_package = "github.com/dymensionxyz/dymension/v3/x/sequencer/types"; // EventIncreasedBond is an event emitted when a sequencer's bond is increased. message EventIncreasedBond { - // sequencer is the bech32-encoded address of the sequencer which increased its bond - string sequencer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; - // added_amount is the amount of coins added to the sequencer's bond - cosmos.base.v1beta1.Coin added_amount = 2 [(gogoproto.nullable) = false]; - // bond is the new active bond amount of the sequencer - repeated cosmos.base.v1beta1.Coin bond = 3 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; + // sequencer is the bech32-encoded address of the sequencer + string sequencer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // added_amount is the amount of coins added to the sequencer's bond + cosmos.base.v1beta1.Coin added_amount = 2 [(gogoproto.nullable) = false]; + // bond is the new active bond amount of the sequencer + repeated cosmos.base.v1beta1.Coin bond = 3 [(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"]; } message EventUpdateRewardAddress { @@ -30,4 +30,32 @@ message EventUpdateWhitelistedRelayers { string creator = 1; // Relayers is an array of the whitelisted relayer addresses. Addresses are bech32-encoded strings. repeated string relayers = 2; -} \ No newline at end of file +} + + +// On a sequencer kicking the incumbent proposer +message EventKickedProposer { + string rollapp = 3; + // Kicker is the bech32-encoded address of the sequencer who triggered the kick + string kicker = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // Proposer is the bech32-encoded address of the proposer who was kicked + string proposer = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// Whenever the proposer changes to a new proposer +message EventProposerChange { + string rollapp = 3; + // Before is the bech32-encoded address of the old proposer + string before = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + // After is the bech32-encoded address of the new proposer + string after = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; +} + +// When a sequencer opt-in status changes +message EventOptInStatusChange { + string rollapp = 3; + // Sequencer is the bech32-encoded address of the old proposer + string sequencer = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; + bool before = 2; + bool after = 4 ; +} diff --git a/proto/dymensionxyz/dymension/sequencer/genesis.proto b/proto/dymensionxyz/dymension/sequencer/genesis.proto index ddfba68a0..52f2646c7 100644 --- a/proto/dymensionxyz/dymension/sequencer/genesis.proto +++ b/proto/dymensionxyz/dymension/sequencer/genesis.proto @@ -7,6 +7,7 @@ import "dymensionxyz/dymension/sequencer/sequencer.proto"; option go_package = "github.com/dymensionxyz/dymension/v3/x/sequencer/types"; + // GenesisState defines the sequencer module's genesis state. message GenesisState { Params params = 1 [ (gogoproto.nullable) = false ]; @@ -15,11 +16,15 @@ message GenesisState { // genesisProposers is a list of the defined genesis proposers repeated GenesisProposer genesisProposers = 3 [ (gogoproto.nullable) = false ]; - // bondReductions is a list of all bond reductions - repeated BondReduction bondReductions = 4 [(gogoproto.nullable) = false]; + // genesisSuccessor is a list of the defined genesis proposers + repeated GenesisProposer genesisSuccessors = 5 + [ (gogoproto.nullable) = false ]; + // list of sequencers in the notice queue + repeated string noticeQueue = 4 [ (gogoproto.nullable) = false ]; } message GenesisProposer { string address = 1; string rollappId = 2; -} \ No newline at end of file +} + diff --git a/proto/dymensionxyz/dymension/sequencer/operating_status.proto b/proto/dymensionxyz/dymension/sequencer/operating_status.proto index 0ce95c1e1..7315b0688 100644 --- a/proto/dymensionxyz/dymension/sequencer/operating_status.proto +++ b/proto/dymensionxyz/dymension/sequencer/operating_status.proto @@ -6,14 +6,12 @@ option go_package = "github.com/dymensionxyz/dymension/v3/x/sequencer/types"; // OperatingStatus defines the operating status of a sequencer enum OperatingStatus { + reserved 1; option (gogoproto.goproto_enum_prefix) = false; // OPERATING_STATUS_UNBONDED defines a sequencer that is not active and won't // be scheduled OPERATING_STATUS_UNBONDED = 0 [ (gogoproto.enumvalue_customname) = "Unbonded" ]; - // UNBONDING defines a sequencer that is currently unbonding. - OPERATING_STATUS_UNBONDING = 1 - [ (gogoproto.enumvalue_customname) = "Unbonding" ]; // OPERATING_STATUS_BONDED defines a sequencer that is bonded and can be // scheduled OPERATING_STATUS_BONDED = 2 [ (gogoproto.enumvalue_customname) = "Bonded" ]; diff --git a/proto/dymensionxyz/dymension/sequencer/params.proto b/proto/dymensionxyz/dymension/sequencer/params.proto index 5c276d59b..c87385e4f 100644 --- a/proto/dymensionxyz/dymension/sequencer/params.proto +++ b/proto/dymensionxyz/dymension/sequencer/params.proto @@ -12,14 +12,18 @@ message Params { option (gogoproto.equal) = true; option (gogoproto.goproto_stringer) = false; + // minimum amt that must be put up for stake to be sequencer cosmos.base.v1beta1.Coin min_bond = 1 [ (gogoproto.nullable) = false, (gogoproto.jsontag) = "min_bond,omitempty" ]; - // unbonding_time is the time duration of unbonding. - google.protobuf.Duration unbonding_time = 2 - [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + // amt where the active sequencer can be kicked if he has less or equal bond + cosmos.base.v1beta1.Coin kick_threshold = 5 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "kick_threshold,omitempty" + ]; + reserved 2; // notice_period is the time duration of notice period. // notice period is the duration between the unbond request and the actual @@ -27,10 +31,15 @@ message Params { google.protobuf.Duration notice_period = 3 [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; - // LivenessSlashMultiplier multiplies with the tokens of the slashed sequencer to compute the burn amount. - string liveness_slash_multiplier = 4 [ + // liveness_slash_min_multiplier multiplies with the tokens of the slashed sequencer to compute the burn amount. + string liveness_slash_min_multiplier = 4 [ (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.moretags) = "yaml:\"liveness_slash_multiplier\"", (gogoproto.nullable) = false ]; + // liveness_slash_min_absolute is the absolute minimum to slash for liveness + cosmos.base.v1beta1.Coin liveness_slash_min_absolute = 6 [ + (gogoproto.nullable) = false, + (gogoproto.jsontag) = "liveness_slash_min_absolute,omitempty" + ]; } \ No newline at end of file diff --git a/proto/dymensionxyz/dymension/sequencer/sequencer.proto b/proto/dymensionxyz/dymension/sequencer/sequencer.proto index a0192d0a4..23f400cfb 100644 --- a/proto/dymensionxyz/dymension/sequencer/sequencer.proto +++ b/proto/dymensionxyz/dymension/sequencer/sequencer.proto @@ -16,35 +16,35 @@ import "dymensionxyz/dymension/sequencer/operating_status.proto"; // Sequencer defines a sequencer identified by its' address (sequencerAddress). // The sequencer could be attached to only one rollapp (rollappId). message Sequencer { - // address is the bech32-encoded address of the sequencer account which is the account that the message was sent from. + reserved 5,9,10; + + // Address is the bech32-encoded address of the sequencer account which is the account that the message was sent from. string address = 1; - // pubkey is the public key of the sequencers' dymint client, as a Protobuf Any. + // DymintPubKey is the public key of the sequencers' dymint client, as a Protobuf Any. google.protobuf.Any dymintPubKey = 2 [(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey"]; - // rollappId defines the rollapp to which the sequencer belongs. + // RollappId defines the rollapp to which the sequencer belongs. string rollappId = 3; - // metadata defines the extra information for the sequencer. + // SequencerMetadata defines the extra information for the sequencer. SequencerMetadata metadata = 4 [(gogoproto.nullable) = false]; - // jailed defined whether the sequencer has been jailed from bonded status or not. - bool jailed = 5; - + bool proposer = 6 [deprecated = true]; - // status is the sequencer status (bonded/unbonding/unbonded). + // OperatingStatus is the sequencer status (bonded/unbonded). OperatingStatus status = 7; - // tokens define the delegated tokens (incl. self-delegation). + + // OptedIn : when true and bonded, the sequencer can be chosen as proposer or successor + // has no effect if already proposer or successor + bool opted_in = 14; + + // Tokens: A coins which should always be one dym coin. It's the amount of tokens the sequencer has given to the module. repeated cosmos.base.v1beta1.Coin tokens = 8 [ (gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; - // unbond_request_height stores the height at which this sequencer has - // requested to unbond. - int64 unbond_request_height = 9; - // unbond_time defines the time when the sequencer will complete unbonding. - google.protobuf.Timestamp unbond_time = 10 - [ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ]; - // notice_period_time defines the time when the sequencer will finish it's notice period if started + + // NoticePeriodTime defines the time when the sequencer will finish it's notice period. Zero means not started. google.protobuf.Timestamp notice_period_time = 11 [ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ]; @@ -54,12 +54,3 @@ message Sequencer { repeated string whitelisted_relayers = 13; } -// BondReduction defines an object which holds the information about the sequencer and its queued unbonding amount -message BondReduction { - // sequencer_address is the bech32-encoded address of the sequencer account which is the account that the message was sent from. - string sequencer_address = 1; - // decrease_bond_amount is the amount of tokens to be unbonded. - cosmos.base.v1beta1.Coin decrease_bond_amount = 2 [(gogoproto.nullable) = false]; - // decrease_bond_time defines, if unbonding, the min time for the sequencer to complete unbonding. - google.protobuf.Timestamp decrease_bond_time = 3 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; -} diff --git a/proto/dymensionxyz/dymension/sequencer/tx.proto b/proto/dymensionxyz/dymension/sequencer/tx.proto index 49858ec67..90d1a8d29 100644 --- a/proto/dymensionxyz/dymension/sequencer/tx.proto +++ b/proto/dymensionxyz/dymension/sequencer/tx.proto @@ -25,6 +25,11 @@ service Msg { rpc UpdateRewardAddress(MsgUpdateRewardAddress) returns (MsgUpdateRewardAddressResponse); // UpdateWhitelistedRelayers defines a method for updating the sequencer's whitelisted relater list. rpc UpdateWhitelistedRelayers(MsgUpdateWhitelistedRelayers) returns (MsgUpdateWhitelistedRelayersResponse); + // UpdateOptInStatus allows toggling optedIn bool + // NOTE: arguably should have just used UpdateSequencerInformation instead of having a new message, but want to avoid changing + // frontends last minute. + rpc UpdateOptInStatus (MsgUpdateOptInStatus) returns (MsgUpdateOptInStatus); + rpc KickProposer (MsgKickProposer) returns (MsgKickProposerResponse); // Unbond defines a method for removing coins from sequencer's bond rpc Unbond (MsgUnbond) returns (MsgUnbondResponse); // IncreaseBond defines a method for increasing a sequencer's bond amount @@ -76,6 +81,15 @@ message MsgCreateSequencer { message MsgCreateSequencerResponse {} +// Try to kick the current proposer whose bond is below kick threshold +message MsgKickProposer { + option (cosmos.msg.v1.signer) = "creator"; + // creator is the bech32-encoded address of the sequencer account which is the account that the message was sent from. + string creator = 1; +} + +message MsgKickProposerResponse {} + message MsgUpdateSequencerInformation { option (cosmos.msg.v1.signer) = "creator"; // creator is the bech32-encoded address of the sequencer account which is the account that the message was sent from. @@ -106,6 +120,18 @@ message MsgUpdateWhitelistedRelayers { message MsgUpdateWhitelistedRelayersResponse {} +message MsgUpdateOptInStatus { + option (cosmos.msg.v1.signer) = "creator"; + // creator is the bech32-encoded address of the sequencer account which is the account that the message was sent from. + string creator = 1; + // OptedIn : the new value + bool opted_in = 2; +} + +message MsgUpdateOptInStatusResponse {} + + + // MsgUnbond defines a SDK message for performing an undelegation from a // bond and a sequencer. message MsgUnbond { @@ -116,11 +142,9 @@ message MsgUnbond { // MsgUnbondResponse defines the Msg/Unbond response type. message MsgUnbondResponse { - // completion_time defines the time at which the unbonding will be completed. // If unbonding the proposer, the completion time is the time at which the notice period will be completed. - oneof completion_time { - // unbonding_completion_time is the time at which the unbonding will be completed. - google.protobuf.Timestamp unbonding_completion_time = 1 [ (gogoproto.stdtime) = true]; + reserved 1; + oneof completion_time { // NOTE: oneof for legacy reasons. // notice_period_completion_time is the time at which the notice period will be completed. google.protobuf.Timestamp notice_period_completion_time = 2 [ (gogoproto.stdtime) = true]; } @@ -151,5 +175,5 @@ message MsgDecreaseBond { // MsgDecreaseBondResponse defines the Msg/DecreaseBond response type. message MsgDecreaseBondResponse { - google.protobuf.Timestamp completion_time = 1 [(gogoproto.nullable) = false, (gogoproto.stdtime) = true]; + reserved 1; } diff --git a/testutil/keeper/dymns.go b/testutil/keeper/dymns.go index 76856a7c2..f3ebd8d00 100644 --- a/testutil/keeper/dymns.go +++ b/testutil/keeper/dymns.go @@ -95,6 +95,7 @@ func DymNSKeeper(t testing.TB) (dymnskeeper.Keeper, dymnstypes.BankKeeper, rolla rollappParamsSubspace, nil, nil, nil, nil, bankKeeper, + nil, authtypes.NewModuleAddress(govtypes.ModuleName).String(), nil, ) diff --git a/testutil/keeper/iro.go b/testutil/keeper/iro.go index 72428b5e4..89cee3360 100644 --- a/testutil/keeper/iro.go +++ b/testutil/keeper/iro.go @@ -11,9 +11,10 @@ import ( "github.com/cosmos/cosmos-sdk/store" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/require" + "github.com/dymensionxyz/dymension/v3/x/iro/keeper" "github.com/dymensionxyz/dymension/v3/x/iro/types" - "github.com/stretchr/testify/require" ) func IROKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { @@ -38,6 +39,7 @@ func IROKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { nil, nil, nil, + nil, ) ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/lightclient.go b/testutil/keeper/lightclient.go index bf1ccf165..8a686ca12 100644 --- a/testutil/keeper/lightclient.go +++ b/testutil/keeper/lightclient.go @@ -1,6 +1,7 @@ package keeper import ( + "bytes" "context" "testing" "time" @@ -8,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" "github.com/cosmos/cosmos-sdk/store" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -19,6 +21,7 @@ import ( "github.com/dymensionxyz/dymension/v3/x/lightclient/types" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" cometbftdb "github.com/cometbft/cometbft-db" "github.com/cometbft/cometbft/libs/log" @@ -28,9 +31,17 @@ import ( ) const ( - Alice = "dym1wg8p6j0pxpnsvhkwfu54ql62cnrumf0v634mft" + CanonClientID = "canon" + DefaultRollapp = "default" ) +var Alice = func() sequencertypes.Sequencer { + ret := sequencertypes.NewTestSequencer(ed25519.GenPrivKey().PubKey()) + ret.Status = sequencertypes.Bonded + ret.RollappId = DefaultRollapp + return ret +}() + func LightClientKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { storeKey := sdk.NewKVStoreKey(types.StoreKey) memStoreKey := storetypes.NewMemoryStoreKey(types.StoreKey + "_mem") @@ -43,25 +54,16 @@ func LightClientKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { registry := codectypes.NewInterfaceRegistry() cdc := codec.NewProtoCodec(registry) - sequencerPubKey := ed25519.GenPrivKey().PubKey() - tmPk, err := codectypes.NewAnyWithValue(sequencerPubKey) - require.NoError(t, err) - testSequencer := sequencertypes.Sequencer{ - Address: Alice, - DymintPubKey: tmPk, - } - nextValHash, err := testSequencer.GetDymintPubKeyHash() - require.NoError(t, err) - testSequencers := map[string]sequencertypes.Sequencer{ - Alice: testSequencer, + seqs := map[string]*sequencertypes.Sequencer{ + Alice.Address: &Alice, } - testConsensusStates := map[string]map[uint64]exported.ConsensusState{ - "canon-client-id": { + consStates := map[string]map[uint64]exported.ConsensusState{ + CanonClientID: { 2: &ibctm.ConsensusState{ Timestamp: time.Unix(1724392989, 0), Root: commitmenttypes.NewMerkleRoot([]byte("test2")), - NextValidatorsHash: nextValHash, + NextValidatorsHash: Alice.MustValsetHash(), }, }, } @@ -70,12 +72,12 @@ func LightClientKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { time.Hour*24*7*2, time.Hour*24*7*3, time.Minute*10, ibcclienttypes.MustParseHeight("1-2"), commitmenttypes.GetSDKSpecs(), []string{}, ) - testGenesisClients := map[string]exported.ClientState{ - "canon-client-id": cs, + genesisClients := map[string]exported.ClientState{ + CanonClientID: cs, } - mockIBCKeeper := NewMockIBCClientKeeper(testConsensusStates, testGenesisClients) - mockSequencerKeeper := NewMockSequencerKeeper(testSequencers) + mockIBCKeeper := NewMockIBCClientKeeper(consStates, genesisClients) + mockSequencerKeeper := NewMockSequencerKeeper(seqs) mockRollappKeeper := NewMockRollappKeeper() k := keeper.NewKeeper( cdc, @@ -138,39 +140,44 @@ func (m *MockIBCCLientKeeper) ConsensusStateHeights(c context.Context, req *ibcc } type MockSequencerKeeper struct { - sequencers map[string]sequencertypes.Sequencer -} - -// GetProposer implements types.SequencerKeeperExpected. -func (m *MockSequencerKeeper) GetProposer(ctx sdk.Context, rollappId string) (val sequencertypes.Sequencer, found bool) { - panic("unimplemented") -} - -func (m *MockSequencerKeeper) UnbondingTime(ctx sdk.Context) (res time.Duration) { - return types.DefaultExpectedCanonicalClientParams().UnbondingPeriod + sequencers map[string]*sequencertypes.Sequencer } -func NewMockSequencerKeeper(sequencers map[string]sequencertypes.Sequencer) *MockSequencerKeeper { - return &MockSequencerKeeper{ - sequencers: sequencers, +func (m *MockSequencerKeeper) SequencerByDymintAddr(ctx sdk.Context, addr cryptotypes.Address) (sequencertypes.Sequencer, error) { + for _, s := range m.sequencers { + if bytes.Equal(s.MustProposerAddr(), addr) { + return *s, nil + } } + return sequencertypes.Sequencer{}, gerrc.ErrNotFound } -func (m *MockSequencerKeeper) GetSequencer(ctx sdk.Context, seqAddr string) (sequencertypes.Sequencer, bool) { - seq, ok := m.sequencers[seqAddr] - return seq, ok +func (m *MockSequencerKeeper) RealSequencer(ctx sdk.Context, addr string) (sequencertypes.Sequencer, error) { + seq, ok := m.sequencers[addr] + var err error + if !ok { + err = gerrc.ErrNotFound + } + return *seq, err } -func (m *MockSequencerKeeper) GetSequencersByRollapp(ctx sdk.Context, rollappId string) (list []sequencertypes.Sequencer) { +func (m *MockSequencerKeeper) RollappSequencers(ctx sdk.Context, rollappId string) (list []sequencertypes.Sequencer) { seqs := make([]sequencertypes.Sequencer, 0, len(m.sequencers)) for _, seq := range m.sequencers { - seqs = append(seqs, seq) + seqs = append(seqs, *seq) } return seqs } -func (m *MockSequencerKeeper) JailSequencerOnFraud(ctx sdk.Context, seqAddr string) error { - return nil +// 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 { + return &MockSequencerKeeper{ + sequencers: sequencers, + } } type MockRollappKeeper struct{} diff --git a/testutil/keeper/rollapp.go b/testutil/keeper/rollapp.go index 318be9ccb..a5887650b 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, authtypes.NewModuleAddress(govtypes.ModuleName).String(), nil) + k := keeper.NewKeeper(cdc, storeKey, paramsSubspace, nil, nil, nil, nil, nil, nil, authtypes.NewModuleAddress(govtypes.ModuleName).String(), nil) ctx := sdk.NewContext(stateStore, cometbftproto.Header{}, false, log.NewNopLogger()) diff --git a/testutil/keeper/sequencer.go b/testutil/keeper/sequencer.go index 56cb3722b..077af5ca1 100644 --- a/testutil/keeper/sequencer.go +++ b/testutil/keeper/sequencer.go @@ -13,6 +13,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/dymensionxyz/dymension/v3/testutil/sample" rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" @@ -31,6 +32,7 @@ func SequencerKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { registry := codectypes.NewInterfaceRegistry() cdc := codec.NewProtoCodec(registry) + cryptocodec.RegisterInterfaces(registry) k := keeper.NewKeeper( cdc, diff --git a/utils/denom/ibc.go b/utils/denom/ibc.go new file mode 100644 index 000000000..4f0f8ca6e --- /dev/null +++ b/utils/denom/ibc.go @@ -0,0 +1,37 @@ +package denom + +import ( + "strings" + + transferTypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" +) + +// ValidateIBCDenom validates that the given denomination is a valid fungible token representation (i.e 'ibc/{hash}') +// per ADR 001 https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-001-coin-source-tracing.md. +// If the denom is valid, return its hash-string part. Inspired by +// https://github.com/cosmos/ibc-go/blob/5d7655684554e4f577be9573ef94ef4ad6c82667/modules/apps/transfer/types/denom.go#L190. +func ValidateIBCDenom(denom string) (string, bool) { + denomSplit := strings.SplitN(denom, "/", 2) + + if len(denomSplit) == 2 && denomSplit[0] == transferTypes.DenomPrefix && strings.TrimSpace(denomSplit[1]) != "" { + return denomSplit[1], true + } + + return "", false +} + +// SourcePortChanFromTracePath extracts source port and channel from the provided IBC denom trace path. +// References: +// - https://github.com/cosmos/ibc-go/blob/main/docs/architecture/adr-001-coin-source-tracing.md +// - https://github.com/cosmos/relayer/issues/288 +func SourcePortChanFromTracePath(tracePath string) (sourcePort, sourceChannel string, validTrace bool) { + sp := strings.Split(tracePath, "/") + if len(sp) < 2 { + return "", "", false + } + sourcePort, sourceChannel = sp[len(sp)-2], sp[len(sp)-1] + if sourcePort == "" || sourceChannel == "" { + return "", "", false + } + return sourcePort, sourceChannel, true +} diff --git a/utils/denom/ibc_test.go b/utils/denom/ibc_test.go new file mode 100644 index 000000000..17895b9c6 --- /dev/null +++ b/utils/denom/ibc_test.go @@ -0,0 +1,40 @@ +package denom_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/dymensionxyz/dymension/v3/utils/denom" +) + +func TestSourcePortChanFromTracePath(t *testing.T) { + testCases := []struct { + name string + trace string + expValid bool + expPort string + expChan string + }{ + {"invalid: empty trace", "", false, "", ""}, + {"invalid: only port", "transfer", false, "", ""}, + {"invalid: only port with '/'", "transfer/", false, "", ""}, + {"invalid: only channel with '/'", "/channel-1", false, "", ""}, + {"invalid: only '/'", "/", false, "", ""}, + {"invalid: double '/'", "transfer//channel-1", false, "", ""}, + {"valid trace", "transfer/channel-1", true, "transfer", "channel-1"}, + {"valid trace with multiple port/channel pairs", "transfer/channel-1/transfer/channel-2", true, "transfer", "channel-2"}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + port, channel, valid := denom.SourcePortChanFromTracePath(tc.trace) + + require.Equal(t, tc.expValid, valid) + if tc.expValid { + require.Equal(t, tc.expPort, port) + require.Equal(t, tc.expChan, channel) + } + }) + } +} diff --git a/x/bridgingfee/ibc_module.go b/x/bridgingfee/ibc_module.go index 43ebfb3d0..c246d0db4 100644 --- a/x/bridgingfee/ibc_module.go +++ b/x/bridgingfee/ibc_module.go @@ -10,6 +10,8 @@ import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" "github.com/dymensionxyz/sdk-utils/utils/uevent" + "github.com/dymensionxyz/sdk-utils/utils/uibc" + txfeeskeeper "github.com/osmosis-labs/osmosis/v15/x/txfees/keeper" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" delayedackkeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" @@ -29,22 +31,25 @@ type IBCModule struct { rollappKeeper rollappkeeper.Keeper delayedAckKeeper delayedackkeeper.Keeper transferKeeper transferkeeper.Keeper + txFeesKeeper txfeeskeeper.Keeper feeModuleAddr sdk.AccAddress } func NewIBCModule( next ibctransfer.IBCModule, - keeper delayedackkeeper.Keeper, + rollappKeeper rollappkeeper.Keeper, + delayedAckKeeper delayedackkeeper.Keeper, transferKeeper transferkeeper.Keeper, + txFeesKeeper txfeeskeeper.Keeper, feeModuleAddr sdk.AccAddress, - rollappKeeper rollappkeeper.Keeper, ) *IBCModule { return &IBCModule{ IBCModule: next, - delayedAckKeeper: keeper, + rollappKeeper: rollappKeeper, + delayedAckKeeper: delayedAckKeeper, transferKeeper: transferKeeper, + txFeesKeeper: txFeesKeeper, feeModuleAddr: feeModuleAddr, - rollappKeeper: rollappKeeper, } } @@ -90,9 +95,20 @@ func (w *IBCModule) OnRecvPacket(ctx sdk.Context, packet channeltypes.Packet, re err = w.transferKeeper.OnRecvPacket(ctx, packet, feeData.FungibleTokenPacketData) if err != nil { l.Error("Charge bridging fee.", "err", err) - // we continue as we don't want the fee charge to fail the transfer in any case + // We continue as we don't want the fee charge to fail the transfer in any case fee = sdk.ZeroInt() } else { + // Charge the fee from the txfees module account: construct the IBC denom and use it for the fee coin. + denomTrace := uibc.GetForeignDenomTrace(packet.GetDestChannel(), feeData.Denom) + feeCoin := sdk.NewCoin(denomTrace.IBCDenom(), fee) + + err = w.txFeesKeeper.ChargeFees(ctx, feeCoin, nil, transfer.Receiver) + if err != nil { + // We continue as we don't want the fee charge to fail the transfer in any case. + // Also, the fee was already successfully sent to x/txfees and charging will be retried at the epoch end. + w.logger(ctx, packet, "OnRecvPacket").Error("Charge bridging fee from x/txfees account.", "err", err) + } + ctx.EventManager().EmitEvent( sdk.NewEvent( EventTypeBridgingFee, diff --git a/x/common/types/events.go b/x/common/types/events.go index 4d19492de..8e383a998 100644 --- a/x/common/types/events.go +++ b/x/common/types/events.go @@ -1,7 +1,7 @@ package types +// RollappPacket attributes const ( - // RollappPacket events AttributeKeyRollappId = "rollapp_id" AttributeKeyPacketStatus = "status" AttributeKeyPacketSourcePort = "source_port" @@ -9,5 +9,17 @@ const ( AttributeKeyPacketDestinationPort = "destination_port" AttributeKeyPacketDestinationChannel = "destination_channel" AttributeKeyPacketSequence = "packet_sequence" + AttributeKeyPacketProofHeight = "proof_height" + AttributeKeyPacketType = "type" + AttributeKeyPacketAcknowledgement = "acknowledgement" AttributeKeyPacketError = "error" ) + +// FungibleTokenPacketData attributes +const ( + AttributeKeyPacketDataDenom = "packet_data_denom" + AttributeKeyPacketDataAmount = "packet_data_amount" + AttributeKeyPacketDataSender = "packet_data_sender" + AttributeKeyPacketDataReceiver = "packet_data_receiver" + AttributeKeyPacketDataMemo = "packet_data_memo" +) diff --git a/x/common/types/rollapp_packet.go b/x/common/types/rollapp_packet.go index e1267b1b5..832ccbe2e 100644 --- a/x/common/types/rollapp_packet.go +++ b/x/common/types/rollapp_packet.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" + channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" ) func (r RollappPacket) LogString() string { @@ -38,6 +39,26 @@ func (r RollappPacket) ValidateBasic() error { } func (r RollappPacket) GetEvents() []sdk.Attribute { + var pd transfertypes.FungibleTokenPacketData + if len(r.Packet.Data) != 0 { + // It's okay if we can't get packet data + pd, _ = r.GetTransferPacketData() + } + + acknowledgement := "none" + if len(r.Acknowledgement) != 0 { + ack, err := r.GetAck() + // It's okay if we can't get acknowledgement + if err == nil { + switch ack.GetResponse().(type) { + case *channeltypes.Acknowledgement_Result: + acknowledgement = "success" + case *channeltypes.Acknowledgement_Error: + acknowledgement = "error" + } + } + } + eventAttributes := []sdk.Attribute{ sdk.NewAttribute(AttributeKeyRollappId, r.RollappId), sdk.NewAttribute(AttributeKeyPacketStatus, r.Status.String()), @@ -46,6 +67,14 @@ func (r RollappPacket) GetEvents() []sdk.Attribute { sdk.NewAttribute(AttributeKeyPacketDestinationPort, r.Packet.DestinationPort), sdk.NewAttribute(AttributeKeyPacketDestinationChannel, r.Packet.DestinationChannel), sdk.NewAttribute(AttributeKeyPacketSequence, strconv.FormatUint(r.Packet.Sequence, 10)), + sdk.NewAttribute(AttributeKeyPacketProofHeight, strconv.FormatUint(r.ProofHeight, 10)), + sdk.NewAttribute(AttributeKeyPacketType, r.Type.String()), + sdk.NewAttribute(AttributeKeyPacketAcknowledgement, acknowledgement), + sdk.NewAttribute(AttributeKeyPacketDataDenom, pd.Denom), + sdk.NewAttribute(AttributeKeyPacketDataAmount, pd.Amount), + sdk.NewAttribute(AttributeKeyPacketDataSender, pd.Sender), + sdk.NewAttribute(AttributeKeyPacketDataReceiver, pd.Receiver), + sdk.NewAttribute(AttributeKeyPacketDataMemo, pd.Memo), } if r.Error != "" { eventAttributes = append(eventAttributes, sdk.NewAttribute(AttributeKeyPacketError, r.Error)) @@ -62,6 +91,22 @@ func (r RollappPacket) GetTransferPacketData() (transfertypes.FungibleTokenPacke return data, nil } +func (r RollappPacket) MustGetTransferPacketData() transfertypes.FungibleTokenPacketData { + data, err := r.GetTransferPacketData() + if err != nil { + panic(err) + } + return data +} + +func (r RollappPacket) GetAck() (channeltypes.Acknowledgement, error) { + var ack channeltypes.Acknowledgement + if err := transfertypes.ModuleCdc.UnmarshalJSON(r.Acknowledgement, &ack); err != nil { + return channeltypes.Acknowledgement{}, err + } + return ack, nil +} + func (r RollappPacket) RestoreOriginalTransferTarget() (RollappPacket, error) { transferPacketData, err := r.GetTransferPacketData() if err != nil { diff --git a/x/delayedack/client/cli/query.go b/x/delayedack/client/cli/query.go index 3779759d9..0cf9025f1 100644 --- a/x/delayedack/client/cli/query.go +++ b/x/delayedack/client/cli/query.go @@ -27,7 +27,7 @@ func GetQueryCmd() *cobra.Command { cmd.AddCommand(CmdGetPacketsByRollapp()) cmd.AddCommand(CmdGetPacketsByStatus()) cmd.AddCommand(CmdGetPacketsByType()) - cmd.AddCommand(CmdGetPendingPacketsByReceiver()) + cmd.AddCommand(CmdGetPendingPacketsByAddress()) return cmd } @@ -219,11 +219,11 @@ func CmdGetPacketsByType() *cobra.Command { return cmd } -func CmdGetPendingPacketsByReceiver() *cobra.Command { +func CmdGetPendingPacketsByAddress() *cobra.Command { cmd := &cobra.Command{ - Use: "pending-packets-by-receiver [rollapp-id] [receiver]", - Short: "Get pending packets by receiver", - Args: cobra.MinimumNArgs(2), + Use: "pending-packets-by-address [address]", + Short: "Get pending packets by address", + Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { @@ -231,9 +231,8 @@ func CmdGetPendingPacketsByReceiver() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) - res, err := queryClient.GetPendingPacketsByReceiver(cmd.Context(), &types.QueryPendingPacketsByReceiverRequest{ - RollappId: args[0], - Receiver: args[1], + res, err := queryClient.GetPendingPacketsByAddress(cmd.Context(), &types.QueryPendingPacketsByAddressRequest{ + Address: args[0], Pagination: nil, // TODO: handle pagination }) if err != nil { diff --git a/x/delayedack/genesis.go b/x/delayedack/genesis.go index a10edd4e3..d451b59df 100644 --- a/x/delayedack/genesis.go +++ b/x/delayedack/genesis.go @@ -2,6 +2,8 @@ package delayedack import ( sdk "github.com/cosmos/cosmos-sdk/types" + + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" ) @@ -10,6 +12,15 @@ import ( func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { k.SetParams(ctx, genState.Params) for _, packet := range genState.RollappPackets { + transferPacketData := packet.MustGetTransferPacketData() + switch packet.Type { + case commontypes.RollappPacket_ON_RECV: + k.MustSetPendingPacketByAddress(ctx, transferPacketData.Receiver, packet.RollappPacketKey()) + case commontypes.RollappPacket_ON_ACK, commontypes.RollappPacket_ON_TIMEOUT: + k.MustSetPendingPacketByAddress(ctx, transferPacketData.Sender, packet.RollappPacketKey()) + case commontypes.RollappPacket_UNDEFINED: + panic("invalid rollapp packet type") + } k.SetRollappPacket(ctx, packet) } } diff --git a/x/delayedack/ibc_middleware.go b/x/delayedack/ibc_middleware.go index e16041004..ed4036c92 100644 --- a/x/delayedack/ibc_middleware.go +++ b/x/delayedack/ibc_middleware.go @@ -121,7 +121,7 @@ func (w IBCMiddleware) OnAcknowledgementPacket( l := w.logger(ctx, packet, "OnAcknowledgementPacket") var ack channeltypes.Acknowledgement - if err := types.ModuleCdc.UnmarshalJSON(acknowledgement, &ack); err != nil { + if err := w.Keeper.Cdc().UnmarshalJSON(acknowledgement, &ack); err != nil { l.Error("Unmarshal acknowledgement.", "err", err) return errorsmod.Wrapf(types.ErrUnknownRequest, "unmarshal ICS-20 transfer packet acknowledgement: %v", err) } @@ -200,6 +200,15 @@ func (w IBCMiddleware) savePacket(ctx sdk.Context, packet channeltypes.Packet, t Type: packetType, } + // Add the packet to the pending packet index + switch packetType { + case commontypes.RollappPacket_ON_RECV: + w.MustSetPendingPacketByAddress(ctx, transfer.FungibleTokenPacketData.Receiver, p.RollappPacketKey()) + case commontypes.RollappPacket_ON_ACK, commontypes.RollappPacket_ON_TIMEOUT: + w.MustSetPendingPacketByAddress(ctx, transfer.FungibleTokenPacketData.Sender, p.RollappPacketKey()) + } + + // Save the rollapp packet w.Keeper.SetRollappPacket(ctx, p) return p diff --git a/x/delayedack/keeper/finalize_test.go b/x/delayedack/keeper/finalize_test.go index 6dce23e84..02e290914 100644 --- a/x/delayedack/keeper/finalize_test.go +++ b/x/delayedack/keeper/finalize_test.go @@ -23,7 +23,7 @@ func (s *DelayedAckTestSuite) TestFinalizePacket() { RollappId: rollapp, Status: commontypes.Status_PENDING, ProofHeight: 8, - Packet: s.getNewTestPacket(2), + Packet: apptesting.GenerateTestPacket(s.T(), 2), }, rollappHeight: 10, expectErr: false, @@ -35,7 +35,7 @@ func (s *DelayedAckTestSuite) TestFinalizePacket() { RollappId: rollapp, Status: commontypes.Status_FINALIZED, ProofHeight: 8, - Packet: s.getNewTestPacket(2), + Packet: apptesting.GenerateTestPacket(s.T(), 2), }, rollappHeight: 10, expectErr: true, @@ -47,7 +47,7 @@ func (s *DelayedAckTestSuite) TestFinalizePacket() { RollappId: rollapp, Status: commontypes.Status_PENDING, ProofHeight: 15, - Packet: s.getNewTestPacket(2), + Packet: apptesting.GenerateTestPacket(s.T(), 2), }, rollappHeight: 10, expectErr: true, @@ -135,7 +135,7 @@ func (s *DelayedAckTestSuite) TestFinalizePacketByPacketKey() { RollappId: rollapp, Status: commontypes.Status_PENDING, ProofHeight: 8, - Packet: s.getNewTestPacket(2), + Packet: apptesting.GenerateTestPacket(s.T(), 2), }, rollappHeight: 10, expectedPacketStatus: commontypes.Status_FINALIZED, diff --git a/x/delayedack/keeper/fraud_test.go b/x/delayedack/keeper/fraud_test.go index 43449fc89..4303fa00f 100644 --- a/x/delayedack/keeper/fraud_test.go +++ b/x/delayedack/keeper/fraud_test.go @@ -1,8 +1,7 @@ package keeper_test import ( - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" - + "github.com/dymensionxyz/dymension/v3/app/apptesting" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" ) @@ -10,9 +9,9 @@ import ( func (suite *DelayedAckTestSuite) TestHandleFraud() { keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx rollappId := "testRollappId" - pkts := generatePackets(rollappId, 10) + pkts := apptesting.GenerateRollappPackets(suite.T(), rollappId, 10) rollappId2 := "testRollappId2" - pkts2 := generatePackets(rollappId2, 10) + pkts2 := apptesting.GenerateRollappPackets(suite.T(), rollappId2, 10) prefixPending1 := types.ByRollappIDByStatus(rollappId, commontypes.Status_PENDING) prefixPending2 := types.ByRollappIDByStatus(rollappId2, commontypes.Status_PENDING) prefixFinalized1 := types.ByRollappIDByStatus(rollappId, commontypes.Status_FINALIZED) @@ -50,25 +49,3 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized2))) suite.Require().Equal(9, len(keeper.ListRollappPackets(ctx, prefixPending2))) } - -/* ---------------------------------- utils --------------------------------- */ - -func generatePackets(rollappId string, num uint64) []commontypes.RollappPacket { - var packets []commontypes.RollappPacket - for i := uint64(1); i <= num; i++ { - packets = append(packets, commontypes.RollappPacket{ - RollappId: rollappId, - Packet: &channeltypes.Packet{ - SourcePort: "testSourcePort", - SourceChannel: "testSourceChannel", - DestinationPort: "testDestinationPort", - DestinationChannel: "testDestinationChannel", - Data: []byte("testData"), - Sequence: i, - }, - Status: commontypes.Status_PENDING, - ProofHeight: i, - }) - } - return packets -} diff --git a/x/delayedack/keeper/grpc_query.go b/x/delayedack/keeper/grpc_query.go index 151b7fb18..4bce04f22 100644 --- a/x/delayedack/keeper/grpc_query.go +++ b/x/delayedack/keeper/grpc_query.go @@ -6,7 +6,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" "google.golang.org/grpc/codes" @@ -55,7 +54,7 @@ func (q Querier) GetPackets(goCtx context.Context, req *types.QueryRollappPacket return res, nil } -func (q Querier) GetPendingPacketsByReceiver(goCtx context.Context, req *types.QueryPendingPacketsByReceiverRequest) (*types.QueryPendingPacketByReceiverListResponse, error) { +func (q Querier) GetPendingPacketsByAddress(goCtx context.Context, req *types.QueryPendingPacketsByAddressRequest) (*types.QueryPendingPacketByAddressListResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "empty request") } @@ -63,27 +62,13 @@ func (q Querier) GetPendingPacketsByReceiver(goCtx context.Context, req *types.Q ctx := sdk.UnwrapSDKContext(goCtx) // Get all pending rollapp packets until the latest finalized height - rollappPendingPackets, _, err := q.GetPendingPacketsUntilFinalizedHeight(ctx, req.RollappId) + p, err := q.Keeper.GetPendingPacketsByAddress(ctx, req.Address) if err != nil { - return nil, fmt.Errorf("get pending rollapp packets until the latest finalized height: rollapp '%s': %w", req.RollappId, err) + return nil, fmt.Errorf("get pending packets by receiver %s: %w", req.Address, err) } - // Filter packets by receiver - result := make([]commontypes.RollappPacket, 0) - for _, packet := range rollappPendingPackets { - // Get packet data - pd, err := packet.GetTransferPacketData() - if err != nil { - return nil, fmt.Errorf("get transfer packet data: rollapp '%s': %w", req.RollappId, err) - } - // Return a packet if its receiver matches the one specified - if pd.Receiver == req.Receiver { - result = append(result, packet) - } - } - - return &types.QueryPendingPacketByReceiverListResponse{ - RollappPackets: result, + return &types.QueryPendingPacketByAddressListResponse{ + RollappPackets: p, Pagination: nil, // TODO: handle pagination }, nil } diff --git a/x/delayedack/keeper/hooks_test.go b/x/delayedack/keeper/hooks_test.go index c9eea7a98..552ab1d52 100644 --- a/x/delayedack/keeper/hooks_test.go +++ b/x/delayedack/keeper/hooks_test.go @@ -3,6 +3,7 @@ package keeper_test import ( channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + "github.com/dymensionxyz/dymension/v3/app/apptesting" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" ) @@ -52,7 +53,7 @@ func (suite *DelayedAckTestSuite) TestAfterEpochEnd() { SourceChannel: "testSourceChannel", DestinationPort: "testDestinationPort", DestinationChannel: "testDestinationChannel", - Data: []byte("testData"), + Data: apptesting.GenerateTestPacketData(suite.T()), Sequence: uint64(i), }, Status: commontypes.Status_PENDING, diff --git a/x/delayedack/keeper/invariants_test.go b/x/delayedack/keeper/invariants_test.go index d7d351590..48db10164 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -2,9 +2,8 @@ package keeper_test import ( "github.com/cometbft/cometbft/libs/rand" - transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" - channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + "github.com/dymensionxyz/dymension/v3/app/apptesting" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" dakeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" @@ -45,11 +44,13 @@ func (suite *DelayedAckTestSuite) TestInvariants() { proofHeight := rollappBlocks[rollapp] + k rollappPacket := commontypes.RollappPacket{ RollappId: rollapp, - Packet: suite.getNewTestPacket(sequence), + Packet: apptesting.GenerateTestPacket(suite.T(), sequence), Status: commontypes.Status_PENDING, ProofHeight: proofHeight, } suite.App.DelayedAckKeeper.SetRollappPacket(suite.Ctx, rollappPacket) + err = suite.App.DelayedAckKeeper.SetPendingPacketByAddress(suite.Ctx, apptesting.TestPacketReceiver, rollappPacket.RollappPacketKey()) + suite.Require().NoError(err) sequence++ } @@ -67,10 +68,13 @@ func (suite *DelayedAckTestSuite) TestInvariants() { suite.App.RollappKeeper.FinalizeRollappStates(suite.Ctx) // manually finalize packets for all rollapps + finalizedNum := suite.FinalizeAllPendingPackets(apptesting.TestPacketReceiver) + // check the total number of packets + var total int for rollapp := range seqPerRollapp { - finalizedNum := suite.FinalizeAllPendingPackets(rollapp, testPacketReceiver) - suite.Require().Equal(rollappBlocks[rollapp], uint64(finalizedNum)) + total += int(rollappBlocks[rollapp]) } + suite.Require().Equal(total, finalizedNum) // test fraud for rollapp := range seqPerRollapp { @@ -107,13 +111,13 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { RollappId: rollapp, Status: commontypes.Status_FINALIZED, ProofHeight: 5, - Packet: suite.getNewTestPacket(1), + Packet: apptesting.GenerateTestPacket(suite.T(), 1), }, commontypes.RollappPacket{ RollappId: rollapp, Status: commontypes.Status_PENDING, ProofHeight: 15, - Packet: suite.getNewTestPacket(2), + Packet: apptesting.GenerateTestPacket(suite.T(), 2), }, false, }, @@ -124,13 +128,13 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { RollappId: rollapp, Status: commontypes.Status_PENDING, ProofHeight: 5, - Packet: suite.getNewTestPacket(1), + Packet: apptesting.GenerateTestPacket(suite.T(), 1), }, commontypes.RollappPacket{ RollappId: rollapp, Status: commontypes.Status_PENDING, ProofHeight: 15, - Packet: suite.getNewTestPacket(2), + Packet: apptesting.GenerateTestPacket(suite.T(), 2), }, false, }, @@ -141,13 +145,13 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { RollappId: rollapp, Status: commontypes.Status_PENDING, ProofHeight: 5, - Packet: suite.getNewTestPacket(1), + Packet: apptesting.GenerateTestPacket(suite.T(), 1), }, commontypes.RollappPacket{ RollappId: rollapp, Status: commontypes.Status_PENDING, ProofHeight: 15, - Packet: suite.getNewTestPacket(2), + Packet: apptesting.GenerateTestPacket(suite.T(), 2), }, false, }, @@ -159,13 +163,13 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { RollappId: rollapp, Status: commontypes.Status_FINALIZED, ProofHeight: 5, - Packet: suite.getNewTestPacket(1), + Packet: apptesting.GenerateTestPacket(suite.T(), 1), }, commontypes.RollappPacket{ RollappId: rollapp, Status: commontypes.Status_PENDING, ProofHeight: 15, - Packet: suite.getNewTestPacket(2), + Packet: apptesting.GenerateTestPacket(suite.T(), 2), }, true, }, @@ -176,13 +180,13 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { RollappId: rollapp, Status: commontypes.Status_FINALIZED, ProofHeight: 5, - Packet: suite.getNewTestPacket(1), + Packet: apptesting.GenerateTestPacket(suite.T(), 1), }, commontypes.RollappPacket{ RollappId: rollapp, Status: commontypes.Status_FINALIZED, ProofHeight: 15, - Packet: suite.getNewTestPacket(2), + Packet: apptesting.GenerateTestPacket(suite.T(), 2), }, true, }, @@ -237,22 +241,3 @@ func (suite *DelayedAckTestSuite) TestRollappPacketsCasesInvariant() { }) } } - -const testPacketReceiver = "testReceiver" - -func (s *DelayedAckTestSuite) getNewTestPacket(sequence uint64) *channeltypes.Packet { - data := &transfertypes.FungibleTokenPacketData{ - Receiver: testPacketReceiver, - } - pd, err := transfertypes.ModuleCdc.MarshalJSON(data) - s.Require().NoError(err) - - return &channeltypes.Packet{ - SourcePort: "testSourcePort", - SourceChannel: testSourceChannel, - DestinationPort: "testDestinationPort", - DestinationChannel: "testDestinationChannel", - Data: pd, - Sequence: sequence, - } -} diff --git a/x/delayedack/keeper/keeper.go b/x/delayedack/keeper/keeper.go index 49018bbd6..dd5107ac2 100644 --- a/x/delayedack/keeper/keeper.go +++ b/x/delayedack/keeper/keeper.go @@ -3,6 +3,8 @@ package keeper import ( "fmt" + "cosmossdk.io/collections" + collcodec "cosmossdk.io/collections/codec" "github.com/cometbft/cometbft/libs/log" "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" @@ -11,6 +13,7 @@ import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" porttypes "github.com/cosmos/ibc-go/v7/modules/core/05-port/types" + "github.com/dymensionxyz/dymension/v3/internal/collcompat" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) @@ -18,12 +21,18 @@ import ( type Keeper struct { rollapptypes.StubRollappCreatedHooks - cdc codec.BinaryCodec + 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. + // In case of ON_ACK/ON_TIMEOUT packet (Hub -> Rollapp), the address is the packet sender. + // Index key: receiver address + packet key. + pendingPacketsByAddress collections.KeySet[collections.Pair[string, []byte]] + rollappKeeper types.RollappKeeper porttypes.ICS4Wrapper channelKeeper types.ChannelKeeper @@ -31,7 +40,7 @@ type Keeper struct { } func NewKeeper( - cdc codec.BinaryCodec, + cdc codec.Codec, storeKey storetypes.StoreKey, channelKeeperStoreKey storetypes.StoreKey, ps paramtypes.Subspace, @@ -49,10 +58,16 @@ func NewKeeper( storeKey: storeKey, channelKeeperStoreKey: channelKeeperStoreKey, paramstore: ps, - rollappKeeper: rollappKeeper, - ICS4Wrapper: ics4Wrapper, - channelKeeper: channelKeeper, - EIBCKeeper: eibcKeeper, + pendingPacketsByAddress: collections.NewKeySet( + collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey)), + collections.NewPrefix(types.PendingPacketsByAddressKeyPrefix), + "pending_packets_by_receiver", + collections.PairKeyCodec(collections.StringKey, collcodec.NewBytesKey[[]byte]()), + ), + rollappKeeper: rollappKeeper, + ICS4Wrapper: ics4Wrapper, + channelKeeper: channelKeeper, + EIBCKeeper: eibcKeeper, } } @@ -60,6 +75,22 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } +// expose codec to be used by the delayedack middleware +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/keeper_test.go b/x/delayedack/keeper/keeper_test.go index ffb55e68b..21862c6c7 100644 --- a/x/delayedack/keeper/keeper_test.go +++ b/x/delayedack/keeper/keeper_test.go @@ -12,10 +12,7 @@ import ( "github.com/dymensionxyz/dymension/v3/x/delayedack/types" ) -const ( - delayedAckEventType = "delayedack" - testSourceChannel = "testSourceChannel" -) +const delayedAckEventType = "delayedack" type DelayedAckTestSuite struct { apptesting.KeeperTestHelper diff --git a/x/delayedack/keeper/rollapp_packet.go b/x/delayedack/keeper/rollapp_packet.go index 35b5bce5a..7dce2f82a 100644 --- a/x/delayedack/keeper/rollapp_packet.go +++ b/x/delayedack/keeper/rollapp_packet.go @@ -3,6 +3,9 @@ package keeper import ( "fmt" + "errors" + + "cosmossdk.io/collections" sdk "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" @@ -28,6 +31,53 @@ func (k Keeper) SetRollappPacket(ctx sdk.Context, rollappPacket commontypes.Roll ) } +// SetPendingPacketByAddress stores a rollapp packet in the KVStore by its receiver. +// Helper index to query all packets by receiver. +func (k Keeper) SetPendingPacketByAddress(ctx sdk.Context, receiver string, rollappPacketKey []byte) error { + return k.pendingPacketsByAddress.Set(ctx, collections.Join(receiver, rollappPacketKey)) +} + +// MustSetPendingPacketByAddress stores a rollapp packet in the KVStore by its receiver. +// Helper index to query all packets by receiver. Panics on encoding errors. +func (k Keeper) MustSetPendingPacketByAddress(ctx sdk.Context, receiver string, rollappPacketKey []byte) { + err := k.SetPendingPacketByAddress(ctx, receiver, rollappPacketKey) + if err != nil { + panic(err) + } +} + +// DeletePendingPacketByAddress deletes a rollapp packet from the KVStore by its receiver. +func (k Keeper) DeletePendingPacketByAddress(ctx sdk.Context, receiver string, rollappPacketKey []byte) error { + return k.pendingPacketsByAddress.Remove(ctx, collections.Join(receiver, rollappPacketKey)) +} + +// MustDeletePendingPacketByAddress deletes a rollapp packet from the KVStore by its receiver. +// Panics on encoding error. Do not panic if the key is not found. +func (k Keeper) MustDeletePendingPacketByAddress(ctx sdk.Context, receiver string, rollappPacketKey []byte) { + err := k.DeletePendingPacketByAddress(ctx, receiver, rollappPacketKey) + if err != nil { + panic(err) + } +} + +// GetPendingPacketsByAddress retrieves rollapp packets from the KVStore by their receiver. +func (k Keeper) GetPendingPacketsByAddress(ctx sdk.Context, receiver string) ([]commontypes.RollappPacket, error) { + var packets []commontypes.RollappPacket + rng := collections.NewPrefixedPairRange[string, []byte](receiver) + err := k.pendingPacketsByAddress.Walk(ctx, rng, func(key collections.Pair[string, []byte]) (stop bool, err error) { + packet, err := k.GetRollappPacket(ctx, string(key.K2())) + if err != nil { + return true, err + } + packets = append(packets, *packet) + return false, nil + }) + if err != nil { + return nil, err + } + return packets, nil +} + // GetRollappPacket retrieves a rollapp packet from the KVStore. func (k Keeper) GetRollappPacket(ctx sdk.Context, rollappPacketKey string) (*commontypes.RollappPacket, error) { store := ctx.KVStore(k.storeKey) @@ -57,23 +107,27 @@ func (k Keeper) UpdateRollappPacketTransferAddress( if rollappPacket.Status != commontypes.Status_PENDING { return types.ErrCanOnlyUpdatePendingPacket } + transferPacketData, err := rollappPacket.GetTransferPacketData() if err != nil { return err } + // Set the recipient and sender based on the rollapp packet type - recipient, sender := transferPacketData.Receiver, transferPacketData.Sender - var originalTransferTarget string + var ( + recipient = transferPacketData.Receiver + sender = transferPacketData.Sender + originalTransferTarget string + ) switch rollappPacket.Type { case commontypes.RollappPacket_ON_RECV: originalTransferTarget = recipient recipient = address - case commontypes.RollappPacket_ON_TIMEOUT: - fallthrough - case commontypes.RollappPacket_ON_ACK: + case commontypes.RollappPacket_ON_ACK, commontypes.RollappPacket_ON_TIMEOUT: originalTransferTarget = sender sender = address } + // Create a new packet data with the updated recipient and sender newPacketData := transfertypes.NewFungibleTokenPacketData( transferPacketData.Denom, @@ -82,14 +136,21 @@ func (k Keeper) UpdateRollappPacketTransferAddress( recipient, transferPacketData.Memo, ) + // Marshall to binary and update the packet with this data - packetBytes := newPacketData.GetBytes() packet := rollappPacket.Packet - packet.Data = packetBytes + packet.Data = newPacketData.GetBytes() // Update rollapp packet with the new updated packet and save in the store rollappPacket.Packet = packet rollappPacket.OriginalTransferTarget = originalTransferTarget + + // Update index: delete the old packet and save the new one + k.MustDeletePendingPacketByAddress(ctx, originalTransferTarget, []byte(rollappPacketKey)) + k.MustSetPendingPacketByAddress(ctx, address, rollappPacket.RollappPacketKey()) + + // Save updated rollapp packet k.SetRollappPacket(ctx, *rollappPacket) + return nil } @@ -97,20 +158,42 @@ func (k Keeper) UpdateRollappPacketTransferAddress( // 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) { - store := ctx.KVStore(k.storeKey) + 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 { + return commontypes.RollappPacket{}, err + } - // Delete the old rollapp packet oldKey := rollappPacket.RollappPacketKey() + + // Delete the old packet from the pending packets index depending on the packet type + switch rollappPacket.Type { + case commontypes.RollappPacket_ON_RECV: + k.MustDeletePendingPacketByAddress(ctx, transferPacketData.Receiver, oldKey) + case commontypes.RollappPacket_ON_ACK, commontypes.RollappPacket_ON_TIMEOUT: + k.MustDeletePendingPacketByAddress(ctx, transferPacketData.Sender, oldKey) + } + + // Delete the old rollapp packet + store := ctx.KVStore(k.storeKey) store.Delete(oldKey) + // Update the packet rollappPacket.Status = newStatus // Create a new rollapp packet with the updated status k.SetRollappPacket(ctx, rollappPacket) - // Call hook subscribers newKey := rollappPacket.RollappPacketKey() + + // Call hook subscribers keeperHooks := k.GetHooks() - err := keeperHooks.AfterPacketStatusUpdated(ctx, &rollappPacket, string(oldKey), string(newKey)) + err = keeperHooks.AfterPacketStatusUpdated(ctx, &rollappPacket, string(oldKey), string(newKey)) if err != nil { return rollappPacket, err } diff --git a/x/delayedack/keeper/rollapp_packet_test.go b/x/delayedack/keeper/rollapp_packet_test.go index 72a86ce0d..53a573be0 100644 --- a/x/delayedack/keeper/rollapp_packet_test.go +++ b/x/delayedack/keeper/rollapp_packet_test.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types" + "github.com/dymensionxyz/dymension/v3/app/apptesting" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" ) @@ -24,15 +25,8 @@ func (suite *DelayedAckTestSuite) TestRollappPacketEvents() { { name: "Test demand order fulfillment - success", rollappPacket: commontypes.RollappPacket{ - RollappId: "testRollappID", - Packet: &channeltypes.Packet{ - SourcePort: "testSourcePort", - SourceChannel: "testSourceChannel", - DestinationPort: "testDestinationPort", - DestinationChannel: "testDestinationChannel", - Data: []byte("testData"), - Sequence: 1, - }, + RollappId: "testRollappID", + Packet: apptesting.GenerateTestPacket(suite.T(), 1), Status: commontypes.Status_PENDING, ProofHeight: 1, }, @@ -174,27 +168,29 @@ func (suite *DelayedAckTestSuite) TestListRollappPackets() { suite.Require().Equal(totalLength, totalCount) } -func (suite *DelayedAckTestSuite) TestUpdateRollappPacketWithStatus() { +func (suite *DelayedAckTestSuite) TestUpdateRollappPacketWithStatus_PendingToFinalized() { var err error keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx - packet := commontypes.RollappPacket{ - RollappId: "testRollappID", - Packet: &channeltypes.Packet{ - SourcePort: "testSourcePort", - SourceChannel: "testSourceChannel", - DestinationPort: "testDestinationPort", - DestinationChannel: "testDestinationChannel", - Data: []byte("testData"), - Sequence: 1, - }, + oldPacket := commontypes.RollappPacket{ + RollappId: "testRollappID", + Packet: apptesting.GenerateTestPacket(suite.T(), 1), Status: commontypes.Status_PENDING, ProofHeight: 1, } - keeper.SetRollappPacket(ctx, packet) + keeper.SetRollappPacket(ctx, oldPacket) + err = keeper.SetPendingPacketByAddress(ctx, apptesting.TestPacketReceiver, oldPacket.RollappPacketKey()) + suite.Require().NoError(err) + // Update the packet status - packet, err = keeper.UpdateRollappPacketWithStatus(ctx, packet, commontypes.Status_FINALIZED) + packet, err := keeper.UpdateRollappPacketWithStatus(ctx, oldPacket, commontypes.Status_FINALIZED) suite.Require().NoError(err) suite.Require().Equal(commontypes.Status_FINALIZED, packet.Status) + + // Check the updated packet is not in the receiver's index anymore + byReceiver, err := keeper.GetPendingPacketsByAddress(ctx, apptesting.TestPacketReceiver) + suite.Require().NoError(err) + suite.Require().Empty(len(byReceiver)) + packets := keeper.GetAllRollappPackets(ctx) suite.Require().Equal(1, len(packets)) // Set the packet and make sure there is only one packet in the store @@ -202,3 +198,111 @@ func (suite *DelayedAckTestSuite) TestUpdateRollappPacketWithStatus() { packets = keeper.GetAllRollappPackets(ctx) suite.Require().Equal(1, len(packets)) } + +func (suite *DelayedAckTestSuite) TestUpdateRollappPacketTransferAddress_ON_RECV() { + var err error + keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx + packet := commontypes.RollappPacket{ + RollappId: "testRollappID", + Packet: apptesting.GenerateTestPacket(suite.T(), 1), + Type: commontypes.RollappPacket_ON_RECV, + Status: commontypes.Status_PENDING, + ProofHeight: 1, + } + keeper.SetRollappPacket(ctx, packet) + err = keeper.SetPendingPacketByAddress(ctx, apptesting.TestPacketReceiver, packet.RollappPacketKey()) + suite.Require().NoError(err) + + // Update the packet receiver + const newReceiver = "newReceiver" + err = keeper.UpdateRollappPacketTransferAddress(ctx, string(packet.RollappPacketKey()), newReceiver) + suite.Require().NoError(err) + + // Check the state + packets := keeper.GetAllRollappPackets(ctx) + suite.Require().Equal(1, len(packets)) + pd1, err := packets[0].GetTransferPacketData() + suite.Require().NoError(err) + suite.Require().Equal(newReceiver, pd1.Receiver) + + // Check the packet key is the same + actualPacket, err := keeper.GetRollappPacket(ctx, string(packet.RollappPacketKey())) + suite.Require().NoError(err) + pd2, err := actualPacket.GetTransferPacketData() + suite.Require().NoError(err) + suite.Require().Equal(newReceiver, pd2.Receiver) + + // Check the index + // Check the packet is in the receiver's index + byReceiverNew, err := keeper.GetPendingPacketsByAddress(ctx, newReceiver) + suite.Require().NoError(err) + suite.Require().Equal(1, len(byReceiverNew)) + suite.Require().Equal(packet.RollappPacketKey(), byReceiverNew[0].RollappPacketKey()) + pd3, err := byReceiverNew[0].GetTransferPacketData() + suite.Require().NoError(err) + suite.Require().Equal(newReceiver, pd3.Receiver) + + // Check the packet is not in the receiver's index + byReceiverOld, err := keeper.GetPendingPacketsByAddress(ctx, apptesting.TestPacketReceiver) + suite.Require().NoError(err) + suite.Require().Empty(byReceiverOld) + + // Set the packet and make sure there is only one packet in the store + keeper.SetRollappPacket(ctx, packet) + packets = keeper.GetAllRollappPackets(ctx) + suite.Require().Equal(1, len(packets)) +} + +func (suite *DelayedAckTestSuite) TestUpdateRollappPacketTransferAddress_ON_ACK() { + var err error + keeper, ctx := suite.App.DelayedAckKeeper, suite.Ctx + packet := commontypes.RollappPacket{ + RollappId: "testRollappID", + Packet: apptesting.GenerateTestPacket(suite.T(), 1), + Type: commontypes.RollappPacket_ON_ACK, + Status: commontypes.Status_PENDING, + ProofHeight: 1, + } + keeper.SetRollappPacket(ctx, packet) + err = keeper.SetPendingPacketByAddress(ctx, apptesting.TestPacketSender, packet.RollappPacketKey()) + suite.Require().NoError(err) + + // Update the packet receiver + const newSender = "newSender" + err = keeper.UpdateRollappPacketTransferAddress(ctx, string(packet.RollappPacketKey()), newSender) + suite.Require().NoError(err) + + // Check the state + packets := keeper.GetAllRollappPackets(ctx) + suite.Require().Equal(1, len(packets)) + pd1, err := packets[0].GetTransferPacketData() + suite.Require().NoError(err) + suite.Require().Equal(newSender, pd1.Sender) + + // Check the packet key is the same + actualPacket, err := keeper.GetRollappPacket(ctx, string(packet.RollappPacketKey())) + suite.Require().NoError(err) + pd2, err := actualPacket.GetTransferPacketData() + suite.Require().NoError(err) + suite.Require().Equal(newSender, pd2.Sender) + + // Check the index + // Check the new packet is in the sender's index + bySenderNew, err := keeper.GetPendingPacketsByAddress(ctx, newSender) + suite.Require().NoError(err) + suite.Require().Equal(1, len(bySenderNew)) + suite.Require().Equal(packet.RollappPacketKey(), bySenderNew[0].RollappPacketKey()) + pd3, err := bySenderNew[0].GetTransferPacketData() + suite.Require().NoError(err) + suite.Require().Equal(newSender, pd3.Sender) + + // Check the old packet is not in the sender's index + bySenderOld, err := keeper.GetPendingPacketsByAddress(ctx, apptesting.TestPacketSender) + suite.Require().NoError(err) + suite.Require().Empty(bySenderOld) + + // Set the packet and make sure there is only one packet in the store + keeper.SetRollappPacket(ctx, packet) + packets = keeper.GetAllRollappPackets(ctx) + suite.Require().Equal(1, len(packets)) +} diff --git a/x/delayedack/types/codec.go b/x/delayedack/types/codec.go index f1f321d40..cbcb94bf4 100644 --- a/x/delayedack/types/codec.go +++ b/x/delayedack/types/codec.go @@ -5,11 +5,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/msgservice" -) - -var ( - Amino = codec.NewLegacyAmino() - ModuleCdc = codec.NewProtoCodec(types.NewInterfaceRegistry()) + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" ) // RegisterCodec registers the necessary x/delayedack interfaces and concrete types on the provided @@ -28,3 +24,18 @@ func RegisterInterfaces(reg types.InterfaceRegistry) { ) msgservice.RegisterMsgServiceDesc(reg, &_Msg_serviceDesc) } + +var ( + Amino = codec.NewLegacyAmino() + ModuleCdc = codec.NewAminoCodec(Amino) +) + +func init() { + RegisterCodec(Amino) + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + sdk.RegisterLegacyAminoCodec(Amino) + RegisterCodec(authzcodec.Amino) + + Amino.Seal() +} diff --git a/x/delayedack/types/events.pb.go b/x/delayedack/types/events.pb.go index 29cde468c..5cfa41511 100644 --- a/x/delayedack/types/events.pb.go +++ b/x/delayedack/types/events.pb.go @@ -113,163 +113,8 @@ func (m *EventFinalizePacket) GetPacketSequence() uint64 { return 0 } -type EventFinalizePacketsUntilHeight struct { - // Sender is the signer of the message. - Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` - // RollappID is the ID of the rollapp. - RollappId string `protobuf:"bytes,2,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` - // Height is a height until which packets are to be finalized. Height is inclusive. - Height uint64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` - // FinalizedNum is the number of finalized packets. - FinalizedNum uint64 `protobuf:"varint,4,opt,name=finalized_num,json=finalizedNum,proto3" json:"finalized_num,omitempty"` -} - -func (m *EventFinalizePacketsUntilHeight) Reset() { *m = EventFinalizePacketsUntilHeight{} } -func (m *EventFinalizePacketsUntilHeight) String() string { return proto.CompactTextString(m) } -func (*EventFinalizePacketsUntilHeight) ProtoMessage() {} -func (*EventFinalizePacketsUntilHeight) Descriptor() ([]byte, []int) { - return fileDescriptor_de2c6b6165d75670, []int{1} -} -func (m *EventFinalizePacketsUntilHeight) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *EventFinalizePacketsUntilHeight) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_EventFinalizePacketsUntilHeight.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 *EventFinalizePacketsUntilHeight) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventFinalizePacketsUntilHeight.Merge(m, src) -} -func (m *EventFinalizePacketsUntilHeight) XXX_Size() int { - return m.Size() -} -func (m *EventFinalizePacketsUntilHeight) XXX_DiscardUnknown() { - xxx_messageInfo_EventFinalizePacketsUntilHeight.DiscardUnknown(m) -} - -var xxx_messageInfo_EventFinalizePacketsUntilHeight proto.InternalMessageInfo - -func (m *EventFinalizePacketsUntilHeight) GetSender() string { - if m != nil { - return m.Sender - } - return "" -} - -func (m *EventFinalizePacketsUntilHeight) GetRollappId() string { - if m != nil { - return m.RollappId - } - return "" -} - -func (m *EventFinalizePacketsUntilHeight) GetHeight() uint64 { - if m != nil { - return m.Height - } - return 0 -} - -func (m *EventFinalizePacketsUntilHeight) GetFinalizedNum() uint64 { - if m != nil { - return m.FinalizedNum - } - return 0 -} - -type EventFinalizeRollappPacketsByReceiver struct { - // Sender is the signer of the message. - Sender string `protobuf:"bytes,1,opt,name=sender,proto3" json:"sender,omitempty"` - // RollappID is the ID of the rollapp. - RollappId string `protobuf:"bytes,2,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` - // Receiver is the one who waits tokens after the finalization. - Receiver string `protobuf:"bytes,3,opt,name=receiver,proto3" json:"receiver,omitempty"` - // Height is a height until which packets are to be finalized. - Height uint64 `protobuf:"varint,4,opt,name=height,proto3" json:"height,omitempty"` - // FinalizedNum is the number of finalized packets. - FinalizedNum uint64 `protobuf:"varint,5,opt,name=finalized_num,json=finalizedNum,proto3" json:"finalized_num,omitempty"` -} - -func (m *EventFinalizeRollappPacketsByReceiver) Reset() { *m = EventFinalizeRollappPacketsByReceiver{} } -func (m *EventFinalizeRollappPacketsByReceiver) String() string { return proto.CompactTextString(m) } -func (*EventFinalizeRollappPacketsByReceiver) ProtoMessage() {} -func (*EventFinalizeRollappPacketsByReceiver) Descriptor() ([]byte, []int) { - return fileDescriptor_de2c6b6165d75670, []int{2} -} -func (m *EventFinalizeRollappPacketsByReceiver) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *EventFinalizeRollappPacketsByReceiver) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_EventFinalizeRollappPacketsByReceiver.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 *EventFinalizeRollappPacketsByReceiver) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventFinalizeRollappPacketsByReceiver.Merge(m, src) -} -func (m *EventFinalizeRollappPacketsByReceiver) XXX_Size() int { - return m.Size() -} -func (m *EventFinalizeRollappPacketsByReceiver) XXX_DiscardUnknown() { - xxx_messageInfo_EventFinalizeRollappPacketsByReceiver.DiscardUnknown(m) -} - -var xxx_messageInfo_EventFinalizeRollappPacketsByReceiver proto.InternalMessageInfo - -func (m *EventFinalizeRollappPacketsByReceiver) GetSender() string { - if m != nil { - return m.Sender - } - return "" -} - -func (m *EventFinalizeRollappPacketsByReceiver) GetRollappId() string { - if m != nil { - return m.RollappId - } - return "" -} - -func (m *EventFinalizeRollappPacketsByReceiver) GetReceiver() string { - if m != nil { - return m.Receiver - } - return "" -} - -func (m *EventFinalizeRollappPacketsByReceiver) GetHeight() uint64 { - if m != nil { - return m.Height - } - return 0 -} - -func (m *EventFinalizeRollappPacketsByReceiver) GetFinalizedNum() uint64 { - if m != nil { - return m.FinalizedNum - } - return 0 -} - func init() { proto.RegisterType((*EventFinalizePacket)(nil), "dymensionxyz.dymension.delayedack.EventFinalizePacket") - proto.RegisterType((*EventFinalizePacketsUntilHeight)(nil), "dymensionxyz.dymension.delayedack.EventFinalizePacketsUntilHeight") - proto.RegisterType((*EventFinalizeRollappPacketsByReceiver)(nil), "dymensionxyz.dymension.delayedack.EventFinalizeRollappPacketsByReceiver") } func init() { @@ -277,34 +122,28 @@ func init() { } var fileDescriptor_de2c6b6165d75670 = []byte{ - // 427 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0xbd, 0x8e, 0xd3, 0x40, - 0x10, 0xce, 0x1e, 0x3e, 0x8b, 0x2c, 0x70, 0xc0, 0x9e, 0x74, 0xb2, 0x4e, 0xc2, 0x84, 0x20, 0x44, - 0x0a, 0x64, 0x8b, 0xbb, 0x82, 0xfe, 0x10, 0x08, 0x1a, 0x74, 0x2c, 0xd0, 0xd0, 0x58, 0xbe, 0xf5, - 0x5c, 0xbc, 0x8a, 0xbd, 0x6b, 0xd6, 0x76, 0x14, 0xe7, 0x29, 0x68, 0x78, 0x06, 0x1e, 0x81, 0x57, - 0xa0, 0x4c, 0x49, 0x89, 0x92, 0x17, 0x41, 0xde, 0xdd, 0xfc, 0x09, 0x42, 0x91, 0xce, 0x33, 0xdf, - 0xe7, 0x6f, 0xbe, 0xf9, 0x3c, 0xc6, 0x41, 0xd2, 0xe4, 0x20, 0x4a, 0x2e, 0xc5, 0xa4, 0x99, 0x86, - 0xab, 0x22, 0x4c, 0x20, 0x8b, 0x1b, 0x48, 0x62, 0x36, 0x0a, 0x61, 0x0c, 0xa2, 0x2a, 0x83, 0x42, - 0xc9, 0x4a, 0x92, 0x47, 0x9b, 0xfc, 0xf5, 0xcb, 0xc1, 0x9a, 0x7f, 0x7a, 0xb6, 0x43, 0x92, 0xc9, - 0x3c, 0x97, 0x22, 0x54, 0x32, 0xcb, 0xe2, 0xa2, 0x88, 0x8a, 0x98, 0x8d, 0xa0, 0x32, 0xb2, 0xfd, - 0xef, 0x07, 0xf8, 0xf8, 0x55, 0x3b, 0xe7, 0x35, 0x17, 0x71, 0xc6, 0xa7, 0x70, 0xa9, 0x51, 0x72, - 0x82, 0xdd, 0x12, 0x44, 0x02, 0xca, 0x43, 0x3d, 0x34, 0xe8, 0x52, 0x5b, 0x91, 0x07, 0x18, 0x2f, - 0x75, 0x78, 0xe2, 0x1d, 0x68, 0xac, 0x6b, 0x3b, 0x6f, 0x13, 0x12, 0xe0, 0x63, 0x23, 0x1f, 0x15, - 0x4a, 0xca, 0xeb, 0x28, 0x05, 0x3e, 0x4c, 0x2b, 0xef, 0x46, 0x0f, 0x0d, 0x1c, 0x7a, 0xdf, 0x40, - 0x97, 0x2d, 0xf2, 0x46, 0x03, 0x84, 0xe2, 0x5b, 0x96, 0x5f, 0x35, 0x05, 0x78, 0x4e, 0x0f, 0x0d, - 0x8e, 0xce, 0x9e, 0x07, 0x3b, 0x76, 0x35, 0x8b, 0x04, 0xd4, 0x8c, 0x33, 0x4e, 0x83, 0x8f, 0x4d, - 0x01, 0x14, 0x1b, 0x95, 0xf6, 0x99, 0x3c, 0xc3, 0xc4, 0x6a, 0x96, 0x8a, 0x45, 0x2c, 0x8d, 0x85, - 0x80, 0xcc, 0x3b, 0xd4, 0x56, 0xef, 0x19, 0xe4, 0x83, 0x62, 0x2f, 0x4d, 0x9f, 0x3c, 0xc5, 0x77, - 0x97, 0x6c, 0xf8, 0x52, 0x83, 0x60, 0xe0, 0xb9, 0xda, 0xed, 0x91, 0xa5, 0xda, 0x6e, 0xff, 0x1b, - 0xc2, 0x0f, 0xff, 0x91, 0x54, 0xf9, 0x49, 0x54, 0x3c, 0xb3, 0xeb, 0xec, 0x99, 0xda, 0x09, 0x76, - 0xb7, 0x82, 0xb2, 0x15, 0x79, 0x8c, 0xef, 0x5c, 0xdb, 0x61, 0x49, 0x24, 0xea, 0x5c, 0xe7, 0xe3, - 0xd0, 0xdb, 0xab, 0xe6, 0xbb, 0x3a, 0xef, 0xff, 0x40, 0xf8, 0xc9, 0x96, 0xaf, 0xad, 0x78, 0xca, - 0x8b, 0x86, 0x02, 0x03, 0x3e, 0x06, 0xb5, 0xaf, 0xbb, 0x53, 0x7c, 0x53, 0x59, 0x09, 0xed, 0xaf, - 0x4b, 0x57, 0xf5, 0x86, 0x73, 0xe7, 0xff, 0xce, 0x0f, 0xff, 0x76, 0x7e, 0xf1, 0xfe, 0xe7, 0xdc, - 0x47, 0xb3, 0xb9, 0x8f, 0x7e, 0xcf, 0x7d, 0xf4, 0x75, 0xe1, 0x77, 0x66, 0x0b, 0xbf, 0xf3, 0x6b, - 0xe1, 0x77, 0x3e, 0xbf, 0x18, 0xf2, 0x2a, 0xad, 0xaf, 0xda, 0x0f, 0x1e, 0xee, 0x38, 0xea, 0xf1, - 0x79, 0x38, 0xd9, 0xfc, 0x59, 0xda, 0xfb, 0x29, 0xaf, 0x5c, 0x7d, 0xd5, 0xe7, 0x7f, 0x02, 0x00, - 0x00, 0xff, 0xff, 0xd4, 0x60, 0x15, 0xe5, 0x5e, 0x03, 0x00, 0x00, + // 333 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x91, 0x41, 0x4f, 0xc2, 0x30, + 0x14, 0xc7, 0x29, 0x22, 0x09, 0x35, 0x41, 0x2d, 0x89, 0x59, 0x4c, 0x5c, 0xd0, 0x8b, 0x1c, 0x4c, + 0x17, 0xe1, 0xe0, 0x5d, 0xa3, 0xd1, 0x1b, 0x4e, 0x4f, 0x5e, 0x96, 0xd1, 0x3d, 0xd9, 0xc2, 0x68, + 0xeb, 0x56, 0x08, 0xe3, 0x53, 0xf8, 0x2d, 0xfc, 0x2a, 0x1e, 0x39, 0x7a, 0x34, 0xf0, 0x45, 0xcc, + 0xda, 0x22, 0x5c, 0xb8, 0xf5, 0xbd, 0xff, 0xbf, 0xbf, 0xf7, 0x7f, 0x79, 0x98, 0x46, 0xc5, 0x18, + 0x78, 0x9e, 0x08, 0x3e, 0x2b, 0xe6, 0xde, 0x7f, 0xe1, 0x45, 0x90, 0x86, 0x05, 0x44, 0x21, 0x1b, + 0x79, 0x30, 0x05, 0xae, 0x72, 0x2a, 0x33, 0xa1, 0x04, 0x39, 0xdf, 0xf6, 0x6f, 0x3e, 0xd3, 0x8d, + 0xff, 0xb4, 0xbb, 0x03, 0xc9, 0xc4, 0x78, 0x2c, 0xb8, 0x97, 0x89, 0x34, 0x0d, 0xa5, 0x0c, 0x64, + 0xc8, 0x46, 0xa0, 0x0c, 0xf6, 0xe2, 0xab, 0x8a, 0x5b, 0xf7, 0xe5, 0x9c, 0x87, 0x84, 0x87, 0x69, + 0x32, 0x87, 0xbe, 0x56, 0xc9, 0x09, 0xae, 0xe7, 0xc0, 0x23, 0xc8, 0x1c, 0xd4, 0x46, 0x9d, 0x86, + 0x6f, 0x2b, 0x72, 0x86, 0xf1, 0x9a, 0x93, 0x44, 0x4e, 0x55, 0x6b, 0x0d, 0xdb, 0x79, 0x8a, 0x08, + 0xc5, 0x2d, 0x83, 0x0f, 0x64, 0x26, 0xc4, 0x7b, 0x10, 0x43, 0x32, 0x8c, 0x95, 0xb3, 0xd7, 0x46, + 0x9d, 0x9a, 0x7f, 0x6c, 0xa4, 0x7e, 0xa9, 0x3c, 0x6a, 0x81, 0xf8, 0xf8, 0xc0, 0xfa, 0x55, 0x21, + 0xc1, 0xa9, 0xb5, 0x51, 0xa7, 0xd9, 0xbd, 0xa6, 0x3b, 0x76, 0x35, 0x8b, 0x50, 0xdf, 0x8c, 0x33, + 0x49, 0xe9, 0x6b, 0x21, 0xc1, 0xc7, 0x86, 0x52, 0xbe, 0xc9, 0x15, 0x26, 0x96, 0x99, 0x67, 0x2c, + 0x60, 0x71, 0xc8, 0x39, 0xa4, 0xce, 0xbe, 0x8e, 0x7a, 0x64, 0x94, 0x97, 0x8c, 0xdd, 0x99, 0x3e, + 0xb9, 0xc4, 0x87, 0x6b, 0x37, 0x7c, 0x4c, 0x80, 0x33, 0x70, 0xea, 0x3a, 0x6d, 0xd3, 0x5a, 0x6d, + 0xf7, 0xf6, 0xf9, 0x7b, 0xe9, 0xa2, 0xc5, 0xd2, 0x45, 0xbf, 0x4b, 0x17, 0x7d, 0xae, 0xdc, 0xca, + 0x62, 0xe5, 0x56, 0x7e, 0x56, 0x6e, 0xe5, 0xed, 0x66, 0x98, 0xa8, 0x78, 0x32, 0x28, 0xe3, 0x79, + 0x3b, 0x4e, 0x30, 0xed, 0x79, 0xb3, 0xed, 0xd3, 0x96, 0xdb, 0xe6, 0x83, 0xba, 0xbe, 0x41, 0xef, + 0x2f, 0x00, 0x00, 0xff, 0xff, 0x4b, 0xa4, 0x49, 0x5e, 0x0c, 0x02, 0x00, 0x00, } func (m *EventFinalizePacket) Marshal() (dAtA []byte, err error) { @@ -366,107 +205,6 @@ func (m *EventFinalizePacket) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *EventFinalizePacketsUntilHeight) 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 *EventFinalizePacketsUntilHeight) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *EventFinalizePacketsUntilHeight) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.FinalizedNum != 0 { - i = encodeVarintEvents(dAtA, i, uint64(m.FinalizedNum)) - i-- - dAtA[i] = 0x20 - } - if m.Height != 0 { - i = encodeVarintEvents(dAtA, i, uint64(m.Height)) - i-- - dAtA[i] = 0x18 - } - if len(m.RollappId) > 0 { - i -= len(m.RollappId) - copy(dAtA[i:], m.RollappId) - i = encodeVarintEvents(dAtA, i, uint64(len(m.RollappId))) - i-- - dAtA[i] = 0x12 - } - if len(m.Sender) > 0 { - i -= len(m.Sender) - copy(dAtA[i:], m.Sender) - i = encodeVarintEvents(dAtA, i, uint64(len(m.Sender))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - -func (m *EventFinalizeRollappPacketsByReceiver) 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 *EventFinalizeRollappPacketsByReceiver) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *EventFinalizeRollappPacketsByReceiver) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if m.FinalizedNum != 0 { - i = encodeVarintEvents(dAtA, i, uint64(m.FinalizedNum)) - i-- - dAtA[i] = 0x28 - } - if m.Height != 0 { - i = encodeVarintEvents(dAtA, i, uint64(m.Height)) - i-- - dAtA[i] = 0x20 - } - if len(m.Receiver) > 0 { - i -= len(m.Receiver) - copy(dAtA[i:], m.Receiver) - i = encodeVarintEvents(dAtA, i, uint64(len(m.Receiver))) - i-- - dAtA[i] = 0x1a - } - if len(m.RollappId) > 0 { - i -= len(m.RollappId) - copy(dAtA[i:], m.RollappId) - i = encodeVarintEvents(dAtA, i, uint64(len(m.RollappId))) - i-- - dAtA[i] = 0x12 - } - if len(m.Sender) > 0 { - i -= len(m.Sender) - copy(dAtA[i:], m.Sender) - i = encodeVarintEvents(dAtA, i, uint64(len(m.Sender))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { offset -= sovEvents(v) base := offset @@ -508,56 +246,6 @@ func (m *EventFinalizePacket) Size() (n int) { return n } -func (m *EventFinalizePacketsUntilHeight) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Sender) - if l > 0 { - n += 1 + l + sovEvents(uint64(l)) - } - l = len(m.RollappId) - if l > 0 { - n += 1 + l + sovEvents(uint64(l)) - } - if m.Height != 0 { - n += 1 + sovEvents(uint64(m.Height)) - } - if m.FinalizedNum != 0 { - n += 1 + sovEvents(uint64(m.FinalizedNum)) - } - return n -} - -func (m *EventFinalizeRollappPacketsByReceiver) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Sender) - if l > 0 { - n += 1 + l + sovEvents(uint64(l)) - } - l = len(m.RollappId) - if l > 0 { - n += 1 + l + sovEvents(uint64(l)) - } - l = len(m.Receiver) - if l > 0 { - n += 1 + l + sovEvents(uint64(l)) - } - if m.Height != 0 { - n += 1 + sovEvents(uint64(m.Height)) - } - if m.FinalizedNum != 0 { - n += 1 + sovEvents(uint64(m.FinalizedNum)) - } - return n -} - func sovEvents(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -767,342 +455,6 @@ func (m *EventFinalizePacket) Unmarshal(dAtA []byte) error { } return nil } -func (m *EventFinalizePacketsUntilHeight) 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 ErrIntOverflowEvents - } - 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: EventFinalizePacketsUntilHeight: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: EventFinalizePacketsUntilHeight: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvents - } - 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 ErrInvalidLengthEvents - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthEvents - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Sender = 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 ErrIntOverflowEvents - } - 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 ErrInvalidLengthEvents - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthEvents - } - 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 Height", wireType) - } - m.Height = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvents - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Height |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field FinalizedNum", wireType) - } - m.FinalizedNum = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvents - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.FinalizedNum |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipEvents(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthEvents - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *EventFinalizeRollappPacketsByReceiver) 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 ErrIntOverflowEvents - } - 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: EventFinalizeRollappPacketsByReceiver: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: EventFinalizeRollappPacketsByReceiver: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sender", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvents - } - 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 ErrInvalidLengthEvents - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthEvents - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Sender = 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 ErrIntOverflowEvents - } - 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 ErrInvalidLengthEvents - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthEvents - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.RollappId = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvents - } - 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 ErrInvalidLengthEvents - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthEvents - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Receiver = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 4: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) - } - m.Height = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvents - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Height |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field FinalizedNum", wireType) - } - m.FinalizedNum = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowEvents - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.FinalizedNum |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipEvents(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthEvents - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func skipEvents(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/delayedack/types/keys.go b/x/delayedack/types/keys.go index b32a8cdb3..a4ada6e9e 100644 --- a/x/delayedack/types/keys.go +++ b/x/delayedack/types/keys.go @@ -14,6 +14,4 @@ const ( MemStoreKey = "mem_delayedack" ) -func KeyPrefix(p string) []byte { - return []byte(p) -} +var PendingPacketsByAddressKeyPrefix = []byte{0x01} diff --git a/x/delayedack/types/msgs.go b/x/delayedack/types/msgs.go index d0f83822d..dd8f024b8 100644 --- a/x/delayedack/types/msgs.go +++ b/x/delayedack/types/msgs.go @@ -4,6 +4,8 @@ import ( "errors" "fmt" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -12,6 +14,16 @@ import ( commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" ) +const ( + TypeMsgFinalizedPacket = "finalized_packet" + TypeMsgFinalizedPacketByPacketKey = "finalized_packet_by_packet_key" +) + +var ( + _ legacytx.LegacyMsg = &MsgFinalizePacket{} + _ legacytx.LegacyMsg = &MsgFinalizePacketByPacketKey{} +) + func (m MsgFinalizePacket) ValidateBasic() error { _, err := sdk.AccAddressFromBech32(m.Sender) if err != nil { @@ -75,3 +87,29 @@ func (m MsgFinalizePacketByPacketKey) MustDecodePacketKey() []byte { } return packetKey } + +func (m *MsgFinalizePacket) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(m) + return sdk.MustSortJSON(bz) +} + +func (m *MsgFinalizePacket) Route() string { + return RouterKey +} + +func (m *MsgFinalizePacket) Type() string { + return TypeMsgFinalizedPacket +} + +func (m *MsgFinalizePacketByPacketKey) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(m) + return sdk.MustSortJSON(bz) +} + +func (m *MsgFinalizePacketByPacketKey) Route() string { + return RouterKey +} + +func (m *MsgFinalizePacketByPacketKey) Type() string { + return TypeMsgFinalizedPacketByPacketKey +} diff --git a/x/delayedack/types/query.pb.go b/x/delayedack/types/query.pb.go index ef1414040..d349fa7b7 100644 --- a/x/delayedack/types/query.pb.go +++ b/x/delayedack/types/query.pb.go @@ -234,24 +234,23 @@ func (m *QueryRollappPacketListResponse) GetPagination() *query.PageResponse { return nil } -type QueryPendingPacketsByReceiverRequest struct { - RollappId string `protobuf:"bytes,1,opt,name=rollappId,proto3" json:"rollappId,omitempty"` - Receiver string `protobuf:"bytes,2,opt,name=receiver,proto3" json:"receiver,omitempty"` - Pagination *query.PageRequest `protobuf:"bytes,3,opt,name=pagination,proto3" json:"pagination,omitempty"` +type QueryPendingPacketsByAddressRequest struct { + Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` + Pagination *query.PageRequest `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } -func (m *QueryPendingPacketsByReceiverRequest) Reset() { *m = QueryPendingPacketsByReceiverRequest{} } -func (m *QueryPendingPacketsByReceiverRequest) String() string { return proto.CompactTextString(m) } -func (*QueryPendingPacketsByReceiverRequest) ProtoMessage() {} -func (*QueryPendingPacketsByReceiverRequest) Descriptor() ([]byte, []int) { +func (m *QueryPendingPacketsByAddressRequest) Reset() { *m = QueryPendingPacketsByAddressRequest{} } +func (m *QueryPendingPacketsByAddressRequest) String() string { return proto.CompactTextString(m) } +func (*QueryPendingPacketsByAddressRequest) ProtoMessage() {} +func (*QueryPendingPacketsByAddressRequest) Descriptor() ([]byte, []int) { return fileDescriptor_0d5f080aa12bfc36, []int{4} } -func (m *QueryPendingPacketsByReceiverRequest) XXX_Unmarshal(b []byte) error { +func (m *QueryPendingPacketsByAddressRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryPendingPacketsByReceiverRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryPendingPacketsByAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryPendingPacketsByReceiverRequest.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryPendingPacketsByAddressRequest.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -261,58 +260,51 @@ func (m *QueryPendingPacketsByReceiverRequest) XXX_Marshal(b []byte, determinist return b[:n], nil } } -func (m *QueryPendingPacketsByReceiverRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryPendingPacketsByReceiverRequest.Merge(m, src) +func (m *QueryPendingPacketsByAddressRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPendingPacketsByAddressRequest.Merge(m, src) } -func (m *QueryPendingPacketsByReceiverRequest) XXX_Size() int { +func (m *QueryPendingPacketsByAddressRequest) XXX_Size() int { return m.Size() } -func (m *QueryPendingPacketsByReceiverRequest) XXX_DiscardUnknown() { - xxx_messageInfo_QueryPendingPacketsByReceiverRequest.DiscardUnknown(m) +func (m *QueryPendingPacketsByAddressRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPendingPacketsByAddressRequest.DiscardUnknown(m) } -var xxx_messageInfo_QueryPendingPacketsByReceiverRequest proto.InternalMessageInfo +var xxx_messageInfo_QueryPendingPacketsByAddressRequest proto.InternalMessageInfo -func (m *QueryPendingPacketsByReceiverRequest) GetRollappId() string { +func (m *QueryPendingPacketsByAddressRequest) GetAddress() string { if m != nil { - return m.RollappId - } - return "" -} - -func (m *QueryPendingPacketsByReceiverRequest) GetReceiver() string { - if m != nil { - return m.Receiver + return m.Address } return "" } -func (m *QueryPendingPacketsByReceiverRequest) GetPagination() *query.PageRequest { +func (m *QueryPendingPacketsByAddressRequest) GetPagination() *query.PageRequest { if m != nil { return m.Pagination } return nil } -type QueryPendingPacketByReceiverListResponse struct { +type QueryPendingPacketByAddressListResponse struct { RollappPackets []types.RollappPacket `protobuf:"bytes,1,rep,name=rollappPackets,proto3" json:"rollappPackets"` Pagination *query.PageResponse `protobuf:"bytes,2,opt,name=pagination,proto3" json:"pagination,omitempty"` } -func (m *QueryPendingPacketByReceiverListResponse) Reset() { - *m = QueryPendingPacketByReceiverListResponse{} +func (m *QueryPendingPacketByAddressListResponse) Reset() { + *m = QueryPendingPacketByAddressListResponse{} } -func (m *QueryPendingPacketByReceiverListResponse) String() string { return proto.CompactTextString(m) } -func (*QueryPendingPacketByReceiverListResponse) ProtoMessage() {} -func (*QueryPendingPacketByReceiverListResponse) Descriptor() ([]byte, []int) { +func (m *QueryPendingPacketByAddressListResponse) String() string { return proto.CompactTextString(m) } +func (*QueryPendingPacketByAddressListResponse) ProtoMessage() {} +func (*QueryPendingPacketByAddressListResponse) Descriptor() ([]byte, []int) { return fileDescriptor_0d5f080aa12bfc36, []int{5} } -func (m *QueryPendingPacketByReceiverListResponse) XXX_Unmarshal(b []byte) error { +func (m *QueryPendingPacketByAddressListResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) } -func (m *QueryPendingPacketByReceiverListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { +func (m *QueryPendingPacketByAddressListResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { if deterministic { - return xxx_messageInfo_QueryPendingPacketByReceiverListResponse.Marshal(b, m, deterministic) + return xxx_messageInfo_QueryPendingPacketByAddressListResponse.Marshal(b, m, deterministic) } else { b = b[:cap(b)] n, err := m.MarshalToSizedBuffer(b) @@ -322,26 +314,26 @@ func (m *QueryPendingPacketByReceiverListResponse) XXX_Marshal(b []byte, determi return b[:n], nil } } -func (m *QueryPendingPacketByReceiverListResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_QueryPendingPacketByReceiverListResponse.Merge(m, src) +func (m *QueryPendingPacketByAddressListResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryPendingPacketByAddressListResponse.Merge(m, src) } -func (m *QueryPendingPacketByReceiverListResponse) XXX_Size() int { +func (m *QueryPendingPacketByAddressListResponse) XXX_Size() int { return m.Size() } -func (m *QueryPendingPacketByReceiverListResponse) XXX_DiscardUnknown() { - xxx_messageInfo_QueryPendingPacketByReceiverListResponse.DiscardUnknown(m) +func (m *QueryPendingPacketByAddressListResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryPendingPacketByAddressListResponse.DiscardUnknown(m) } -var xxx_messageInfo_QueryPendingPacketByReceiverListResponse proto.InternalMessageInfo +var xxx_messageInfo_QueryPendingPacketByAddressListResponse proto.InternalMessageInfo -func (m *QueryPendingPacketByReceiverListResponse) GetRollappPackets() []types.RollappPacket { +func (m *QueryPendingPacketByAddressListResponse) GetRollappPackets() []types.RollappPacket { if m != nil { return m.RollappPackets } return nil } -func (m *QueryPendingPacketByReceiverListResponse) GetPagination() *query.PageResponse { +func (m *QueryPendingPacketByAddressListResponse) GetPagination() *query.PageResponse { if m != nil { return m.Pagination } @@ -353,8 +345,8 @@ func init() { proto.RegisterType((*QueryParamsResponse)(nil), "dymensionxyz.dymension.delayedack.QueryParamsResponse") proto.RegisterType((*QueryRollappPacketsRequest)(nil), "dymensionxyz.dymension.delayedack.QueryRollappPacketsRequest") proto.RegisterType((*QueryRollappPacketListResponse)(nil), "dymensionxyz.dymension.delayedack.QueryRollappPacketListResponse") - proto.RegisterType((*QueryPendingPacketsByReceiverRequest)(nil), "dymensionxyz.dymension.delayedack.QueryPendingPacketsByReceiverRequest") - proto.RegisterType((*QueryPendingPacketByReceiverListResponse)(nil), "dymensionxyz.dymension.delayedack.QueryPendingPacketByReceiverListResponse") + proto.RegisterType((*QueryPendingPacketsByAddressRequest)(nil), "dymensionxyz.dymension.delayedack.QueryPendingPacketsByAddressRequest") + proto.RegisterType((*QueryPendingPacketByAddressListResponse)(nil), "dymensionxyz.dymension.delayedack.QueryPendingPacketByAddressListResponse") } func init() { @@ -362,48 +354,48 @@ func init() { } var fileDescriptor_0d5f080aa12bfc36 = []byte{ - // 645 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0x4f, 0x6f, 0x12, 0x41, - 0x14, 0x67, 0x68, 0x4b, 0xec, 0x34, 0xe9, 0x61, 0xec, 0x81, 0xac, 0xcd, 0x5a, 0x37, 0xfe, 0xa1, - 0x2a, 0x33, 0x81, 0x46, 0x3d, 0x35, 0xa6, 0x24, 0x4a, 0x8c, 0x1e, 0xe8, 0xda, 0x13, 0x07, 0xcd, - 0x00, 0x93, 0x75, 0x53, 0xd8, 0xd9, 0xee, 0x0e, 0xa4, 0x6b, 0xc3, 0xc5, 0x93, 0x37, 0x4d, 0xfc, - 0x02, 0x1e, 0x8d, 0xdf, 0xc3, 0xa4, 0x37, 0x9b, 0x78, 0xd0, 0x93, 0x31, 0xe0, 0x07, 0x31, 0x3b, - 0xb3, 0x2c, 0x50, 0xa0, 0x6c, 0xb9, 0x79, 0x63, 0x77, 0xdf, 0xef, 0xfd, 0xfe, 0xcc, 0x7b, 0x03, - 0xcc, 0x37, 0x82, 0x16, 0x73, 0x7c, 0x9b, 0x3b, 0xc7, 0xc1, 0x5b, 0x12, 0x3f, 0x90, 0x06, 0x6b, - 0xd2, 0x80, 0x35, 0x68, 0xfd, 0x90, 0x1c, 0xb5, 0x99, 0x17, 0x60, 0xd7, 0xe3, 0x82, 0xa3, 0x1b, - 0xa3, 0xe5, 0x38, 0x7e, 0xc0, 0xc3, 0x72, 0x6d, 0xc3, 0xe2, 0x16, 0x97, 0xd5, 0x24, 0xfc, 0xa5, - 0x80, 0xda, 0xa6, 0xc5, 0xb9, 0xd5, 0x64, 0x84, 0xba, 0x36, 0xa1, 0x8e, 0xc3, 0x05, 0x15, 0x36, - 0x77, 0xfc, 0xe8, 0xeb, 0xdd, 0x3a, 0xf7, 0x5b, 0xdc, 0x27, 0x35, 0xea, 0x33, 0xc5, 0x47, 0x3a, - 0x85, 0x1a, 0x13, 0xb4, 0x40, 0x5c, 0x6a, 0xd9, 0x8e, 0x2c, 0x8e, 0x6a, 0xf1, 0x7c, 0xc5, 0x2e, - 0xf5, 0x68, 0x2b, 0xee, 0x3d, 0xa3, 0xbe, 0xce, 0x5b, 0x2d, 0xee, 0x10, 0x5f, 0x50, 0xd1, 0x1e, - 0xd4, 0x16, 0x2f, 0xae, 0xf5, 0x78, 0xb3, 0x49, 0x5d, 0xf7, 0xb5, 0x4b, 0xeb, 0x87, 0x4c, 0x28, - 0x8c, 0xb1, 0x01, 0xd1, 0x7e, 0xa8, 0xb8, 0x22, 0x49, 0x4d, 0x76, 0xd4, 0x66, 0xbe, 0x30, 0x5e, - 0xc1, 0xab, 0x63, 0x6f, 0x7d, 0x97, 0x3b, 0x3e, 0x43, 0x65, 0x98, 0x51, 0xe2, 0xb2, 0x60, 0x0b, - 0xe4, 0xd6, 0x8a, 0xdb, 0x78, 0x6e, 0xa0, 0x58, 0xb5, 0x28, 0x2d, 0x9f, 0xfe, 0xbe, 0x9e, 0x32, - 0x23, 0xb8, 0xf1, 0x3e, 0x0d, 0x35, 0x49, 0x60, 0x2a, 0x4d, 0x15, 0x29, 0x69, 0x40, 0x8f, 0x36, - 0xe1, 0x6a, 0x24, 0xf6, 0x59, 0x43, 0x52, 0xad, 0x9a, 0xc3, 0x17, 0x68, 0x17, 0x66, 0x94, 0xed, - 0x6c, 0x7a, 0x0b, 0xe4, 0xd6, 0x8b, 0xb7, 0x66, 0xa9, 0x50, 0xbe, 0xf1, 0x4b, 0x59, 0x6c, 0x46, - 0x20, 0xf4, 0x04, 0x2e, 0x8b, 0xc0, 0x65, 0xd9, 0x25, 0x09, 0x2e, 0xcc, 0x01, 0x8f, 0x09, 0xc4, - 0x07, 0x81, 0xcb, 0x4c, 0x09, 0x47, 0x4f, 0x21, 0x1c, 0x1e, 0x6e, 0x76, 0x59, 0xe6, 0x71, 0x1b, - 0xab, 0x49, 0xc0, 0xe1, 0x24, 0x60, 0x35, 0x79, 0xd1, 0x24, 0xe0, 0x0a, 0xb5, 0x58, 0xe4, 0xcf, - 0x1c, 0x41, 0x1a, 0xdf, 0x00, 0xd4, 0x27, 0xa3, 0x78, 0x61, 0xfb, 0x22, 0x8e, 0xbd, 0x0a, 0xd7, - 0xbd, 0xb1, 0x9c, 0xb2, 0x60, 0x6b, 0x29, 0xb7, 0x56, 0xbc, 0x7f, 0x19, 0xed, 0xd1, 0x09, 0x9c, - 0xeb, 0x84, 0xca, 0x63, 0x36, 0xd2, 0xd2, 0xc6, 0x9d, 0xb9, 0x36, 0x94, 0xb0, 0x31, 0x1f, 0x5f, - 0x00, 0xbc, 0xa9, 0x66, 0x86, 0x39, 0x0d, 0xdb, 0xb1, 0x22, 0x82, 0x52, 0x60, 0xb2, 0x3a, 0xb3, - 0x3b, 0xcc, 0x4b, 0x76, 0xb8, 0x1a, 0xbc, 0xe2, 0x45, 0x00, 0xa9, 0x66, 0xd5, 0x8c, 0x9f, 0xcf, - 0x45, 0xbe, 0xb4, 0x70, 0xe4, 0xdf, 0x01, 0xcc, 0x4d, 0x4a, 0x1d, 0x2a, 0xfd, 0xef, 0xc2, 0x2f, - 0x7e, 0x5e, 0x81, 0x2b, 0xd2, 0x11, 0xfa, 0x0a, 0x60, 0x46, 0xad, 0x1c, 0x7a, 0x90, 0x60, 0x3b, - 0x27, 0x77, 0x5f, 0x7b, 0x78, 0x59, 0x98, 0xd2, 0x63, 0x14, 0xde, 0xfd, 0xf8, 0xfb, 0x29, 0x7d, - 0x0f, 0x6d, 0x93, 0xa4, 0x57, 0x1c, 0xfa, 0x09, 0x20, 0x2c, 0x33, 0x31, 0x88, 0x63, 0x37, 0x29, - 0xf3, 0xd4, 0x5b, 0x43, 0xdb, 0x5b, 0x08, 0x3e, 0x7a, 0xd8, 0x46, 0x59, 0x7a, 0xd8, 0x43, 0x8f, - 0x13, 0x79, 0x90, 0xec, 0xe4, 0x24, 0x1e, 0xde, 0x2e, 0x39, 0x51, 0x77, 0x4c, 0x17, 0x7d, 0x48, - 0xc3, 0x6b, 0xa1, 0xb3, 0x19, 0xbb, 0x80, 0xca, 0x89, 0x43, 0xbe, 0x78, 0x9b, 0xb4, 0xe7, 0x0b, - 0x35, 0x9a, 0x3e, 0xeb, 0x46, 0x55, 0xda, 0x3f, 0x40, 0x66, 0x12, 0xfb, 0xaa, 0x5f, 0x7e, 0xb0, - 0x9d, 0xf9, 0xa9, 0x79, 0x0c, 0xbe, 0x76, 0x4b, 0xfb, 0xa7, 0x3d, 0x1d, 0x9c, 0xf5, 0x74, 0xf0, - 0xa7, 0xa7, 0x83, 0x8f, 0x7d, 0x3d, 0x75, 0xd6, 0xd7, 0x53, 0xbf, 0xfa, 0x7a, 0xaa, 0xfa, 0xc8, - 0xb2, 0xc5, 0x9b, 0x76, 0x2d, 0x5c, 0x9c, 0x59, 0xbc, 0x9d, 0x1d, 0x72, 0x3c, 0x4a, 0x1e, 0xde, - 0xc0, 0x7e, 0x2d, 0x23, 0xff, 0xc2, 0x76, 0xfe, 0x05, 0x00, 0x00, 0xff, 0xff, 0x1b, 0xc8, 0xfd, - 0xca, 0x06, 0x08, 0x00, 0x00, + // 644 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0xcf, 0x4e, 0x13, 0x41, + 0x18, 0xef, 0x14, 0xa8, 0x61, 0x48, 0x38, 0x8c, 0x1c, 0x36, 0x1b, 0xb2, 0xe2, 0x1a, 0x05, 0x54, + 0x66, 0xd2, 0x12, 0xf5, 0x44, 0x0c, 0x24, 0xd0, 0x68, 0x34, 0x81, 0xd5, 0x13, 0x07, 0xcd, 0xb4, + 0x3b, 0x59, 0x37, 0xb4, 0x3b, 0xcb, 0xce, 0x94, 0xb0, 0x12, 0x2e, 0x5e, 0xf4, 0x48, 0xe2, 0x5b, + 0xf8, 0x1e, 0x26, 0x9c, 0x0c, 0x89, 0x07, 0x3d, 0x19, 0x03, 0xbe, 0x87, 0x66, 0x67, 0xb6, 0xdb, + 0x96, 0xb6, 0x74, 0xe9, 0xcd, 0x5b, 0x67, 0xfa, 0xfd, 0xe6, 0xf7, 0x67, 0xbe, 0x6f, 0x16, 0xae, + 0xb8, 0x71, 0x93, 0x05, 0xc2, 0xe7, 0xc1, 0x61, 0xfc, 0x9e, 0x64, 0x0b, 0xe2, 0xb2, 0x06, 0x8d, + 0x99, 0x4b, 0xeb, 0x7b, 0x64, 0xbf, 0xc5, 0xa2, 0x18, 0x87, 0x11, 0x97, 0x1c, 0xdd, 0xee, 0x2e, + 0xc7, 0xd9, 0x02, 0x77, 0xca, 0xcd, 0x39, 0x8f, 0x7b, 0x5c, 0x55, 0x93, 0xe4, 0x97, 0x06, 0x9a, + 0xf3, 0x1e, 0xe7, 0x5e, 0x83, 0x11, 0x1a, 0xfa, 0x84, 0x06, 0x01, 0x97, 0x54, 0xfa, 0x3c, 0x10, + 0xe9, 0xbf, 0xf7, 0xeb, 0x5c, 0x34, 0xb9, 0x20, 0x35, 0x2a, 0x98, 0xe6, 0x23, 0x07, 0xe5, 0x1a, + 0x93, 0xb4, 0x4c, 0x42, 0xea, 0xf9, 0x81, 0x2a, 0x4e, 0x6b, 0xf1, 0x68, 0xc5, 0x21, 0x8d, 0x68, + 0x33, 0x3b, 0x7b, 0x48, 0x7d, 0x9d, 0x37, 0x9b, 0x3c, 0x20, 0x42, 0x52, 0xd9, 0x6a, 0xd7, 0x56, + 0xae, 0xae, 0x8d, 0x78, 0xa3, 0x41, 0xc3, 0xf0, 0x6d, 0x48, 0xeb, 0x7b, 0x4c, 0x6a, 0x8c, 0x3d, + 0x07, 0xd1, 0x4e, 0xa2, 0x78, 0x5b, 0x91, 0x3a, 0x6c, 0xbf, 0xc5, 0x84, 0xb4, 0xdf, 0xc0, 0x9b, + 0x3d, 0xbb, 0x22, 0xe4, 0x81, 0x60, 0xa8, 0x0a, 0x4b, 0x5a, 0x9c, 0x01, 0x16, 0xc0, 0xd2, 0x4c, + 0x65, 0x19, 0x8f, 0x0c, 0x14, 0xeb, 0x23, 0x36, 0x26, 0x4f, 0x7f, 0xdd, 0x2a, 0x38, 0x29, 0xdc, + 0xfe, 0x54, 0x84, 0xa6, 0x22, 0x70, 0xb4, 0xa6, 0x6d, 0x25, 0xa9, 0x4d, 0x8f, 0xe6, 0xe1, 0x74, + 0x2a, 0xf6, 0x99, 0xab, 0xa8, 0xa6, 0x9d, 0xce, 0x06, 0x5a, 0x83, 0x25, 0x6d, 0xdb, 0x28, 0x2e, + 0x80, 0xa5, 0xd9, 0xca, 0xdd, 0x61, 0x2a, 0xb4, 0x6f, 0xfc, 0x4a, 0x15, 0x3b, 0x29, 0x08, 0x6d, + 0xc2, 0x49, 0x19, 0x87, 0xcc, 0x98, 0x50, 0xe0, 0xf2, 0x08, 0x70, 0x8f, 0x40, 0xfc, 0x3a, 0x0e, + 0x99, 0xa3, 0xe0, 0x68, 0x0b, 0xc2, 0xce, 0xe5, 0x1a, 0x93, 0x2a, 0x8f, 0x7b, 0x58, 0x77, 0x02, + 0x4e, 0x3a, 0x01, 0xeb, 0xce, 0x4b, 0x3b, 0x01, 0x6f, 0x53, 0x8f, 0xa5, 0xfe, 0x9c, 0x2e, 0xa4, + 0xfd, 0x15, 0x40, 0xab, 0x3f, 0x8a, 0x17, 0xbe, 0x90, 0x59, 0xec, 0xbb, 0x70, 0x36, 0xea, 0xc9, + 0xc9, 0x00, 0x0b, 0x13, 0x4b, 0x33, 0x95, 0x87, 0xd7, 0xd1, 0x9e, 0xde, 0xc0, 0xa5, 0x93, 0x50, + 0xb5, 0xc7, 0x46, 0x51, 0xd9, 0x58, 0x1c, 0x69, 0x43, 0x0b, 0xeb, 0xf1, 0xf1, 0x11, 0xc0, 0x3b, + 0xba, 0x67, 0x58, 0xe0, 0xfa, 0x81, 0x97, 0x12, 0x6c, 0xc4, 0xeb, 0xae, 0x1b, 0x31, 0x91, 0xdd, + 0xad, 0x01, 0x6f, 0x50, 0xbd, 0x93, 0xde, 0x6c, 0x7b, 0x79, 0x29, 0xd1, 0xe2, 0xd8, 0x89, 0x7e, + 0x03, 0x70, 0xb1, 0x5f, 0x49, 0x26, 0xe4, 0xbf, 0x8b, 0xb6, 0x72, 0x32, 0x05, 0xa7, 0x94, 0x21, + 0xf4, 0x05, 0xc0, 0x92, 0x1e, 0x28, 0xf4, 0x28, 0xc7, 0xec, 0xf5, 0x4f, 0xb6, 0xf9, 0xf8, 0xba, + 0x30, 0xad, 0xc7, 0x2e, 0x7f, 0xf8, 0xfe, 0xe7, 0x73, 0xf1, 0x01, 0x5a, 0x26, 0x79, 0x1f, 0x30, + 0xf4, 0x03, 0x40, 0x58, 0x65, 0xb2, 0x1d, 0xc7, 0x5a, 0x5e, 0xe6, 0x81, 0x6f, 0x82, 0xb9, 0x3e, + 0x16, 0xbc, 0xfb, 0xb2, 0xed, 0xaa, 0xf2, 0xb0, 0x8e, 0x9e, 0xe6, 0xf2, 0xa0, 0xd8, 0xc9, 0x51, + 0xf6, 0xee, 0x1c, 0x93, 0x23, 0xfd, 0x82, 0x1c, 0xa3, 0xbf, 0x00, 0x9a, 0x89, 0xb3, 0xc1, 0x9d, + 0x8e, 0xb6, 0x72, 0x67, 0x7c, 0xe5, 0xa8, 0x98, 0xcf, 0xc7, 0x3a, 0x67, 0x60, 0xa3, 0xdb, 0x2f, + 0x95, 0xf7, 0x2a, 0xda, 0xcc, 0xe3, 0x5d, 0x1f, 0xb7, 0x12, 0xb1, 0x3a, 0xf3, 0x0f, 0x58, 0xb4, + 0x92, 0x85, 0x91, 0x8e, 0xea, 0xf1, 0xc6, 0xce, 0xe9, 0xb9, 0x05, 0xce, 0xce, 0x2d, 0xf0, 0xfb, + 0xdc, 0x02, 0x27, 0x17, 0x56, 0xe1, 0xec, 0xc2, 0x2a, 0xfc, 0xbc, 0xb0, 0x0a, 0xbb, 0x4f, 0x3c, + 0x5f, 0xbe, 0x6b, 0xd5, 0x92, 0x41, 0x19, 0x46, 0x75, 0xb0, 0x4a, 0x0e, 0xbb, 0xf9, 0x92, 0xf7, + 0x54, 0xd4, 0x4a, 0xea, 0x83, 0xb4, 0xfa, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x19, 0xae, 0x61, 0xeb, + 0xd4, 0x07, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -423,7 +415,7 @@ type QueryClient interface { // Queries a list of RollappPacket items by rollappID. GetPackets(ctx context.Context, in *QueryRollappPacketsRequest, opts ...grpc.CallOption) (*QueryRollappPacketListResponse, error) // Queries a list of pending RollappPacket items by rollappID and receiver. - GetPendingPacketsByReceiver(ctx context.Context, in *QueryPendingPacketsByReceiverRequest, opts ...grpc.CallOption) (*QueryPendingPacketByReceiverListResponse, error) + GetPendingPacketsByAddress(ctx context.Context, in *QueryPendingPacketsByAddressRequest, opts ...grpc.CallOption) (*QueryPendingPacketByAddressListResponse, error) } type queryClient struct { @@ -452,9 +444,9 @@ func (c *queryClient) GetPackets(ctx context.Context, in *QueryRollappPacketsReq return out, nil } -func (c *queryClient) GetPendingPacketsByReceiver(ctx context.Context, in *QueryPendingPacketsByReceiverRequest, opts ...grpc.CallOption) (*QueryPendingPacketByReceiverListResponse, error) { - out := new(QueryPendingPacketByReceiverListResponse) - err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.delayedack.Query/GetPendingPacketsByReceiver", in, out, opts...) +func (c *queryClient) GetPendingPacketsByAddress(ctx context.Context, in *QueryPendingPacketsByAddressRequest, opts ...grpc.CallOption) (*QueryPendingPacketByAddressListResponse, error) { + out := new(QueryPendingPacketByAddressListResponse) + err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.delayedack.Query/GetPendingPacketsByAddress", in, out, opts...) if err != nil { return nil, err } @@ -468,7 +460,7 @@ type QueryServer interface { // Queries a list of RollappPacket items by rollappID. GetPackets(context.Context, *QueryRollappPacketsRequest) (*QueryRollappPacketListResponse, error) // Queries a list of pending RollappPacket items by rollappID and receiver. - GetPendingPacketsByReceiver(context.Context, *QueryPendingPacketsByReceiverRequest) (*QueryPendingPacketByReceiverListResponse, error) + GetPendingPacketsByAddress(context.Context, *QueryPendingPacketsByAddressRequest) (*QueryPendingPacketByAddressListResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -481,8 +473,8 @@ func (*UnimplementedQueryServer) Params(ctx context.Context, req *QueryParamsReq func (*UnimplementedQueryServer) GetPackets(ctx context.Context, req *QueryRollappPacketsRequest) (*QueryRollappPacketListResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetPackets not implemented") } -func (*UnimplementedQueryServer) GetPendingPacketsByReceiver(ctx context.Context, req *QueryPendingPacketsByReceiverRequest) (*QueryPendingPacketByReceiverListResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetPendingPacketsByReceiver not implemented") +func (*UnimplementedQueryServer) GetPendingPacketsByAddress(ctx context.Context, req *QueryPendingPacketsByAddressRequest) (*QueryPendingPacketByAddressListResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPendingPacketsByAddress not implemented") } func RegisterQueryServer(s grpc1.Server, srv QueryServer) { @@ -525,20 +517,20 @@ func _Query_GetPackets_Handler(srv interface{}, ctx context.Context, dec func(in return interceptor(ctx, in, info, handler) } -func _Query_GetPendingPacketsByReceiver_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(QueryPendingPacketsByReceiverRequest) +func _Query_GetPendingPacketsByAddress_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryPendingPacketsByAddressRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(QueryServer).GetPendingPacketsByReceiver(ctx, in) + return srv.(QueryServer).GetPendingPacketsByAddress(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/dymensionxyz.dymension.delayedack.Query/GetPendingPacketsByReceiver", + FullMethod: "/dymensionxyz.dymension.delayedack.Query/GetPendingPacketsByAddress", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(QueryServer).GetPendingPacketsByReceiver(ctx, req.(*QueryPendingPacketsByReceiverRequest)) + return srv.(QueryServer).GetPendingPacketsByAddress(ctx, req.(*QueryPendingPacketsByAddressRequest)) } return interceptor(ctx, in, info, handler) } @@ -556,8 +548,8 @@ var _Query_serviceDesc = grpc.ServiceDesc{ Handler: _Query_GetPackets_Handler, }, { - MethodName: "GetPendingPacketsByReceiver", - Handler: _Query_GetPendingPacketsByReceiver_Handler, + MethodName: "GetPendingPacketsByAddress", + Handler: _Query_GetPendingPacketsByAddress_Handler, }, }, Streams: []grpc.StreamDesc{}, @@ -721,7 +713,7 @@ func (m *QueryRollappPacketListResponse) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } -func (m *QueryPendingPacketsByReceiverRequest) Marshal() (dAtA []byte, err error) { +func (m *QueryPendingPacketsByAddressRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -731,12 +723,12 @@ func (m *QueryPendingPacketsByReceiverRequest) Marshal() (dAtA []byte, err error return dAtA[:n], nil } -func (m *QueryPendingPacketsByReceiverRequest) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryPendingPacketsByAddressRequest) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryPendingPacketsByReceiverRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryPendingPacketsByAddressRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -751,26 +743,19 @@ func (m *QueryPendingPacketsByReceiverRequest) MarshalToSizedBuffer(dAtA []byte) i = encodeVarintQuery(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x1a - } - if len(m.Receiver) > 0 { - i -= len(m.Receiver) - copy(dAtA[i:], m.Receiver) - i = encodeVarintQuery(dAtA, i, uint64(len(m.Receiver))) - i-- dAtA[i] = 0x12 } - if len(m.RollappId) > 0 { - i -= len(m.RollappId) - copy(dAtA[i:], m.RollappId) - i = encodeVarintQuery(dAtA, i, uint64(len(m.RollappId))) + if len(m.Address) > 0 { + i -= len(m.Address) + copy(dAtA[i:], m.Address) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Address))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } -func (m *QueryPendingPacketByReceiverListResponse) Marshal() (dAtA []byte, err error) { +func (m *QueryPendingPacketByAddressListResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -780,12 +765,12 @@ func (m *QueryPendingPacketByReceiverListResponse) Marshal() (dAtA []byte, err e return dAtA[:n], nil } -func (m *QueryPendingPacketByReceiverListResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *QueryPendingPacketByAddressListResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *QueryPendingPacketByReceiverListResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *QueryPendingPacketByAddressListResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int @@ -892,17 +877,13 @@ func (m *QueryRollappPacketListResponse) Size() (n int) { return n } -func (m *QueryPendingPacketsByReceiverRequest) Size() (n int) { +func (m *QueryPendingPacketsByAddressRequest) Size() (n int) { if m == nil { return 0 } var l int _ = l - l = len(m.RollappId) - if l > 0 { - n += 1 + l + sovQuery(uint64(l)) - } - l = len(m.Receiver) + l = len(m.Address) if l > 0 { n += 1 + l + sovQuery(uint64(l)) } @@ -913,7 +894,7 @@ func (m *QueryPendingPacketsByReceiverRequest) Size() (n int) { return n } -func (m *QueryPendingPacketByReceiverListResponse) Size() (n int) { +func (m *QueryPendingPacketByAddressListResponse) Size() (n int) { if m == nil { return 0 } @@ -1347,7 +1328,7 @@ func (m *QueryRollappPacketListResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryPendingPacketsByReceiverRequest) Unmarshal(dAtA []byte) error { +func (m *QueryPendingPacketsByAddressRequest) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1370,15 +1351,15 @@ func (m *QueryPendingPacketsByReceiverRequest) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryPendingPacketsByReceiverRequest: wiretype end group for non-group") + return fmt.Errorf("proto: QueryPendingPacketsByAddressRequest: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryPendingPacketsByReceiverRequest: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryPendingPacketsByAddressRequest: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RollappId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -1406,41 +1387,9 @@ func (m *QueryPendingPacketsByReceiverRequest) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RollappId = string(dAtA[iNdEx:postIndex]) + m.Address = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Receiver", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowQuery - } - 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 ErrInvalidLengthQuery - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthQuery - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Receiver = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 3: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Pagination", wireType) } @@ -1497,7 +1446,7 @@ func (m *QueryPendingPacketsByReceiverRequest) Unmarshal(dAtA []byte) error { } return nil } -func (m *QueryPendingPacketByReceiverListResponse) Unmarshal(dAtA []byte) error { +func (m *QueryPendingPacketByAddressListResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -1520,10 +1469,10 @@ func (m *QueryPendingPacketByReceiverListResponse) Unmarshal(dAtA []byte) error fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: QueryPendingPacketByReceiverListResponse: wiretype end group for non-group") + return fmt.Errorf("proto: QueryPendingPacketByAddressListResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: QueryPendingPacketByReceiverListResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: QueryPendingPacketByAddressListResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: diff --git a/x/delayedack/types/query.pb.gw.go b/x/delayedack/types/query.pb.gw.go index 2032bdabf..fcd4b965a 100644 --- a/x/delayedack/types/query.pb.gw.go +++ b/x/delayedack/types/query.pb.gw.go @@ -153,11 +153,11 @@ func local_request_Query_GetPackets_0(ctx context.Context, marshaler runtime.Mar } var ( - filter_Query_GetPendingPacketsByReceiver_0 = &utilities.DoubleArray{Encoding: map[string]int{"rollappId": 0, "receiver": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} + filter_Query_GetPendingPacketsByAddress_0 = &utilities.DoubleArray{Encoding: map[string]int{"address": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} ) -func request_Query_GetPendingPacketsByReceiver_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryPendingPacketsByReceiverRequest +func request_Query_GetPendingPacketsByAddress_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPendingPacketsByAddressRequest var metadata runtime.ServerMetadata var ( @@ -167,42 +167,31 @@ func request_Query_GetPendingPacketsByReceiver_0(ctx context.Context, marshaler _ = err ) - val, ok = pathParams["rollappId"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "rollappId") - } - - protoReq.RollappId, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "rollappId", err) - } - - val, ok = pathParams["receiver"] + val, ok = pathParams["address"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "receiver") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") } - protoReq.Receiver, err = runtime.String(val) + protoReq.Address, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "receiver", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GetPendingPacketsByReceiver_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GetPendingPacketsByAddress_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := client.GetPendingPacketsByReceiver(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + msg, err := client.GetPendingPacketsByAddress(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } -func local_request_Query_GetPendingPacketsByReceiver_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryPendingPacketsByReceiverRequest +func local_request_Query_GetPendingPacketsByAddress_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryPendingPacketsByAddressRequest var metadata runtime.ServerMetadata var ( @@ -212,36 +201,25 @@ func local_request_Query_GetPendingPacketsByReceiver_0(ctx context.Context, mars _ = err ) - val, ok = pathParams["rollappId"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "rollappId") - } - - protoReq.RollappId, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "rollappId", err) - } - - val, ok = pathParams["receiver"] + val, ok = pathParams["address"] if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "receiver") + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "address") } - protoReq.Receiver, err = runtime.String(val) + protoReq.Address, err = runtime.String(val) if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "receiver", err) + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "address", err) } if err := req.ParseForm(); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GetPendingPacketsByReceiver_0); err != nil { + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_GetPendingPacketsByAddress_0); err != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.GetPendingPacketsByReceiver(ctx, &protoReq) + msg, err := server.GetPendingPacketsByAddress(ctx, &protoReq) return msg, metadata, err } @@ -298,7 +276,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) - mux.Handle("GET", pattern_Query_GetPendingPacketsByReceiver_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_GetPendingPacketsByAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() var stream runtime.ServerTransportStream @@ -309,7 +287,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := local_request_Query_GetPendingPacketsByReceiver_0(rctx, inboundMarshaler, server, req, pathParams) + resp, md, err := local_request_Query_GetPendingPacketsByAddress_0(rctx, inboundMarshaler, server, req, pathParams) md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { @@ -317,7 +295,7 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv return } - forward_Query_GetPendingPacketsByReceiver_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_GetPendingPacketsByAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -402,7 +380,7 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) - mux.Handle("GET", pattern_Query_GetPendingPacketsByReceiver_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + mux.Handle("GET", pattern_Query_GetPendingPacketsByAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) @@ -411,14 +389,14 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - resp, md, err := request_Query_GetPendingPacketsByReceiver_0(rctx, inboundMarshaler, client, req, pathParams) + resp, md, err := request_Query_GetPendingPacketsByAddress_0(rctx, inboundMarshaler, client, req, pathParams) ctx = runtime.NewServerMetadataContext(ctx, md) if err != nil { runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) return } - forward_Query_GetPendingPacketsByReceiver_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + forward_Query_GetPendingPacketsByAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) }) @@ -430,7 +408,7 @@ var ( pattern_Query_GetPackets_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"dymensionxyz", "dymension", "delayedack", "packets", "rollappId", "status"}, "", runtime.AssumeColonVerbOpt(false))) - pattern_Query_GetPendingPacketsByReceiver_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"dymensionxyz", "dymension", "delayedack", "pending-receiver-packets", "rollappId", "receiver"}, "", runtime.AssumeColonVerbOpt(false))) + pattern_Query_GetPendingPacketsByAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"dymensionxyz", "dymension", "delayedack", "pending-receiver-packets", "address"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -438,5 +416,5 @@ var ( forward_Query_GetPackets_0 = runtime.ForwardResponseMessage - forward_Query_GetPendingPacketsByReceiver_0 = runtime.ForwardResponseMessage + forward_Query_GetPendingPacketsByAddress_0 = runtime.ForwardResponseMessage ) diff --git a/x/dymns/keeper/keeper_suite_test.go b/x/dymns/keeper/keeper_suite_test.go index 6cbff1d3a..8229fcbc0 100644 --- a/x/dymns/keeper/keeper_suite_test.go +++ b/x/dymns/keeper/keeper_suite_test.go @@ -144,6 +144,7 @@ func (s *KeeperTestSuite) SetupTest() { rollappParamsSubspace, nil, nil, nil, nil, bk, + nil, authtypes.NewModuleAddress(govtypes.ModuleName).String(), nil, ) diff --git a/x/eibc/keeper/hooks_test.go b/x/eibc/keeper/hooks_test.go index 95c55d235..6d3a24587 100644 --- a/x/eibc/keeper/hooks_test.go +++ b/x/eibc/keeper/hooks_test.go @@ -59,10 +59,14 @@ 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.UpdateRollappPacketWithStatus(suite.Ctx, *rollappPacket, tc.packetStatus) + suite.Require().NoError(err) + } // delete the rollapp packet err = suite.App.DelayedAckKeeper.DeleteRollappPacket(suite.Ctx, rollappPacket) diff --git a/x/eibc/types/codec.go b/x/eibc/types/codec.go index 39c5ff023..c7e86637c 100644 --- a/x/eibc/types/codec.go +++ b/x/eibc/types/codec.go @@ -4,9 +4,9 @@ import ( "github.com/cosmos/cosmos-sdk/codec" cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/authz" - "github.com/cosmos/cosmos-sdk/types/msgservice" + "github.com/cosmos/cosmos-sdk/x/authz" + authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" ) func RegisterCodec(cdc *codec.LegacyAmino) { @@ -30,5 +30,15 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { var ( Amino = codec.NewLegacyAmino() - ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) + ModuleCdc = codec.NewAminoCodec(Amino) ) + +func init() { + RegisterCodec(Amino) + // Register all Amino interfaces and concrete types on the authz Amino codec so that this can later be + // used to properly serialize MsgGrant and MsgExec instances + sdk.RegisterLegacyAminoCodec(Amino) + RegisterCodec(authzcodec.Amino) + + Amino.Seal() +} diff --git a/x/eibc/types/tx.go b/x/eibc/types/tx.go index d2e0f841a..7bb951d58 100644 --- a/x/eibc/types/tx.go +++ b/x/eibc/types/tx.go @@ -4,6 +4,8 @@ import ( "encoding/hex" "fmt" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" + errorsmod "cosmossdk.io/errors" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -13,6 +15,9 @@ import ( var ( _ = sdk.Msg(&MsgFulfillOrder{}) _ = sdk.Msg(&MsgUpdateDemandOrder{}) + + _ legacytx.LegacyMsg = &MsgFulfillOrder{} + _ legacytx.LegacyMsg = &MsgFulfillOrderAuthorized{} ) func NewMsgFulfillOrder(fulfillerAddress, orderId, expectedFee string) *MsgFulfillOrder { diff --git a/x/gamm/amm_test.go b/x/gamm/amm_test.go index deec4d7b6..3d680067d 100644 --- a/x/gamm/amm_test.go +++ b/x/gamm/amm_test.go @@ -4,11 +4,11 @@ import ( "fmt" "testing" + cometbftproto "github.com/cometbft/cometbft/proto/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/osmosis-labs/osmosis/v15/x/gamm/pool-models/balancer" "github.com/stretchr/testify/suite" - cometbftproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/dymensionxyz/dymension/v3/app/apptesting" "github.com/dymensionxyz/dymension/v3/testutil/sample" ) @@ -47,9 +47,9 @@ func (s *KeeperTestSuite) TestSwapsRevenue() { expRevenue bool }{ { - name: "1% swap fee, 1% taker fee", + name: "1% swap fee, 0.9% taker fee", swapFee: sdk.NewDecWithPrec(1, 2), // 1% - takerFee: sdk.NewDecWithPrec(1, 2), // 1% + takerFee: sdk.NewDecWithPrec(9, 3), // 0.9% expRevenue: true, }, { diff --git a/x/incentives/keeper/msg_server.go b/x/incentives/keeper/msg_server.go index 22110e00d..38cab4039 100644 --- a/x/incentives/keeper/msg_server.go +++ b/x/incentives/keeper/msg_server.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/osmosis-labs/osmosis/v15/osmoutils" - txfeestypes "github.com/osmosis-labs/osmosis/v15/x/txfees/types" "github.com/dymensionxyz/dymension/v3/x/incentives/types" ) @@ -41,7 +40,7 @@ func (server msgServer) CreateGauge(goCtx context.Context, msg *types.MsgCreateG params := server.keeper.GetParams(ctx) fee := params.CreateGaugeBaseFee.Add(params.AddDenomFee.MulRaw(int64(len(msg.Coins)))) if err = server.keeper.ChargeGaugesFee(ctx, owner, fee, msg.Coins); err != nil { - return nil, err + return nil, fmt.Errorf("charge gauge fee: %w", err) } gaugeID, err := server.keeper.CreateGauge(ctx, msg.IsPerpetual, owner, msg.Coins, msg.DistributeTo, msg.StartTime, msg.NumEpochsPaidOver) @@ -78,7 +77,7 @@ func (server msgServer) AddToGauge(goCtx context.Context, msg *types.MsgAddToGau params := server.keeper.GetParams(ctx) fee := params.AddToGaugeBaseFee.Add(params.AddDenomFee.MulRaw(int64(len(msg.Rewards) + len(gauge.Coins)))) if err = server.keeper.ChargeGaugesFee(ctx, owner, fee, msg.Rewards); err != nil { - return nil, err + return nil, fmt.Errorf("charge gauge fee: %w", err) } err = server.keeper.AddToGaugeRewards(ctx, owner, msg.Rewards, gauge) @@ -100,7 +99,7 @@ func (server msgServer) AddToGauge(goCtx context.Context, msg *types.MsgAddToGau // balance that is less than fee + amount of the coin from gaugeCoins that is of base denom. // gaugeCoins might not have a coin of tx base denom. In that case, fee is only compared to balance. // The fee is sent to the txfees module, to be burned. -func (k Keeper) ChargeGaugesFee(ctx sdk.Context, address sdk.AccAddress, fee sdk.Int, gaugeCoins sdk.Coins) (err error) { +func (k Keeper) ChargeGaugesFee(ctx sdk.Context, payer sdk.AccAddress, fee sdk.Int, gaugeCoins sdk.Coins) (err error) { var feeDenom string if k.tk == nil { feeDenom, err = sdk.GetBaseDenom() @@ -112,11 +111,11 @@ func (k Keeper) ChargeGaugesFee(ctx sdk.Context, address sdk.AccAddress, fee sdk } totalCost := gaugeCoins.AmountOf(feeDenom).Add(fee) - accountBalance := k.bk.GetBalance(ctx, address, feeDenom).Amount + accountBalance := k.bk.GetBalance(ctx, payer, feeDenom).Amount if accountBalance.LT(totalCost) { return errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, "account's balance is less than the total cost of the message. Balance: %s %s, Total Cost: %s", feeDenom, accountBalance, totalCost) } - return k.bk.SendCoinsFromAccountToModule(ctx, address, txfeestypes.ModuleName, sdk.NewCoins(sdk.NewCoin(feeDenom, fee))) + return k.tk.ChargeFeesFromPayer(ctx, payer, sdk.NewCoin(feeDenom, fee), nil) } diff --git a/x/incentives/keeper/msg_server_test.go b/x/incentives/keeper/msg_server_test.go index 3d88aacc3..577d344ce 100644 --- a/x/incentives/keeper/msg_server_test.go +++ b/x/incentives/keeper/msg_server_test.go @@ -192,9 +192,9 @@ func (suite *KeeperTestSuite) TestCreateGauge() { finalAccountBalance := accountBalance.Sub(fee...) suite.Require().Equal(finalAccountBalance.String(), balanceAmount.String(), "test: %v", tc.name) - // test fee charged to txfees module account + // test fee charged to txfees module account and burned txfeesBalanceAfter := bankKeeper.GetBalance(ctx, accountKeeper.GetModuleAddress(txfees.ModuleName), "stake") - suite.Require().Equal(txfeesBalanceBefore.Amount.Add(feeRaw), txfeesBalanceAfter.Amount, "test: %v", tc.name) + suite.Require().Equal(txfeesBalanceBefore.Amount, txfeesBalanceAfter.Amount, "test: %v", tc.name) } }) } @@ -369,9 +369,9 @@ func (suite *KeeperTestSuite) TestAddToGauge() { finalAccountBalance := accountBalance.Sub(fee...) suite.Require().Equal(finalAccountBalance.String(), bal.String(), "test: %v", tc.name) - // test fee charged to txfees module account + // test fee charged to txfees module account and burned txfeesBalanceAfter := bankKeeper.GetBalance(ctx, accountKeeper.GetModuleAddress(txfees.ModuleName), "stake") - suite.Require().Equal(txfeesBalanceBefore.Amount.Add(feeRaw), txfeesBalanceAfter.Amount, "test: %v", tc.name) + suite.Require().Equal(txfeesBalanceBefore.Amount, txfeesBalanceAfter.Amount, "test: %v", tc.name) } }) } diff --git a/x/incentives/types/expected_keepers.go b/x/incentives/types/expected_keepers.go index d9881e46e..c9c0b5998 100644 --- a/x/incentives/types/expected_keepers.go +++ b/x/incentives/types/expected_keepers.go @@ -39,6 +39,7 @@ type EpochKeeper interface { // TxFeesKeeper defines the expected interface needed to managing transaction fees. type TxFeesKeeper interface { GetBaseDenom(ctx sdk.Context) (denom string, err error) + ChargeFeesFromPayer(ctx sdk.Context, payer sdk.AccAddress, takerFeeCoin sdk.Coin, beneficiary *sdk.AccAddress) error } type RollappKeeper interface { diff --git a/x/iro/keeper/create_plan.go b/x/iro/keeper/create_plan.go index 091fbda1e..d17708e4f 100644 --- a/x/iro/keeper/create_plan.go +++ b/x/iro/keeper/create_plan.go @@ -162,8 +162,8 @@ func (k Keeper) CreateModuleAccountForPlan(ctx sdk.Context, plan types.Plan) (au // MintAllocation mints the allocated amount and registers the denom in the bank denom metadata store func (k Keeper) MintAllocation(ctx sdk.Context, allocatedAmount math.Int, rollappId, rollappTokenSymbol string, exponent uint64) (sdk.Coin, error) { - baseDenom := fmt.Sprintf("%s_%s", types.IROTokenPrefix, rollappId) - displayDenom := fmt.Sprintf("%s_%s", types.IROTokenPrefix, rollappTokenSymbol) + baseDenom := types.IRODenom(rollappId) + displayDenom := types.IRODenom(rollappTokenSymbol) metadata := banktypes.Metadata{ Description: fmt.Sprintf("Future token for rollapp %s", rollappId), DenomUnits: []*banktypes.DenomUnit{ diff --git a/x/iro/keeper/create_plan_test.go b/x/iro/keeper/create_plan_test.go index 9f8db72c3..7dc7a6ddd 100644 --- a/x/iro/keeper/create_plan_test.go +++ b/x/iro/keeper/create_plan_test.go @@ -112,7 +112,7 @@ func (s *KeeperTestSuite) TestMintAllocation() { k := s.App.IROKeeper allocatedAmount := sdk.NewInt(10).MulRaw(1e18) - expectedBaseDenom := fmt.Sprintf("%s_%s", types.IROTokenPrefix, rollappId) + expectedBaseDenom := types.IRODenom(rollappId) rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) minted, err := k.MintAllocation(s.Ctx, allocatedAmount, rollapp.RollappId, rollapp.GenesisInfo.NativeDenom.Base, uint64(rollapp.GenesisInfo.NativeDenom.Exponent)) diff --git a/x/iro/keeper/keeper.go b/x/iro/keeper/keeper.go index bdd6788d3..5f1b685c4 100644 --- a/x/iro/keeper/keeper.go +++ b/x/iro/keeper/keeper.go @@ -26,6 +26,7 @@ type Keeper struct { gk types.GammKeeper pm types.PoolManagerKeeper ik types.IncentivesKeeper + tk types.TxFeesKeeper } func NewKeeper( @@ -39,6 +40,7 @@ func NewKeeper( gk types.GammKeeper, ik types.IncentivesKeeper, pm types.PoolManagerKeeper, + tk types.TxFeesKeeper, ) *Keeper { return &Keeper{ cdc: cdc, @@ -51,6 +53,7 @@ func NewKeeper( gk: gk, ik: ik, pm: pm, + tk: tk, } } diff --git a/x/iro/keeper/keeper_test.go b/x/iro/keeper/keeper_test.go index 90f7d8b79..19a0fbc5e 100644 --- a/x/iro/keeper/keeper_test.go +++ b/x/iro/keeper/keeper_test.go @@ -44,6 +44,10 @@ func (suite *KeeperTestSuite) SetupTest() { rollapp := suite.App.RollappKeeper.MustGetRollapp(suite.Ctx, rollappId) funds := suite.App.IROKeeper.GetParams(suite.Ctx).CreationFee.Mul(math.NewInt(10)) // 10 times the creation fee suite.FundAcc(sdk.MustAccAddressFromBech32(rollapp.Owner), sdk.NewCoins(sdk.NewCoin(appparams.BaseDenom, funds))) + + // set txfees basedenom + err := suite.App.TxFeesKeeper.SetBaseDenom(suite.Ctx, "adym") + suite.Require().NoError(err) } // BuySomeTokens buys some tokens from the plan diff --git a/x/iro/keeper/trade.go b/x/iro/keeper/trade.go index ee0339bda..4cb61f94f 100644 --- a/x/iro/keeper/trade.go +++ b/x/iro/keeper/trade.go @@ -2,14 +2,11 @@ package keeper import ( "context" + "fmt" errorsmod "cosmossdk.io/errors" "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" - - txfeestypes "github.com/osmosis-labs/osmosis/v15/x/txfees/types" - "github.com/dymensionxyz/sdk-utils/utils/uevent" appparams "github.com/dymensionxyz/dymension/v3/app/params" @@ -62,7 +59,7 @@ func (m msgServer) Sell(ctx context.Context, req *types.MsgSell) (*types.MsgSell // Buy buys fixed amount of allocation with price according to the price curve func (k Keeper) Buy(ctx sdk.Context, planId string, buyer sdk.AccAddress, amountTokensToBuy, maxCostAmt math.Int) error { - plan, err := k.GetTradeableIRO(ctx, planId, buyer.String()) + plan, err := k.GetTradeableIRO(ctx, planId, buyer) if err != nil { return err } @@ -86,7 +83,8 @@ func (k Keeper) Buy(ctx sdk.Context, planId string, buyer sdk.AccAddress, amount // Charge taker fee takerFee := sdk.NewCoin(appparams.BaseDenom, takerFeeAmt) - err = k.chargeTakerFee(ctx, takerFee, buyer) + owner := k.rk.MustGetRollappOwner(ctx, plan.RollappId) + err = k.chargeTakerFee(ctx, takerFee, buyer, &owner) if err != nil { return err } @@ -127,7 +125,7 @@ func (k Keeper) Buy(ctx sdk.Context, planId string, buyer sdk.AccAddress, amount // BuyExactSpend uses exact amount of DYM to buy tokens on the curve func (k Keeper) BuyExactSpend(ctx sdk.Context, planId string, buyer sdk.AccAddress, amountToSpend, minTokensAmt math.Int) error { - plan, err := k.GetTradeableIRO(ctx, planId, buyer.String()) + plan, err := k.GetTradeableIRO(ctx, planId, buyer) if err != nil { return err } @@ -156,7 +154,8 @@ func (k Keeper) BuyExactSpend(ctx sdk.Context, planId string, buyer sdk.AccAddre // Charge taker fee takerFee := sdk.NewCoin(appparams.BaseDenom, takerFeeAmt) - err = k.chargeTakerFee(ctx, takerFee, buyer) + owner := k.rk.MustGetRollappOwner(ctx, plan.RollappId) + err = k.chargeTakerFee(ctx, takerFee, buyer, &owner) if err != nil { return err } @@ -197,7 +196,7 @@ func (k Keeper) BuyExactSpend(ctx sdk.Context, planId string, buyer sdk.AccAddre // Sell sells allocation with price according to the price curve func (k Keeper) Sell(ctx sdk.Context, planId string, seller sdk.AccAddress, amountTokensToSell, minIncomeAmt math.Int) error { - plan, err := k.GetTradeableIRO(ctx, planId, seller.String()) + plan, err := k.GetTradeableIRO(ctx, planId, seller) if err != nil { return err } @@ -216,7 +215,8 @@ func (k Keeper) Sell(ctx sdk.Context, planId string, seller sdk.AccAddress, amou // Charge taker fee takerFee := sdk.NewCoin(appparams.BaseDenom, takerFeeAmt) - err = k.chargeTakerFee(ctx, takerFee, seller) + owner := k.rk.MustGetRollappOwner(ctx, plan.RollappId) + err = k.chargeTakerFee(ctx, takerFee, seller, &owner) if err != nil { return err } @@ -259,7 +259,7 @@ func (k Keeper) Sell(ctx sdk.Context, planId string, seller sdk.AccAddress, amou // - plan must exist // - plan must not be settled // - plan must have started (unless the trader is the owner) -func (k Keeper) GetTradeableIRO(ctx sdk.Context, planId string, trader string) (*types.Plan, error) { +func (k Keeper) GetTradeableIRO(ctx sdk.Context, planId string, trader sdk.AccAddress) (*types.Plan, error) { plan, found := k.GetPlan(ctx, planId) if !found { return nil, types.ErrPlanNotFound @@ -270,17 +270,22 @@ func (k Keeper) GetTradeableIRO(ctx sdk.Context, planId string, trader string) ( } // Validate start time started (unless the trader is the owner) - if ctx.BlockTime().Before(plan.StartTime) && k.rk.MustGetRollapp(ctx, plan.RollappId).Owner != trader { + owner := k.rk.MustGetRollappOwner(ctx, plan.RollappId) + if ctx.BlockTime().Before(plan.StartTime) && !owner.Equals(trader) { return nil, errorsmod.Wrapf(types.ErrPlanNotStarted, "planId: %d", plan.Id) } return &plan, nil } -// chargeTakerFee charges taker fee from the sender -// takerFee sent to the txfees module -func (k Keeper) chargeTakerFee(ctx sdk.Context, takerFee sdk.Coin, sender sdk.AccAddress) error { - return k.BK.SendCoinsFromAccountToModule(ctx, sender, txfeestypes.ModuleName, sdk.NewCoins(takerFee)) +// chargeTakerFee charges taker fee from the sender. +// The fee is sent to the txfees module and the beneficiary if presented. +func (k Keeper) chargeTakerFee(ctx sdk.Context, takerFeeCoin sdk.Coin, sender sdk.AccAddress, beneficiary *sdk.AccAddress) error { + err := k.tk.ChargeFeesFromPayer(ctx, sender, takerFeeCoin, beneficiary) + if err != nil { + return fmt.Errorf("charge fees: sender: %s: fee: %s: %w", sender, takerFeeCoin, err) + } + return nil } // ApplyTakerFee applies taker fee to the cost diff --git a/x/iro/keeper/trade_test.go b/x/iro/keeper/trade_test.go index eb62d5723..8a9e97a02 100644 --- a/x/iro/keeper/trade_test.go +++ b/x/iro/keeper/trade_test.go @@ -5,8 +5,7 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/osmosis-labs/osmosis/v15/x/txfees" + "github.com/cosmos/gogoproto/proto" "github.com/dymensionxyz/dymension/v3/testutil/sample" "github.com/dymensionxyz/dymension/v3/x/iro/types" @@ -25,6 +24,7 @@ func (s *KeeperTestSuite) TestBuy() { rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) planId, err := k.CreatePlan(s.Ctx, totalAllocation, startTime, startTime.Add(time.Hour), rollapp, curve, incentives) s.Require().NoError(err) + initialOwnerBalance := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.RollappKeeper.MustGetRollappOwner(s.Ctx, rollappId)) plan := k.MustGetPlan(s.Ctx, planId) reservedTokens := plan.SoldAmt @@ -71,12 +71,20 @@ func (s *KeeperTestSuite) TestBuy() { s.Require().NoError(err) s.Assert().True(expectedCost2.GT(expectedCost)) + // extract taker fee from buy event + takerFeeAmt := s.TakerFeeAmtAfterBuy() + // assert balance buyerFinalBalance := s.App.BankKeeper.GetAllBalances(s.Ctx, buyer) - takerFee := s.App.BankKeeper.GetAllBalances(s.Ctx, authtypes.NewModuleAddress(txfees.ModuleName)) - expectedBalance := buyersFunds.AmountOf("adym").Sub(expectedCost).Sub(takerFee.AmountOf("adym")) + expectedBalance := buyersFunds.AmountOf("adym").Sub(expectedCost).Sub(takerFeeAmt) s.Require().Equal(expectedBalance, buyerFinalBalance.AmountOf("adym")) s.Require().Equal(buyAmt, buyerFinalBalance.AmountOf(plan.GetIRODenom())) + + // assert owner is incentivized: it must get 50% of taker fee + currentOwnerBalance := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.RollappKeeper.MustGetRollappOwner(s.Ctx, rollappId)) + ownerBalanceChange := currentOwnerBalance.Sub(initialOwnerBalance...) + ownerRevenue := takerFeeAmt.QuoRaw(2) + s.Require().Equal(ownerRevenue, ownerBalanceChange.AmountOf("adym")) } func (s *KeeperTestSuite) TestTradeAfterSettled() { @@ -150,9 +158,11 @@ func (s *KeeperTestSuite) TestTakerFee() { err = k.Buy(s.Ctx, planId, buyer, buyAmt, buyAmt.Add(expectedTakerFee)) s.Require().NoError(err) + // Extract taker fee from buy event + takerFeeAmtBuy := s.TakerFeeAmtAfterBuy() + // Check taker fee - takerFee := s.App.BankKeeper.GetAllBalances(s.Ctx, authtypes.NewModuleAddress(txfees.ModuleName)) - s.Require().Equal(expectedTakerFee, takerFee.AmountOf("adym")) + s.Require().Equal(expectedTakerFee, takerFeeAmtBuy) } func (s *KeeperTestSuite) TestSell() { @@ -168,6 +178,7 @@ func (s *KeeperTestSuite) TestSell() { rollapp, _ := s.App.RollappKeeper.GetRollapp(s.Ctx, rollappId) planId, err := k.CreatePlan(s.Ctx, totalAllocation, startTime, startTime.Add(time.Hour), rollapp, curve, incentives) s.Require().NoError(err) + initialOwnerBalance := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.RollappKeeper.MustGetRollappOwner(s.Ctx, rollappId)) s.Ctx = s.Ctx.WithBlockTime(startTime.Add(time.Minute)) buyer := sample.Acc() @@ -180,16 +191,29 @@ func (s *KeeperTestSuite) TestSell() { err = k.Buy(s.Ctx, planId, buyer, buyAmt, maxAmt) s.Require().NoError(err) + // Extract taker fee from buy event + takerFeeAmtBuy := s.TakerFeeAmtAfterBuy() + // Sell tokens sellAmt := sdk.NewInt(500).MulRaw(1e18) minReceive := sdk.NewInt(1) // Set a very low minReceive for testing purposes err = k.Sell(s.Ctx, planId, buyer, sellAmt, minReceive) s.Require().NoError(err) + // Extract taker fee from sell event + takerFeeAmtSell := s.TakerFeeAmtAfterSell() + // Check balances after sell balances := s.App.BankKeeper.GetAllBalances(s.Ctx, buyer) s.Require().Equal(buyAmt.Sub(sellAmt), balances.AmountOf(k.MustGetPlan(s.Ctx, planId).GetIRODenom())) + // Assert owner is incentivized: it must get 50% of taker fee + currentOwnerBalance := s.App.BankKeeper.GetAllBalances(s.Ctx, s.App.RollappKeeper.MustGetRollappOwner(s.Ctx, rollappId)) + ownerBalanceChange := currentOwnerBalance.Sub(initialOwnerBalance...) + // ownerRevenue = (takerFeeBuy + takerFeeSell) / 2 + ownerRevenue := takerFeeAmtBuy.Add(takerFeeAmtSell).QuoRaw(2) + s.Require().Equal(ownerRevenue, ownerBalanceChange.AmountOf("adym")) + // Attempt to sell more than owned - should fail err = k.Sell(s.Ctx, planId, buyer, buyAmt, minReceive) s.Require().Error(err) @@ -199,3 +223,35 @@ func (s *KeeperTestSuite) TestSell() { err = k.Sell(s.Ctx, planId, buyer, sellAmt, highMinReceive) s.Require().Error(err) } + +func (s *KeeperTestSuite) TakerFeeAmtAfterSell() sdk.Int { + // Extract taker fee from event + eventName := proto.MessageName(new(types.EventSell)) + takerFeeAmt, found := s.ExtractTakerFeeAmtFromEvents(s.Ctx.EventManager().Events(), eventName) + s.Require().True(found) + return takerFeeAmt +} + +func (s *KeeperTestSuite) TakerFeeAmtAfterBuy() sdk.Int { + // Extract taker fee from event + eventName := proto.MessageName(new(types.EventBuy)) + takerFeeAmt, found := s.ExtractTakerFeeAmtFromEvents(s.Ctx.EventManager().Events(), eventName) + s.Require().True(found) + return takerFeeAmt +} + +func (s *KeeperTestSuite) ExtractTakerFeeAmtFromEvents(events []sdk.Event, eventName string) (sdk.Int, bool) { + event, found := s.FindLastEventOfType(events, eventName) + if !found { + return sdk.Int{}, false + } + attrs := s.ExtractAttributes(event) + for key, value := range attrs { + if key == "taker_fee" { + fee, ok := sdk.NewIntFromString(value) + s.Require().True(ok) + return fee, true + } + } + return sdk.ZeroInt(), false +} diff --git a/x/iro/types/expected_keepers.go b/x/iro/types/expected_keepers.go index b27ec2c97..c4e38e838 100644 --- a/x/iro/types/expected_keepers.go +++ b/x/iro/types/expected_keepers.go @@ -1,7 +1,7 @@ package types import ( - time "time" + "time" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -56,5 +56,9 @@ type PoolManagerKeeper interface { type RollappKeeper interface { GetRollapp(ctx sdk.Context, rollappId string) (rollapp rollapptypes.Rollapp, found bool) SetIROPlanToRollapp(ctx sdk.Context, rollapp *rollapptypes.Rollapp, iro Plan) error - MustGetRollapp(ctx sdk.Context, rollappId string) rollapptypes.Rollapp + MustGetRollappOwner(ctx sdk.Context, rollappID string) sdk.AccAddress +} + +type TxFeesKeeper interface { + ChargeFeesFromPayer(ctx sdk.Context, payer sdk.AccAddress, takerFeeCoin sdk.Coin, beneficiary *sdk.AccAddress) error } diff --git a/x/iro/types/plan.go b/x/iro/types/plan.go index 7dfed17d3..ba8e1aed4 100644 --- a/x/iro/types/plan.go +++ b/x/iro/types/plan.go @@ -3,6 +3,7 @@ package types import ( "errors" fmt "fmt" + "strings" time "time" "cosmossdk.io/math" @@ -10,7 +11,15 @@ import ( authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) -const IROTokenPrefix = "future" +const IROTokenPrefix = "future_" + +func IRODenom(rollappID string) string { + return fmt.Sprintf("%s%s", IROTokenPrefix, rollappID) +} + +func RollappIDFromIRODenom(denom string) (string, bool) { + return strings.CutPrefix(denom, IROTokenPrefix) +} var MinTokenAllocation = math.LegacyNewDec(10) // min allocation in decimal representation @@ -78,9 +87,9 @@ func (p Plan) GetAddress() sdk.AccAddress { return addr } -// get IRO token's denom +// GetIRODenom returns IRO token's denom func (p Plan) GetIRODenom() string { - return fmt.Sprintf("%s_%s", IROTokenPrefix, p.RollappId) + return IRODenom(p.RollappId) } func DefaultIncentivePlanParams() IncentivePlanParams { diff --git a/x/iro/types/plan_test.go b/x/iro/types/plan_test.go new file mode 100644 index 000000000..5c3f7d70f --- /dev/null +++ b/x/iro/types/plan_test.go @@ -0,0 +1,41 @@ +package types + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func FuzzIRODenom(f *testing.F) { + f.Add("exampleRollappID") + f.Add("") + f.Add("123456") + f.Add("🚀🌕") + + f.Fuzz(func(t *testing.T, rollappID string) { + denom := IRODenom(rollappID) + id, ok := RollappIDFromIRODenom(denom) + require.True(t, ok) + require.Equal(t, rollappID, id) + }) +} + +func FuzzRollappIDFromIRODenom(f *testing.F) { + f.Add(IROTokenPrefix + "exampleRollappID") + f.Add(IROTokenPrefix) + f.Add("notfuture_prefix") + f.Add(IROTokenPrefix + "🚀🌕") + + f.Fuzz(func(t *testing.T, denom string) { + rollappID, ok := RollappIDFromIRODenom(denom) + if ok { + // Ensure that reconstructing the denom gives the original denom + reconstructedDenom := IRODenom(rollappID) + require.Equal(t, denom, reconstructedDenom) + } else { + // Denom do not have the prefix + require.False(t, strings.HasPrefix(denom, IROTokenPrefix)) + } + }) +} diff --git a/x/lightclient/ante/ibc_msg_channel_open_ack.go b/x/lightclient/ante/ibc_msg_channel_open_ack.go index 066ef76e6..8e3cdb396 100644 --- a/x/lightclient/ante/ibc_msg_channel_open_ack.go +++ b/x/lightclient/ante/ibc_msg_channel_open_ack.go @@ -19,13 +19,13 @@ func (i IBCMessagesDecorator) HandleMsgChannelOpenAck(ctx sdk.Context, msg *ibcc if err != nil { return err } - rollappID, found := i.lightClientKeeper.GetRollappForClientID(ctx, connection.GetClientID()) + rollappID, found := i.k.GetRollappForClientID(ctx, connection.GetClientID()) if !found { // channel is for non rollapp return nil } // Check if canon channel already exists for rollapp, if yes, return err - rollapp, found := i.rollappKeeper.GetRollapp(ctx, rollappID) + rollapp, found := i.raK.GetRollapp(ctx, rollappID) if !found { return errorsmod.Wrap(gerrc.ErrInternal, "rollapp not found") } @@ -34,7 +34,7 @@ func (i IBCMessagesDecorator) HandleMsgChannelOpenAck(ctx sdk.Context, msg *ibcc } // Set this channel as the canonical channel for the rollapp rollapp.ChannelId = msg.ChannelId - i.rollappKeeper.SetRollapp(ctx, rollapp) + i.raK.SetRollapp(ctx, rollapp) if err := uevent.EmitTypedEvent(ctx, &types.EventSetCanonicalChannel{ RollappId: rollappID, diff --git a/x/lightclient/ante/ibc_msg_channel_open_ack_test.go b/x/lightclient/ante/ibc_msg_channel_open_ack_test.go index 020d88c08..6455168f1 100644 --- a/x/lightclient/ante/ibc_msg_channel_open_ack_test.go +++ b/x/lightclient/ante/ibc_msg_channel_open_ack_test.go @@ -15,8 +15,8 @@ import ( func TestHandleMsgChannelOpenAck(t *testing.T) { keeper, ctx := keepertest.LightClientKeeper(t) testRollapps := map[string]rollapptypes.Rollapp{ - "rollapp-has-canon-client": { - RollappId: "rollapp-has-canon-client", + keepertest.DefaultRollapp: { + RollappId: keepertest.DefaultRollapp, ChannelId: "channel-on-canon-client", }, "rollapp-no-canon-channel": { @@ -26,20 +26,20 @@ func TestHandleMsgChannelOpenAck(t *testing.T) { } testConnections := map[string]ibcconnectiontypes.ConnectionEnd{ "new-channel-on-canon-client": { - ClientId: "canon-client-id", + ClientId: keepertest.CanonClientID, }, "first-channel-on-canon-client": { - ClientId: "canon-client-id-2", + ClientId: "keepertest.CanonClientID-2", }, "non-canon-channel-id": { - ClientId: "non-canon-client-id", + ClientId: "non-keepertest.CanonClientID", }, } rollappKeeper := NewMockRollappKeeper(testRollapps, nil) ibcclientKeeper := NewMockIBCClientKeeper(nil) ibcchannelKeeper := NewMockIBCChannelKeeper(testConnections) - keeper.SetCanonicalClient(ctx, "rollapp-has-canon-client", "canon-client-id") - keeper.SetCanonicalClient(ctx, "rollapp-no-canon-channel", "canon-client-id-2") + keeper.SetCanonicalClient(ctx, keepertest.DefaultRollapp, keepertest.CanonClientID) + keeper.SetCanonicalClient(ctx, "rollapp-no-canon-channel", "keepertest.CanonClientID-2") ibcMsgDecorator := ante.NewIBCMessagesDecorator(*keeper, ibcclientKeeper, ibcchannelKeeper, rollappKeeper) testCases := []struct { name string diff --git a/x/lightclient/ante/ibc_msg_submit_misbehaviour.go b/x/lightclient/ante/ibc_msg_submit_misbehaviour.go index e0a991ff8..616ebfc8e 100644 --- a/x/lightclient/ante/ibc_msg_submit_misbehaviour.go +++ b/x/lightclient/ante/ibc_msg_submit_misbehaviour.go @@ -4,24 +4,13 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" ibcclienttypes "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/dymensionxyz/gerr-cosmos/gerrc" ) func (i IBCMessagesDecorator) HandleMsgSubmitMisbehaviour(ctx sdk.Context, msg *ibcclienttypes.MsgSubmitMisbehaviour) error { - clientState, found := i.ibcClientKeeper.GetClientState(ctx, msg.ClientId) - if !found { - return nil - } - // Cast client state to tendermint client state - we need this to get the chain id - tendmermintClientState, ok := clientState.(*ibctm.ClientState) - if !ok { - return nil - } - // Check if the client is the canonical client for a rollapp - rollappID := tendmermintClientState.ChainId - canonicalClient, _ := i.lightClientKeeper.GetCanonicalClient(ctx, rollappID) - if canonicalClient == msg.ClientId { - return errorsmod.Wrap(ibcclienttypes.ErrInvalidClient, "cannot submit misbehavour for a canonical client") + _, ok := i.k.GetRollappForClientID(ctx, msg.ClientId) + if ok { + return errorsmod.Wrap(gerrc.ErrInvalidArgument, "cannot submit misbehavour for a canonical client") } return nil } diff --git a/x/lightclient/ante/ibc_msg_submit_misbehaviour_test.go b/x/lightclient/ante/ibc_msg_submit_misbehaviour_test.go index 5ea75fc23..bae2dd89b 100644 --- a/x/lightclient/ante/ibc_msg_submit_misbehaviour_test.go +++ b/x/lightclient/ante/ibc_msg_submit_misbehaviour_test.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/ibc-go/v7/modules/core/exported" ibcsolomachine "github.com/cosmos/ibc-go/v7/modules/light-clients/06-solomachine" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + "github.com/dymensionxyz/gerr-cosmos/gerrc" keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" "github.com/dymensionxyz/dymension/v3/x/lightclient/ante" @@ -18,13 +19,13 @@ func TestHandleMsgSubmitMisbehaviour(t *testing.T) { rollappKeeper := NewMockRollappKeeper(nil, nil) testClientStates := map[string]exported.ClientState{ "non-tm-client-id": &ibcsolomachine.ClientState{}, - "canon-client-id": &ibctm.ClientState{ - ChainId: "rollapp-has-canon-client", + keepertest.CanonClientID: &ibctm.ClientState{ + ChainId: keepertest.DefaultRollapp, }, } ibcclientKeeper := NewMockIBCClientKeeper(testClientStates) ibcchannelKeeper := NewMockIBCChannelKeeper(nil) - keeper.SetCanonicalClient(ctx, "rollapp-has-canon-client", "canon-client-id") + keeper.SetCanonicalClient(ctx, keepertest.DefaultRollapp, keepertest.CanonClientID) ibcMsgDecorator := ante.NewIBCMessagesDecorator(*keeper, ibcclientKeeper, ibcchannelKeeper, rollappKeeper) testCases := []struct { name string @@ -42,10 +43,10 @@ func TestHandleMsgSubmitMisbehaviour(t *testing.T) { { name: "Client is a known canonical client for a rollapp", inputMsg: ibcclienttypes.MsgSubmitMisbehaviour{ - ClientId: "canon-client-id", + ClientId: keepertest.CanonClientID, Misbehaviour: nil, }, - err: ibcclienttypes.ErrInvalidClient, + err: gerrc.ErrInvalidArgument, }, { name: "Client is not a known canonical client", diff --git a/x/lightclient/ante/ibc_msg_update_client.go b/x/lightclient/ante/ibc_msg_update_client.go index 76dfd6840..b8029676a 100644 --- a/x/lightclient/ante/ibc_msg_update_client.go +++ b/x/lightclient/ante/ibc_msg_update_client.go @@ -1,99 +1,163 @@ package ante import ( + "bytes" + "errors" + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" ibcclienttypes "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/dymensionxyz/dymension/v3/x/lightclient/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" "github.com/dymensionxyz/gerr-cosmos/gerrc" ) func (i IBCMessagesDecorator) HandleMsgUpdateClient(ctx sdk.Context, msg *ibcclienttypes.MsgUpdateClient) error { - clientState, found := i.ibcClientKeeper.GetClientState(ctx, msg.ClientId) - if !found { + if !i.k.Enabled() { return nil } - - // Cast client state to tendermint client state - we need this to get the chain id(rollapp id) - tmClientState, ok := clientState.(*ibctm.ClientState) - if !ok { + _, canonical := i.k.GetRollappForClientID(ctx, msg.ClientId) + header, err := getHeader(msg) + if !canonical && errorsmod.IsOf(err, errIsMisbehaviour) { + // We don't want to block misbehavior submission for non rollapps return nil } - // Check if the client is the canonical client for the rollapp - rollappID := tmClientState.ChainId - canonicalClient, _ := i.lightClientKeeper.GetCanonicalClient(ctx, rollappID) - if canonicalClient != msg.ClientId { - return nil // The client is not a rollapp's canonical client. Continue with default behaviour. + if errorsmod.IsOf(err, errNoHeader) { + // it doesn't concern us + return nil } - - // cannot update the LC unless fork is resolved (after receiving state updates of HF height +1 & HF height +2 - if i.lightClientKeeper.IsHardForkingInProgress(ctx, rollappID) { - return types.ErrorHardForkInProgress + if err != nil { + return errorsmod.Wrap(err, "get header") + } + seq, err := i.getSequencer(ctx, header) + err = errorsmod.Wrap(err, "get sequencer") + if errorsmod.IsOf(err, errProposerMismatch) { + // this should not occur on any chain, regardless of being a rollapp or not + return err + } + if errorsmod.IsOf(err, gerrc.ErrNotFound) { + if !canonical { + // not from sequencer, and not canonical - it's not interesting + return nil + } + return gerrc.ErrInvalidArgument.Wrap("update canonical client with non sequencer header") } - - clientMessage, err := ibcclienttypes.UnpackClientMessage(msg.ClientMessage) if err != nil { - return nil + return err } - _, ok = clientMessage.(*ibctm.Misbehaviour) - if ok { - return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "misbehavior evidence is disabled for canonical clients") + + // ~~~~~ + // now we know that the msg is a header, and it was produced by a sequencer + // ~~~~~ + + if !seq.Bonded() { + // we assume here that sequencers will not propose blocks on other chains connected to the hub except for their rollapp + return gerrc.ErrInvalidArgument.Wrap("header is from unbonded sequencer") } - header, ok := clientMessage.(*ibctm.Header) + + rollapp, ok := i.raK.GetRollapp(ctx, seq.RollappId) if !ok { - return nil + return gerrc.ErrInternal.Wrapf("get rollapp from sequencer: rollapp: %s", seq.RollappId) } - ra, ok := i.rollappKeeper.GetRollapp(ctx, rollappID) - if !ok { - return errorsmod.Wrap(gerrc.ErrInternal, "rollapp not found") + // cannot update the LC unless fork is resolved (after receiving state updates of HF height +1 & HF height +2 + 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 != ra.RevisionNumber { + if header.Header.Version.App != rollapp.RevisionNumber { return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "client update revision mismatch") } - // Check if there are existing block descriptors for the given height of client state - height := uint64(header.Header.Height) - stateInfo, err := i.rollappKeeper.FindStateInfoByHeight(ctx, rollappID, height) + h := header.GetHeight().GetRevisionHeight() + stateInfos, err := i.getStateInfos(ctx, rollapp.RollappId, h) if err != nil { - // No BDs found for given height. - // Will accept the update optimistically - // But also save the blockProposer address with the height for future verification - i.acceptUpdateOptimistically(ctx, msg.ClientId, header) - return nil + return errorsmod.Wrap(err, "get state infos") } - bd, _ := stateInfo.GetBlockDescriptor(height) - stateInfo, err = i.rollappKeeper.FindStateInfoByHeight(ctx, rollappID, height+1) - if err != nil { - // No BDs found for next height. - // Will accept the update optimistically - // But also save the blockProposer address with the height for future verification - i.acceptUpdateOptimistically(ctx, msg.ClientId, header) - return nil + if stateInfos.containingHPlus1 != nil { + // the header is pessimistic: the state update has already been received, so we check the header doesn't mismatch + return errorsmod.Wrap(i.validateUpdatePessimistically(ctx, stateInfos, header.ConsensusState(), h), "validate pessimistic") + } + + // the header is optimistic: the state update has not yet been received, so we save optimistically + return errorsmod.Wrap(i.k.SaveSigner(ctx, seq.Address, msg.ClientId, h), "save updater") +} + +var ( + errIsMisbehaviour = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "misbehavior evidence is disabled for canonical clients") + errNoHeader = errors.New("message does not contain header") + errProposerMismatch = errorsmod.Wrap(gerrc.ErrInvalidArgument, "validator set proposer not equal header proposer field") +) + +func (i IBCMessagesDecorator) getSequencer(ctx sdk.Context, header *ibctm.Header) (sequencertypes.Sequencer, error) { + proposerBySignature := header.ValidatorSet.Proposer.GetAddress() + proposerByData := header.Header.ProposerAddress + // Does ibc already guarantee this equal to header.ProposerAddr? I don't think so + if !bytes.Equal(proposerBySignature, proposerByData) { + return sequencertypes.Sequencer{}, errProposerMismatch } - sequencerPubKey, err := i.lightClientKeeper.GetSequencerPubKey(ctx, stateInfo.Sequencer) + return i.k.SeqK.SequencerByDymintAddr(ctx, proposerByData) +} + +func getHeader(msg *ibcclienttypes.MsgUpdateClient) (*ibctm.Header, error) { + clientMessage, err := ibcclienttypes.UnpackClientMessage(msg.ClientMessage) if err != nil { - return err + return nil, errorsmod.Wrap(err, "unpack client message") } - rollappState := types.RollappState{ - BlockDescriptor: bd, - NextBlockSequencer: sequencerPubKey, + _, ok := clientMessage.(*ibctm.Misbehaviour) + if ok { + return nil, errIsMisbehaviour } - // Ensure that the ibc header is compatible with the existing rollapp state - // If it's not, we error and prevent the MsgUpdateClient from being processed - err = types.CheckCompatibility(*header.ConsensusState(), rollappState) - if err != nil { - return err + header, ok := clientMessage.(*ibctm.Header) + if !ok { + return nil, errNoHeader } + return header, nil +} + +// if containingHPlus1 is not nil then containingH also guaranteed to not be nil +type stateInfos struct { + containingH *rollapptypes.StateInfo + containingHPlus1 *rollapptypes.StateInfo +} - return nil +// getStateInfos gets state infos for h and h+1 +func (i IBCMessagesDecorator) getStateInfos(ctx sdk.Context, rollapp string, h uint64) (stateInfos, error) { + // Check if there are existing block descriptors for the given height of client state + s0, err := i.raK.FindStateInfoByHeight(ctx, rollapp, h) + if errorsmod.IsOf(err, gerrc.ErrNotFound) { + return stateInfos{}, nil + } + if err != nil { + return stateInfos{}, err + } + s1 := s0 + if !s1.ContainsHeight(h + 1) { + s1, err = i.raK.FindStateInfoByHeight(ctx, rollapp, h+1) + if errorsmod.IsOf(err, gerrc.ErrNotFound) { + return stateInfos{s0, nil}, nil + } + if err != nil { + return stateInfos{}, err + } + } + return stateInfos{s0, s1}, nil } -func (i IBCMessagesDecorator) acceptUpdateOptimistically(ctx sdk.Context, clientID string, header *ibctm.Header) { - i.lightClientKeeper.SetConsensusStateValHash(ctx, clientID, uint64(header.Header.Height), header.Header.ValidatorsHash) +func (i IBCMessagesDecorator) validateUpdatePessimistically(ctx sdk.Context, infos stateInfos, consState *ibctm.ConsensusState, h uint64) error { + bd, _ := infos.containingH.GetBlockDescriptor(h) + seq, err := i.k.SeqK.RealSequencer(ctx, infos.containingHPlus1.Sequencer) + if err != nil { + return errorsmod.Wrap(errors.Join(err, gerrc.ErrInternal), "get sequencer of state info") + } + rollappState := types.RollappState{ + BlockDescriptor: bd, + NextBlockSequencer: seq, + } + return errorsmod.Wrap(types.CheckCompatibility(*consState, rollappState), "check compatibility") } diff --git a/x/lightclient/ante/ibc_msg_update_client_test.go b/x/lightclient/ante/ibc_msg_update_client_test.go index 227ab6a63..522bea74a 100644 --- a/x/lightclient/ante/ibc_msg_update_client_test.go +++ b/x/lightclient/ante/ibc_msg_update_client_test.go @@ -5,347 +5,133 @@ import ( "time" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - sdk "github.com/cosmos/cosmos-sdk/types" + cometprototypes "github.com/cometbft/cometbft/proto/tendermint/types" + comettypes "github.com/cometbft/cometbft/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" ibcsolomachine "github.com/cosmos/ibc-go/v7/modules/light-clients/06-solomachine" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" "github.com/dymensionxyz/dymension/v3/x/lightclient/ante" - "github.com/dymensionxyz/dymension/v3/x/lightclient/keeper" - "github.com/dymensionxyz/dymension/v3/x/lightclient/types" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" "github.com/stretchr/testify/require" ) -func TestHandleMsgUpdateClient(t *testing.T) { - type testInput struct { - msg *ibcclienttypes.MsgUpdateClient - rollapps map[string]rollapptypes.Rollapp - stateInfos map[string]map[uint64]rollapptypes.StateInfo +func ConvertValidator(src comettypes.Validator) *cometprototypes.Validator { + // TODO: surely this must already exist somewhere + + pk, err := cryptocodec.FromTmPubKeyInterface(src.PubKey) + if err != nil { + panic(err) } - testCases := []struct { - name string - prepare func(ctx sdk.Context, k keeper.Keeper) testInput - assert func(ctx sdk.Context, k keeper.Keeper, err error) - }{ - { - name: "Could not find a client with given client id", - prepare: func(ctx sdk.Context, k keeper.Keeper) testInput { - return testInput{ - msg: &ibcclienttypes.MsgUpdateClient{ - ClientId: "non-existent-client", - }, - } - }, - assert: func(ctx sdk.Context, k keeper.Keeper, err error) { - require.NoError(t, err) - }, - }, - { - name: "Could not unpack as tendermint client state", - prepare: func(ctx sdk.Context, k keeper.Keeper) testInput { - return testInput{ - msg: &ibcclienttypes.MsgUpdateClient{ - ClientId: "non-tm-client-id", - }, - } - }, - assert: func(ctx sdk.Context, k keeper.Keeper, err error) { - require.NoError(t, err) - }, - }, - { - name: "Client is not a known canonical client of a rollapp", - prepare: func(ctx sdk.Context, k keeper.Keeper) testInput { - return testInput{ - msg: &ibcclienttypes.MsgUpdateClient{ - ClientId: "canon-client-id", - }, - } - }, - assert: func(ctx sdk.Context, k keeper.Keeper, err error) { - require.NoError(t, err) - }, - }, - { - name: "Could not find state info for height - ensure optimistically accepted and signer stored in state", - prepare: func(ctx sdk.Context, k keeper.Keeper) testInput { - k.SetCanonicalClient(ctx, "rollapp-has-canon-client", "canon-client-id") - seqValHash, err := k.GetSequencerHash(ctx, keepertest.Alice) - require.NoError(t, err) - var valSet, trustedVals *cmtproto.ValidatorSet - signedHeader := &cmtproto.SignedHeader{ - Header: &cmtproto.Header{ - ValidatorsHash: seqValHash, - Height: 1, - }, - Commit: &cmtproto.Commit{}, - } - header := ibctm.Header{ - SignedHeader: signedHeader, - ValidatorSet: valSet, - TrustedHeight: ibcclienttypes.MustParseHeight("1-1"), - TrustedValidators: trustedVals, - } - clientMsg, err := ibcclienttypes.PackClientMessage(&header) - require.NoError(t, err) - return testInput{ - msg: &ibcclienttypes.MsgUpdateClient{ - ClientId: "canon-client-id", - ClientMessage: clientMsg, - Signer: "relayerAddr", - }, - rollapps: map[string]rollapptypes.Rollapp{ - "rollapp-has-canon-client": { - RollappId: "rollapp-has-canon-client", - }, - }, - stateInfos: map[string]map[uint64]rollapptypes.StateInfo{ - "rollapp-has-canon-client": { - 3: { - Sequencer: keepertest.Alice, - StateInfoIndex: rollapptypes.StateInfoIndex{ - Index: 3, - }, - StartHeight: 3, - NumBlocks: 1, - BDs: rollapptypes.BlockDescriptors{ - BD: []rollapptypes.BlockDescriptor{ - { - Height: 3, - StateRoot: []byte{}, - Timestamp: time.Unix(1724392989, 0), - }, - }, - }, - }, - }, - }, - } - }, - assert: func(ctx sdk.Context, k keeper.Keeper, err error) { - require.NoError(t, err) - seqValHash, found := k.GetConsensusStateValHash(ctx, "canon-client-id", 1) - require.True(t, found) - seq, err := k.GetSequencerFromValHash(ctx, "rollapp-has-canon-client", seqValHash) - require.NoError(t, err) - require.Equal(t, keepertest.Alice, seq) - }, + pkP, err := cryptocodec.ToTmProtoPublicKey(pk) + if err != nil { + panic(err) + } + dst := &cometprototypes.Validator{ + Address: src.Address, + VotingPower: src.VotingPower, + ProposerPriority: src.ProposerPriority, + PubKey: pkP, + } + return dst +} + +func ConvertValidatorSet(src *comettypes.ValidatorSet) *cometprototypes.ValidatorSet { + // TODO: surely this must already exist somewhere + + if src == nil { + return nil + } + + dst := &cometprototypes.ValidatorSet{ + Validators: make([]*cometprototypes.Validator, len(src.Validators)), + } + + for i, validator := range src.Validators { + dst.Validators[i] = ConvertValidator(*validator) + } + dst.TotalVotingPower = src.TotalVotingPower() + dst.Proposer = ConvertValidator(*src.Proposer) + + return dst +} + +func TestHandleMsgUpdateClientGood(t *testing.T) { + k, ctx := keepertest.LightClientKeeper(t) + testClientStates := map[string]exported.ClientState{ + "non-tm-client-id": &ibcsolomachine.ClientState{}, + } + testClientStates[keepertest.CanonClientID] = &ibctm.ClientState{ + ChainId: keepertest.DefaultRollapp, + } + + blocktimestamp := time.Unix(1724392989, 0) + var trustedVals *cmtproto.ValidatorSet + signedHeader := &cmtproto.SignedHeader{ + Header: &cmtproto.Header{ + AppHash: []byte("appHash"), + ProposerAddress: keepertest.Alice.MustProposerAddr(), + Time: blocktimestamp, + ValidatorsHash: keepertest.Alice.MustValsetHash(), + NextValidatorsHash: keepertest.Alice.MustValsetHash(), + Height: 1, }, - { - name: "State is incompatible - do not accept", - prepare: func(ctx sdk.Context, k keeper.Keeper) testInput { - k.SetCanonicalClient(ctx, "rollapp-has-canon-client", "canon-client-id") - var ( - valSet *cmtproto.ValidatorSet - trustedVals *cmtproto.ValidatorSet - ) - signedHeader := &cmtproto.SignedHeader{ - Header: &cmtproto.Header{ - AppHash: []byte("appHash"), - ProposerAddress: []byte("sequencerAddr"), - Time: time.Unix(1724392989, 0), - NextValidatorsHash: []byte("nextValHash"), - Height: 1, - }, - Commit: &cmtproto.Commit{}, - } - header := ibctm.Header{ - SignedHeader: signedHeader, - ValidatorSet: valSet, - TrustedHeight: ibcclienttypes.MustParseHeight("1-1"), - TrustedValidators: trustedVals, - } - clientMsg, err := ibcclienttypes.PackClientMessage(&header) - require.NoError(t, err) - return testInput{ - msg: &ibcclienttypes.MsgUpdateClient{ - ClientId: "canon-client-id", - ClientMessage: clientMsg, - Signer: "sequencerAddr", - }, - rollapps: map[string]rollapptypes.Rollapp{ - "rollapp-has-canon-client": { - RollappId: "rollapp-has-canon-client", - }, - }, - stateInfos: map[string]map[uint64]rollapptypes.StateInfo{ - "rollapp-has-canon-client": { - 1: { - Sequencer: keepertest.Alice, - StateInfoIndex: rollapptypes.StateInfoIndex{ - Index: 1, - }, - StartHeight: 1, - NumBlocks: 1, - BDs: rollapptypes.BlockDescriptors{ - BD: []rollapptypes.BlockDescriptor{ - { - Height: 1, - StateRoot: []byte{}, - Timestamp: time.Unix(1724392989, 0), - }, - }, - }, - }, - 2: { - Sequencer: keepertest.Alice, - StateInfoIndex: rollapptypes.StateInfoIndex{ - Index: 2, - }, - StartHeight: 2, - NumBlocks: 1, - BDs: rollapptypes.BlockDescriptors{ - BD: []rollapptypes.BlockDescriptor{ - { - Height: 2, - StateRoot: []byte("appHash2"), - Timestamp: time.Unix(1724392989, 0), - }, - }, - }, - }, - }, - }, - } - }, - assert: func(ctx sdk.Context, k keeper.Keeper, err error) { - require.ErrorIs(t, err, types.ErrStateRootsMismatch) - }, + Commit: &cmtproto.Commit{}, + } + header := ibctm.Header{ + SignedHeader: signedHeader, + ValidatorSet: ConvertValidatorSet(keepertest.Alice.MustValset()), + TrustedHeight: ibcclienttypes.MustParseHeight("1-1"), + TrustedValidators: trustedVals, + } + + rollapps := map[string]rollapptypes.Rollapp{ + keepertest.DefaultRollapp: { + RollappId: keepertest.DefaultRollapp, }, - { - name: "Ensure state is compatible - happy path", - prepare: func(ctx sdk.Context, k keeper.Keeper) testInput { - sequencer := keepertest.Alice - proposerAddr, err := k.GetSequencerPubKey(ctx, sequencer) - require.NoError(t, err) - proposerAddrBytes, err := proposerAddr.Marshal() - require.NoError(t, err) - blocktimestamp := time.Unix(1724392989, 0) - k.SetCanonicalClient(ctx, "rollapp-has-canon-client", "canon-client-id") - var ( - valSet *cmtproto.ValidatorSet - trustedVals *cmtproto.ValidatorSet - ) - nextValsHash, err := k.GetSequencerHash(ctx, sequencer) - require.NoError(t, err) - signedHeader := &cmtproto.SignedHeader{ - Header: &cmtproto.Header{ - AppHash: []byte("appHash"), - ProposerAddress: proposerAddrBytes, - Time: blocktimestamp, - ValidatorsHash: nextValsHash, - NextValidatorsHash: nextValsHash, - Height: 1, - }, - Commit: &cmtproto.Commit{}, - } - header := ibctm.Header{ - SignedHeader: signedHeader, - ValidatorSet: valSet, - TrustedHeight: ibcclienttypes.MustParseHeight("1-1"), - TrustedValidators: trustedVals, - } - clientMsg, err := ibcclienttypes.PackClientMessage(&header) - require.NoError(t, err) - return testInput{ - msg: &ibcclienttypes.MsgUpdateClient{ - ClientId: "canon-client-id", - ClientMessage: clientMsg, - Signer: "relayerAddr", - }, - rollapps: map[string]rollapptypes.Rollapp{ - "rollapp-has-canon-client": { - RollappId: "rollapp-has-canon-client", - }, - }, - stateInfos: map[string]map[uint64]rollapptypes.StateInfo{ - "rollapp-has-canon-client": { - 1: { - Sequencer: keepertest.Alice, - StateInfoIndex: rollapptypes.StateInfoIndex{ - Index: 1, - }, - StartHeight: 1, - NumBlocks: 2, - BDs: rollapptypes.BlockDescriptors{ - BD: []rollapptypes.BlockDescriptor{ - { - Height: 1, - StateRoot: []byte("appHash"), - Timestamp: blocktimestamp, - }, - { - Height: 2, - StateRoot: []byte("appHash2"), - Timestamp: blocktimestamp.Add(1), - }, - }, - }, - }, + } + stateInfos := map[string]map[uint64]rollapptypes.StateInfo{ + keepertest.DefaultRollapp: { + 1: { + Sequencer: keepertest.Alice.Address, + StateInfoIndex: rollapptypes.StateInfoIndex{ + Index: 1, + }, + StartHeight: 1, + NumBlocks: 2, + BDs: rollapptypes.BlockDescriptors{ + BD: []rollapptypes.BlockDescriptor{ + { + Height: 1, + StateRoot: []byte("appHash"), + Timestamp: header.SignedHeader.Header.Time, }, - }, - } - }, - assert: func(ctx sdk.Context, k keeper.Keeper, err error) { - require.NoError(t, err) - }, - }, - { - name: "Client is not a known canonical client of a rollapp", - prepare: func(ctx sdk.Context, k keeper.Keeper) testInput { - return testInput{ - msg: &ibcclienttypes.MsgUpdateClient{ - ClientId: "canon-client-id", - }, - } - }, - assert: func(ctx sdk.Context, k keeper.Keeper, err error) { - require.NoError(t, err) - }, - }, - { - name: "SubmitMisbehavior for a canonical chain", - prepare: func(ctx sdk.Context, k keeper.Keeper) testInput { - k.SetCanonicalClient(ctx, "rollapp-has-canon-client", "canon-client-id") - m := &ibctm.Misbehaviour{} - mAny, _ := ibcclienttypes.PackClientMessage(m) - - return testInput{ - msg: &ibcclienttypes.MsgUpdateClient{ - ClientId: "canon-client-id", - ClientMessage: mAny, - }, - rollapps: map[string]rollapptypes.Rollapp{ - "rollapp-has-canon-client": { - RollappId: "rollapp-has-canon-client", + { + Height: 2, + StateRoot: []byte("appHash2"), + Timestamp: header.SignedHeader.Header.Time.Add(1), }, }, - } - }, - assert: func(ctx sdk.Context, k keeper.Keeper, err error) { - require.Error(t, err) + }, }, }, } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - keeper, ctx := keepertest.LightClientKeeper(t) - testClientStates := map[string]exported.ClientState{ - "non-tm-client-id": &ibcsolomachine.ClientState{}, - "canon-client-id": &ibctm.ClientState{ - ChainId: "rollapp-has-canon-client", - }, - } - ibcclientKeeper := NewMockIBCClientKeeper(testClientStates) - ibcchannelKeeper := NewMockIBCChannelKeeper(nil) - input := tc.prepare(ctx, *keeper) - rollappKeeper := NewMockRollappKeeper(input.rollapps, input.stateInfos) - ibcMsgDecorator := ante.NewIBCMessagesDecorator(*keeper, ibcclientKeeper, ibcchannelKeeper, rollappKeeper) - err := ibcMsgDecorator.HandleMsgUpdateClient(ctx, input.msg) - tc.assert(ctx, *keeper, err) - }) + ibcclientKeeper := NewMockIBCClientKeeper(testClientStates) + ibcchannelKeeper := NewMockIBCChannelKeeper(nil) + rollappKeeper := NewMockRollappKeeper(rollapps, stateInfos) + ibcMsgDecorator := ante.NewIBCMessagesDecorator(*k, ibcclientKeeper, ibcchannelKeeper, rollappKeeper) + clientMsg, err := ibcclienttypes.PackClientMessage(&header) + require.NoError(t, err) + msg := &ibcclienttypes.MsgUpdateClient{ + ClientId: keepertest.CanonClientID, + ClientMessage: clientMsg, + Signer: "relayerAddr", } + err = ibcMsgDecorator.HandleMsgUpdateClient(ctx, msg) + require.NoError(t, err) } + +// TODO: bring back the rest of the old tests https://github.com/dymensionxyz/dymension/issues/1364 diff --git a/x/lightclient/ante/ibc_msgs.go b/x/lightclient/ante/ibc_msgs.go index 5148fd8db..792cffae8 100644 --- a/x/lightclient/ante/ibc_msgs.go +++ b/x/lightclient/ante/ibc_msgs.go @@ -12,36 +12,42 @@ import ( var _ sdk.AnteDecorator = IBCMessagesDecorator{} type IBCMessagesDecorator struct { - ibcClientKeeper types.IBCClientKeeperExpected - ibcChannelKeeper types.IBCChannelKeeperExpected - rollappKeeper types.RollappKeeperExpected - lightClientKeeper keeper.Keeper + ibcClientKeeper types.IBCClientKeeperExpected + ibcChannelKeeper types.IBCChannelKeeperExpected + raK types.RollappKeeperExpected + k keeper.Keeper } -func NewIBCMessagesDecorator(k keeper.Keeper, ibcClient types.IBCClientKeeperExpected, ibcChannel types.IBCChannelKeeperExpected, rk types.RollappKeeperExpected) IBCMessagesDecorator { +func NewIBCMessagesDecorator( + k keeper.Keeper, + ibcClient types.IBCClientKeeperExpected, + ibcChannel types.IBCChannelKeeperExpected, + rk types.RollappKeeperExpected, +) IBCMessagesDecorator { return IBCMessagesDecorator{ - ibcClientKeeper: ibcClient, - ibcChannelKeeper: ibcChannel, - rollappKeeper: rk, - lightClientKeeper: k, + ibcClientKeeper: ibcClient, + ibcChannelKeeper: ibcChannel, + raK: rk, + k: k, } } func (i IBCMessagesDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { msgs := tx.GetMsgs() for _, m := range msgs { + // TODO: need to handle authz etc switch msg := m.(type) { case *ibcclienttypes.MsgSubmitMisbehaviour: if err := i.HandleMsgSubmitMisbehaviour(ctx, msg); err != nil { - return ctx, errorsmod.Wrap(err, "failed to handle MsgSubmitMisbehaviour") + return ctx, errorsmod.Wrap(err, "handle MsgSubmitMisbehaviour") } case *ibcclienttypes.MsgUpdateClient: if err := i.HandleMsgUpdateClient(ctx, msg); err != nil { - return ctx, errorsmod.Wrap(err, "failed to handle MsgUpdateClient") + return ctx, errorsmod.Wrap(err, "handle MsgUpdateClient") } case *ibcchanneltypes.MsgChannelOpenAck: if err := i.HandleMsgChannelOpenAck(ctx, msg); err != nil { - return ctx, errorsmod.Wrap(err, "failed to handle MsgChannelOpenAck") + return ctx, errorsmod.Wrap(err, "handle MsgChannelOpenAck") } default: continue diff --git a/x/lightclient/keeper/canonical_client.go b/x/lightclient/keeper/canonical_client.go index c30978bf7..ba8b25862 100644 --- a/x/lightclient/keeper/canonical_client.go +++ b/x/lightclient/keeper/canonical_client.go @@ -63,7 +63,7 @@ func (k Keeper) GetAllCanonicalClients(ctx sdk.Context) (clients []types.Canonic } func (k Keeper) expectedClient(ctx sdk.Context) ibctm.ClientState { - return types.ExpectedCanonicalClientParams(k.sequencerKeeper.UnbondingTime(ctx)) + return types.DefaultExpectedCanonicalClientParams() } var errChainIDMismatch = errors.New("chain id mismatch") @@ -108,9 +108,10 @@ func (k Keeper) validClient(ctx sdk.Context, clientID string, cs exported.Client return errorsmod.Wrapf(err, "find state info by height h+1: %d", h+1) } bd, _ := stateInfoH.GetBlockDescriptor(h) - nextSeq, err := k.GetSequencerPubKey(ctx, stateInfoHplus1.Sequencer) + + nextSeq, err := k.SeqK.RealSequencer(ctx, stateInfoHplus1.Sequencer) if err != nil { - return errorsmod.Wrap(err, "get sequencer pubkey") + return errorsmod.Wrap(err, "get sequencer") } rollappState := types.RollappState{ BlockDescriptor: bd, diff --git a/x/lightclient/keeper/genesis.go b/x/lightclient/keeper/genesis.go index 19b4f5260..2cc0d3c2f 100644 --- a/x/lightclient/keeper/genesis.go +++ b/x/lightclient/keeper/genesis.go @@ -1,6 +1,7 @@ package keeper import ( + "cosmossdk.io/collections" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/dymension/v3/x/lightclient/types" ) @@ -12,16 +13,30 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genesisState types.GenesisState) { for _, client := range genesisState.GetCanonicalClients() { k.SetCanonicalClient(ctx, client.RollappId, client.IbcClientId) } - for _, stateSigner := range genesisState.GetConsensusStateSigners() { - k.SetConsensusStateValHash(ctx, stateSigner.IbcClientId, stateSigner.Height, []byte(stateSigner.BlockValHash)) + for _, signer := range genesisState.HeaderSigners { + if err := k.SaveSigner(ctx, signer.SequencerAddress, signer.ClientId, signer.Height); err != nil { + panic(err) + } } } func (k Keeper) ExportGenesis(ctx sdk.Context) types.GenesisState { clients := k.GetAllCanonicalClients(ctx) - stateSigners := k.GetAllConsensusStateSigners(ctx) - return types.GenesisState{ - CanonicalClients: clients, - ConsensusStateSigners: stateSigners, + + ret := types.GenesisState{ + CanonicalClients: clients, + } + + if err := k.headerSigners.Walk(ctx, nil, + func(key collections.Triple[string, string, uint64]) (stop bool, err error) { + ret.HeaderSigners = append(ret.HeaderSigners, types.HeaderSignerEntry{ + SequencerAddress: key.K1(), + ClientId: key.K2(), + Height: key.K3(), + }) + return false, nil + }); err != nil { + panic(err) } + return ret } diff --git a/x/lightclient/keeper/genesis_test.go b/x/lightclient/keeper/genesis_test.go index 657c96814..c3d240742 100644 --- a/x/lightclient/keeper/genesis_test.go +++ b/x/lightclient/keeper/genesis_test.go @@ -1,6 +1,7 @@ package keeper_test import ( + "reflect" "testing" keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" @@ -14,14 +15,9 @@ func TestInitGenesis(t *testing.T) { {RollappId: "rollapp-1", IbcClientId: "client-1"}, {RollappId: "rollapp-2", IbcClientId: "client-2"}, } - stateSigners := []types.ConsensusStateSigner{ - {IbcClientId: "client-1", Height: 1, BlockValHash: "signer-1"}, - {IbcClientId: "client-1", Height: 2, BlockValHash: "signer-1"}, - } keeper.InitGenesis(ctx, types.GenesisState{ - CanonicalClients: clients, - ConsensusStateSigners: stateSigners, + CanonicalClients: clients, }) ibc, found := keeper.GetCanonicalClient(ctx, "rollapp-1") @@ -30,13 +26,6 @@ func TestInitGenesis(t *testing.T) { ibc, found = keeper.GetCanonicalClient(ctx, "rollapp-2") require.True(t, found) require.Equal(t, "client-2", ibc) - - signer, found := keeper.GetConsensusStateValHash(ctx, "client-1", 1) - require.True(t, found) - require.Equal(t, []byte("signer-1"), signer) - signer, found = keeper.GetConsensusStateValHash(ctx, "client-1", 2) - require.True(t, found) - require.Equal(t, []byte("signer-1"), signer) } func TestExportGenesis(t *testing.T) { @@ -44,8 +33,6 @@ func TestExportGenesis(t *testing.T) { keeper.SetCanonicalClient(ctx, "rollapp-1", "client-1") keeper.SetCanonicalClient(ctx, "rollapp-2", "client-2") - keeper.SetConsensusStateValHash(ctx, "client-1", 1, []byte("signer-1")) - keeper.SetConsensusStateValHash(ctx, "client-1", 2, []byte("signer-1")) genesis := keeper.ExportGenesis(ctx) @@ -54,11 +41,37 @@ 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.ConsensusStateSigners, 2) - require.Equal(t, "client-1", genesis.ConsensusStateSigners[0].IbcClientId) - require.Equal(t, "client-1", genesis.ConsensusStateSigners[1].IbcClientId) - require.Equal(t, uint64(1), genesis.ConsensusStateSigners[0].Height) - require.Equal(t, uint64(2), genesis.ConsensusStateSigners[1].Height) - require.Equal(t, "signer-1", genesis.ConsensusStateSigners[0].BlockValHash) - require.Equal(t, "signer-1", genesis.ConsensusStateSigners[1].BlockValHash) +} + +func TestImportExportGenesis(t *testing.T) { + k, ctx := keepertest.LightClientKeeper(t) + + g := types.GenesisState{ + CanonicalClients: []types.CanonicalClient{ + { + RollappId: "rollapp-1", + IbcClientId: "client-1", + }, + { + RollappId: "rollapp-2", + IbcClientId: "client-2", + }, + }, + HeaderSigners: []types.HeaderSignerEntry{ + { + SequencerAddress: "signer-1", + ClientId: "client-1", + Height: 42, + }, + { + SequencerAddress: "signer-2", + ClientId: "client-2", + Height: 43, + }, + }, + } + + k.InitGenesis(ctx, g) + compare := k.ExportGenesis(ctx) + require.True(t, reflect.DeepEqual(g, compare), "expected %v but got %v", g, compare) } diff --git a/x/lightclient/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index 40a04f83c..a340362cd 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -1,11 +1,15 @@ package keeper import ( - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" + "errors" + + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" ibcclienttypes "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/dymensionxyz/dymension/v3/x/lightclient/types" + sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) @@ -31,11 +35,20 @@ func (hook rollappHook) AfterUpdateState( rollappId string, stateInfo *rollapptypes.StateInfo, ) error { - canonicalClient, found := hook.k.GetCanonicalClient(ctx, rollappId) - if !found { - canonicalClient, foundClient := hook.k.GetProspectiveCanonicalClient(ctx, rollappId, stateInfo.GetLatestHeight()-1) - if foundClient { - hook.k.SetCanonicalClient(ctx, rollappId, canonicalClient) + if !hook.k.Enabled() { + return nil + } + + client, ok := hook.k.GetCanonicalClient(ctx, rollappId) + if !ok { + client, ok = hook.k.GetProspectiveCanonicalClient(ctx, rollappId, stateInfo.GetLatestHeight()-1) + if ok { + hook.k.SetCanonicalClient(ctx, rollappId, client) + // we now verified everything up to and including stateInfo.GetLatestHeight()-1 + // so we should prune everything up to stateInfo.GetLatestHeight()-1 + if err := hook.k.PruneSignersBelow(ctx, rollappId, stateInfo.GetLatestHeight()); err != nil { + return errorsmod.Wrap(err, "prune signers") + } } return nil } @@ -46,57 +59,94 @@ func (hook rollappHook) AfterUpdateState( return nil } - sequencerPk, err := hook.k.GetSequencerPubKey(ctx, stateInfo.Sequencer) + seq, err := hook.k.SeqK.RealSequencer(ctx, stateInfo.Sequencer) if err != nil { - return err - } - latestHeight := stateInfo.GetLatestHeight() - // We check from latestHeight-1 downwards, as the nextValHash for latestHeight will not be available until next stateupdate - for h := latestHeight - 1; h >= stateInfo.StartHeight; h-- { - bd, _ := stateInfo.GetBlockDescriptor(h) - // Check if any optimistic updates were made for the given height - blockValHash, found := hook.k.GetConsensusStateValHash(ctx, canonicalClient, bd.GetHeight()) - if !found { - continue - } - err := hook.checkStateForHeight(ctx, rollappId, bd, canonicalClient, sequencerPk, blockValHash) - if err != nil { - return err - } + return errorsmod.Wrap(errors.Join(gerrc.ErrInternal, err), "get sequencer for state info") } - // Check for the last BD from the previous stateInfo as now we have the nextValhash available for that block - blockValHash, found := hook.k.GetConsensusStateValHash(ctx, canonicalClient, stateInfo.StartHeight-1) - if found { - previousStateInfo, err := hook.k.rollappKeeper.FindStateInfoByHeight(ctx, rollappId, stateInfo.StartHeight-1) - if err != nil { - return err - } - bd, _ := previousStateInfo.GetBlockDescriptor(stateInfo.StartHeight - 1) - err = hook.checkStateForHeight(ctx, rollappId, bd, canonicalClient, sequencerPk, blockValHash) - if err != nil { - return err + + // [hStart-1..,hEnd) is correct because we compare against a next validators hash + for h := stateInfo.GetStartHeight() - 1; h < stateInfo.GetLatestHeight(); h++ { + if err := hook.validateOptimisticUpdate(ctx, rollappId, client, seq, stateInfo, h); err != nil { + return errorsmod.Wrap(err, "validate optimistic update") } } return nil } -func (hook rollappHook) checkStateForHeight(ctx sdk.Context, rollappId string, bd rollapptypes.BlockDescriptor, canonicalClient string, sequencerPk tmprotocrypto.PublicKey, blockValHash []byte) error { - cs, _ := hook.k.ibcClientKeeper.GetClientState(ctx, canonicalClient) - height := ibcclienttypes.NewHeight(cs.GetLatestHeight().GetRevisionNumber(), bd.GetHeight()) - consensusState, _ := hook.k.ibcClientKeeper.GetClientConsensusState(ctx, canonicalClient, height) - // Cast consensus state to tendermint consensus state - we need this to check the state root and timestamp and nextValHash - tmConsensusState, ok := consensusState.(*ibctm.ConsensusState) +func (hook rollappHook) validateOptimisticUpdate( + ctx sdk.Context, + rollapp string, + client string, + nextSequencer sequencertypes.Sequencer, + cache *rollapptypes.StateInfo, // a place to look up the BD for a height + h uint64, +) error { + got, ok := hook.getConsensusState(ctx, client, h) if !ok { + // done, nothing to validate return nil } - rollappState := types.RollappState{ - BlockDescriptor: bd, - NextBlockSequencer: sequencerPk, - } - err := types.CheckCompatibility(*tmConsensusState, rollappState) + expectBD, err := hook.getBlockDescriptor(ctx, rollapp, cache, h) if err != nil { return err } - hook.k.RemoveConsensusStateValHash(ctx, canonicalClient, bd.GetHeight()) + expect := types.RollappState{ + BlockDescriptor: expectBD, + NextBlockSequencer: nextSequencer, + } + signerAddr, err := hook.k.GetSigner(ctx, client, h) + if err != nil { + return gerrc.ErrInternal.Wrapf("got cons state but no signer addr: client: %s: h: %d", client, h) + } + signer, err := hook.k.SeqK.RealSequencer(ctx, signerAddr) + if err != nil { + return gerrc.ErrInternal.Wrapf("got cons state but no signer seq: client: %s: h: %d: signer addr: %s", client, h, signerAddr) + } + // remove to allow unbond + err = hook.k.RemoveSigner(ctx, signer.Address, client, h) + if err != nil { + return errorsmod.Wrap(err, "remove signer") + } + err = types.CheckCompatibility(*got, expect) + if err != nil { + // return gerrc.ErrFault + return errors.Join(gerrc.ErrFault, err) + } + + // everything is fine return nil } + +func (hook rollappHook) getBlockDescriptor(ctx sdk.Context, + rollapp string, + cache *rollapptypes.StateInfo, + h uint64, +) (rollapptypes.BlockDescriptor, error) { + stateInfo := cache + if !stateInfo.ContainsHeight(h) { + var err error + stateInfo, err = hook.k.rollappKeeper.FindStateInfoByHeight(ctx, rollapp, h) + if err != nil { + return rollapptypes.BlockDescriptor{}, errors.Join(err, gerrc.ErrInternal) + } + } + bd, _ := stateInfo.GetBlockDescriptor(h) + return bd, nil +} + +func (hook rollappHook) getConsensusState(ctx sdk.Context, + client string, + h uint64, +) (*ibctm.ConsensusState, bool) { + cs, _ := hook.k.ibcClientKeeper.GetClientState(ctx, client) + height := ibcclienttypes.NewHeight(cs.GetLatestHeight().GetRevisionNumber(), h) + consensusState, ok := hook.k.ibcClientKeeper.GetClientConsensusState(ctx, client, height) + if !ok { + return nil, false + } + tmConsensusState, ok := consensusState.(*ibctm.ConsensusState) + if !ok { + return nil, false + } + return tmConsensusState, true +} diff --git a/x/lightclient/keeper/hook_listener_test.go b/x/lightclient/keeper/hook_listener_test.go index 79bcdf1e2..c2fdd7463 100644 --- a/x/lightclient/keeper/hook_listener_test.go +++ b/x/lightclient/keeper/hook_listener_test.go @@ -35,41 +35,17 @@ func TestAfterUpdateState(t *testing.T) { }, expectErr: false, }, - { - name: "canonical client exists but consensus state is not found for given height", - prepare: func(ctx sdk.Context, k lightClientKeeper.Keeper) testInput { - k.SetCanonicalClient(ctx, "rollapp-has-canon-client-but-no-state", "canon-client-id-no-state") - return testInput{ - rollappId: "rollapp-has-canon-client-but-no-state", - stateInfo: &rollapptypes.StateInfo{ - Sequencer: keepertest.Alice, - StartHeight: 1, - NumBlocks: 1, - BDs: rollapptypes.BlockDescriptors{ - BD: []rollapptypes.BlockDescriptor{ - { - Height: 1, - StateRoot: []byte("test"), - Timestamp: time.Unix(1724392989, 0), - }, - }, - }, - }, - } - }, - expectErr: false, - }, + { name: "both states are not compatible - slash the sequencer who signed", prepare: func(ctx sdk.Context, k lightClientKeeper.Keeper) testInput { - k.SetCanonicalClient(ctx, "rollapp-has-canon-client", "canon-client-id") - seqValHash, err := k.GetSequencerHash(ctx, keepertest.Alice) + k.SetCanonicalClient(ctx, keepertest.DefaultRollapp, keepertest.CanonClientID) + err := k.SaveSigner(ctx, keepertest.Alice.Address, keepertest.CanonClientID, 2) require.NoError(t, err) - k.SetConsensusStateValHash(ctx, "canon-client-id", 2, seqValHash) return testInput{ - rollappId: "rollapp-has-canon-client", + rollappId: keepertest.DefaultRollapp, stateInfo: &rollapptypes.StateInfo{ - Sequencer: keepertest.Alice, + Sequencer: keepertest.Alice.Address, StartHeight: 1, NumBlocks: 3, BDs: rollapptypes.BlockDescriptors{ @@ -99,14 +75,14 @@ func TestAfterUpdateState(t *testing.T) { { name: "state is compatible", prepare: func(ctx sdk.Context, k lightClientKeeper.Keeper) testInput { - k.SetCanonicalClient(ctx, "rollapp-has-canon-client", "canon-client-id") - seqValHash, err := k.GetSequencerHash(ctx, keepertest.Alice) + k.SetCanonicalClient(ctx, keepertest.DefaultRollapp, keepertest.CanonClientID) + err := k.SaveSigner(ctx, keepertest.Alice.Address, keepertest.CanonClientID, 2) require.NoError(t, err) - k.SetConsensusStateValHash(ctx, "canon-client-id", 2, seqValHash) + return testInput{ - rollappId: "rollapp-has-canon-client", + rollappId: keepertest.DefaultRollapp, stateInfo: &rollapptypes.StateInfo{ - Sequencer: keepertest.Alice, + Sequencer: keepertest.Alice.Address, StartHeight: 1, NumBlocks: 3, BDs: rollapptypes.BlockDescriptors{ diff --git a/x/lightclient/keeper/keeper.go b/x/lightclient/keeper/keeper.go index aa47c5388..fdd3479b5 100644 --- a/x/lightclient/keeper/keeper.go +++ b/x/lightclient/keeper/keeper.go @@ -1,28 +1,55 @@ package keeper import ( - "bytes" "context" "errors" "fmt" + "cosmossdk.io/collections" errorsmod "cosmossdk.io/errors" "github.com/cometbft/cometbft/libs/log" - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" "github.com/cosmos/cosmos-sdk/codec" 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/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 { + return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) +} + +// wrapper to allow taking a pointer to mutable value +type enabled struct { + enabled bool +} + type Keeper struct { + // if false, will not run the msg update client ante handler. Very hacky + // use to avoid problems in ibctesting. + enabled *enabled + cdc codec.BinaryCodec storeKey storetypes.StoreKey ibcClientKeeper types.IBCClientKeeperExpected - sequencerKeeper types.SequencerKeeperExpected + SeqK types.SequencerKeeperExpected rollappKeeper types.RollappKeeperExpected + + // + headerSigners collections.KeySet[collections.Triple[string, string, uint64]] + // -> + clientHeightToSigner collections.Map[collections.Pair[string, uint64], string] +} + +func (k Keeper) Enabled() bool { + return k.enabled.enabled +} + +func (k Keeper) SetEnabled(b bool) { + k.enabled.enabled = b } func NewKeeper( @@ -32,86 +59,126 @@ func NewKeeper( sequencerKeeper types.SequencerKeeperExpected, rollappKeeper types.RollappKeeperExpected, ) *Keeper { + service := collcompat.NewKVStoreService(storeKey) + sb := collections.NewSchemaBuilder(service) k := &Keeper{ + enabled: &enabled{true}, cdc: cdc, storeKey: storeKey, ibcClientKeeper: ibcKeeper, - sequencerKeeper: sequencerKeeper, + SeqK: sequencerKeeper, rollappKeeper: rollappKeeper, + headerSigners: collections.NewKeySet( + sb, + types.HeaderSignersPrefixKey, + "header_signers", + collections.TripleKeyCodec(collections.StringKey, collections.StringKey, collections.Uint64Key), + ), + clientHeightToSigner: collections.NewMap( + sb, + types.ClientHeightToSigner, + "client_height_to_signer", + collections.PairKeyCodec(collections.StringKey, collections.Uint64Key), + collections.StringValue, + ), } return k } -// GetSequencerHash returns the sequencer's tendermint public key hash -func (k Keeper) GetSequencerHash(ctx sdk.Context, sequencerAddr string) ([]byte, error) { - seq, found := k.sequencerKeeper.GetSequencer(ctx, sequencerAddr) - if !found { - return nil, fmt.Errorf("sequencer not found") +func (k Keeper) CanUnbond(ctx sdk.Context, seq sequencertypes.Sequencer) error { + client, ok := k.GetCanonicalClient(ctx, seq.RollappId) + if !ok { + return errorsmod.Wrap(sequencertypes.ErrUnbondNotAllowed, "no canonical client") } - return seq.GetDymintPubKeyHash() -} - -func (k Keeper) GetSequencerPubKey(ctx sdk.Context, sequencerAddr string) (tmprotocrypto.PublicKey, error) { - seq, found := k.sequencerKeeper.GetSequencer(ctx, sequencerAddr) - if !found { - return tmprotocrypto.PublicKey{}, fmt.Errorf("sequencer not found") + rng := collections.NewSuperPrefixedTripleRange[string, string, uint64](seq.Address, client) + return k.headerSigners.Walk(ctx, rng, func(key collections.Triple[string, string, uint64]) (stop bool, err error) { + return true, errorsmod.Wrapf(sequencertypes.ErrUnbondNotAllowed, "unverified header: h: %d", key.K3()) + }) +} + +// PruneSignersAbove removes bookkeeping for all heights ABOVE h for given rollapp +// This should only be called after canonical client set +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") } - return seq.GetCometPubKey() -} - -func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) -} -func (k Keeper) GetSequencerFromValHash(ctx sdk.Context, rollappID string, blockValHash []byte) (string, error) { - sequencerList := k.sequencerKeeper.GetSequencersByRollapp(ctx, rollappID) - for _, seq := range sequencerList { - seqHash, err := seq.GetDymintPubKeyHash() - if err != nil { - return "", err - } - if bytes.Equal(seqHash, blockValHash) { - return seq.Address, nil + 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 "", types.ErrSequencerNotFound -} + return nil +} + +// PruneSignersBelow removes bookkeeping for all heights BELOW h for given rollapp +// 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") + } -// SetConsensusStateValHash sets block valHash for the given height of the client -func (k Keeper) SetConsensusStateValHash(ctx sdk.Context, clientID string, height uint64, blockValHash []byte) { - store := ctx.KVStore(k.storeKey) - store.Set(types.ConsensusStateValhashKeyByClientID(clientID, height), blockValHash) + 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) RemoveConsensusStateValHash(ctx sdk.Context, clientID string, height uint64) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.ConsensusStateValhashKeyByClientID(clientID, height)) +// GetSigner returns the sequencer address who signed the header in the update +func (k Keeper) GetSigner(ctx sdk.Context, client string, h uint64) (string, error) { + return k.clientHeightToSigner.Get(ctx, collections.Join(client, h)) } -// GetConsensusStateValHash returns the block valHash for the given height of the client -func (k Keeper) GetConsensusStateValHash(ctx sdk.Context, clientID string, height uint64) ([]byte, bool) { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.ConsensusStateValhashKeyByClientID(clientID, height)) - if bz == nil { - return nil, false - } - return bz, true +func (k Keeper) SaveSigner(ctx sdk.Context, seqAddr string, client string, h uint64) error { + return errors.Join( + k.headerSigners.Set(ctx, collections.Join3(seqAddr, client, h)), + k.clientHeightToSigner.Set(ctx, collections.Join(client, h), seqAddr), + ) } -func (k Keeper) GetAllConsensusStateSigners(ctx sdk.Context) (signers []types.ConsensusStateSigner) { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, types.ConsensusStateValhashKey) - defer iterator.Close() // nolint: errcheck - for ; iterator.Valid(); iterator.Next() { - key := iterator.Key() - clientID, height := types.ParseConsensusStateValhashKey(key) - signers = append(signers, types.ConsensusStateSigner{ - IbcClientId: clientID, - Height: height, - BlockValHash: string(iterator.Value()), - }) - } - return +func (k Keeper) RemoveSigner(ctx sdk.Context, seqAddr string, client string, h uint64) error { + return errors.Join( + k.headerSigners.Remove(ctx, collections.Join3(seqAddr, client, h)), + k.clientHeightToSigner.Remove(ctx, collections.Join(client, h)), + ) } func (k Keeper) GetRollappForClientID(ctx sdk.Context, clientID string) (string, bool) { diff --git a/x/lightclient/keeper/keeper_test.go b/x/lightclient/keeper/keeper_test.go new file mode 100644 index 000000000..ea5c59758 --- /dev/null +++ b/x/lightclient/keeper/keeper_test.go @@ -0,0 +1,115 @@ +package keeper_test + +import ( + "testing" + + cometbftproto "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/dymensionxyz/dymension/v3/app/apptesting" + keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" + "github.com/dymensionxyz/dymension/v3/x/lightclient/keeper" + sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/sdk-utils/utils/utest" + "github.com/stretchr/testify/suite" +) + +type TestSuite struct { + apptesting.KeeperTestHelper +} + +func (s *TestSuite) SetupTest() { + app := apptesting.Setup(s.T(), false) + ctx := app.GetBaseApp().NewContext(false, cometbftproto.Header{}) + + s.App = app + s.Ctx = ctx +} + +func (s *TestSuite) k() *keeper.Keeper { + return &s.App.LightClientKeeper +} + +func TestSequencerKeeperTestSuite(t *testing.T) { + suite.Run(t, new(TestSuite)) +} + +// Basic flow should prevent unbonding at appropriate times, and +// handle pruning. +func (s *TestSuite) TestUnbondConditionFlow() { + seq := keepertest.Alice + + client := keepertest.CanonClientID + + s.k().SetCanonicalClient(s.Ctx, seq.RollappId, client) + + // allowed! + err := s.k().CanUnbond(s.Ctx, seq) + s.Require().NoError(err) + + // add some unverified headers + for h := range 10 { + err := s.k().SaveSigner(s.Ctx, seq.Address, client, uint64(h)) + s.Require().NoError(err) + } + + // not allowed! + err = s.k().CanUnbond(s.Ctx, seq) + utest.IsErr(s.Require(), err, sequencertypes.ErrUnbondNotAllowed) + + // we prune some, but still not allowed + err = s.k().PruneSignersAbove(s.Ctx, seq.RollappId, 6) + s.Require().NoError(err) + + err = s.k().CanUnbond(s.Ctx, seq) + utest.IsErr(s.Require(), err, sequencertypes.ErrUnbondNotAllowed) + + // the rest are verified + for h := range 7 { + err := s.k().RemoveSigner(s.Ctx, seq.Address, client, uint64(h)) + s.Require().NoError(err) + } + + // allowed! + err = s.k().CanUnbond(s.Ctx, seq) + s.Require().NoError(err) +} + +// Basic flow should prevent unbonding at appropriate times, and +// handle pruning. +func (s *TestSuite) TestPruneBelow() { + seq := keepertest.Alice + + client := keepertest.CanonClientID + + s.k().SetCanonicalClient(s.Ctx, seq.RollappId, client) + + // allowed! + err := s.k().CanUnbond(s.Ctx, seq) + s.Require().NoError(err) + + // add some unverified headers + for h := range 10 { + err := s.k().SaveSigner(s.Ctx, seq.Address, client, uint64(h)) + s.Require().NoError(err) + } + + // not allowed! + err = s.k().CanUnbond(s.Ctx, seq) + utest.IsErr(s.Require(), err, sequencertypes.ErrUnbondNotAllowed) + + // we prune some, but still not allowed + err = s.k().PruneSignersBelow(s.Ctx, seq.RollappId, 6) + s.Require().NoError(err) + + err = s.k().CanUnbond(s.Ctx, seq) + utest.IsErr(s.Require(), err, sequencertypes.ErrUnbondNotAllowed) + + // the rest are verified + for h := 6; h < 10; h++ { + err := s.k().RemoveSigner(s.Ctx, seq.Address, client, uint64(h)) + s.Require().NoError(err) + } + + // allowed! + err = s.k().CanUnbond(s.Ctx, seq) + s.Require().NoError(err) +} diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index 351469cd4..f85f10160 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -36,11 +36,12 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraud deleteConsensusState(cs, h) deleteConsensusMetadata(cs, h) - // clean the optimistic updates valset - k.RemoveConsensusStateValHash(ctx, client, h.GetRevisionHeight()) - return false }) + + // clean the optimistic updates valset + k.PruneSignersAbove(ctx, client, fraudHeight-1) + // marks that hard fork is in progress k.setHardForkInProgress(ctx, rollappId) @@ -59,8 +60,8 @@ func (k Keeper) ResolveHardFork(ctx sdk.Context, rollappID string) { bd := stateinfo.GetLatestBlockDescriptor() // get the valHash of this sequencer - proposer, _ := k.sequencerKeeper.GetSequencer(ctx, stateinfo.Sequencer) - valHash, _ := proposer.GetDymintPubKeyHash() + proposer, _ := k.SeqK.RealSequencer(ctx, stateinfo.Sequencer) + valHash, _ := proposer.ValsetHash() // unfreeze the client and set the latest height k.resetClientToValidState(clientStore, height) diff --git a/x/lightclient/types/expected_keepers.go b/x/lightclient/types/expected_keepers.go index ac00ff3a4..65dc146c4 100644 --- a/x/lightclient/types/expected_keepers.go +++ b/x/lightclient/types/expected_keepers.go @@ -2,8 +2,8 @@ package types import ( "context" - "time" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" @@ -13,12 +13,8 @@ import ( ) type SequencerKeeperExpected interface { - GetSequencer(ctx sdk.Context, sequencerAddress string) (val sequencertypes.Sequencer, found bool) - GetSequencersByRollapp(ctx sdk.Context, rollappId string) (list []sequencertypes.Sequencer) - UnbondingTime(ctx sdk.Context) (res time.Duration) - JailSequencerOnFraud(ctx sdk.Context, sequencerAddress string) error - - GetProposer(ctx sdk.Context, rollappId string) (val sequencertypes.Sequencer, found bool) + SequencerByDymintAddr(ctx sdk.Context, addr cryptotypes.Address) (sequencertypes.Sequencer, error) + RealSequencer(ctx sdk.Context, addr string) (sequencertypes.Sequencer, error) } type RollappKeeperExpected interface { diff --git a/x/lightclient/types/genesis.go b/x/lightclient/types/genesis.go index dc655184f..d6c0b2399 100644 --- a/x/lightclient/types/genesis.go +++ b/x/lightclient/types/genesis.go @@ -4,8 +4,7 @@ import fmt "fmt" func DefaultGenesisState() GenesisState { return GenesisState{ - CanonicalClients: []CanonicalClient{}, - ConsensusStateSigners: []ConsensusStateSigner{}, + CanonicalClients: []CanonicalClient{}, } } @@ -18,16 +17,6 @@ func (g GenesisState) Validate() error { return fmt.Errorf("invalid ibc client id: %v", client) } } - for _, stateSigner := range g.ConsensusStateSigners { - if stateSigner.IbcClientId == "" { - return fmt.Errorf("invalid ibc client id: %v", stateSigner) - } - if stateSigner.Height == 0 { - return fmt.Errorf("invalid height: %v", stateSigner) - } - if stateSigner.BlockValHash == "" { - return fmt.Errorf("invalid signer: %v", stateSigner) - } - } + return nil } diff --git a/x/lightclient/types/genesis.pb.go b/x/lightclient/types/genesis.pb.go index bac2bb4eb..737c834f9 100644 --- a/x/lightclient/types/genesis.pb.go +++ b/x/lightclient/types/genesis.pb.go @@ -23,16 +23,78 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// Used for genesis import/export only +type HeaderSignerEntry struct { + // acc addr + SequencerAddress string `protobuf:"bytes,1,opt,name=sequencer_address,json=sequencerAddress,proto3" json:"sequencer_address,omitempty"` + ClientId string `protobuf:"bytes,2,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + Height uint64 `protobuf:"varint,3,opt,name=height,proto3" json:"height,omitempty"` +} + +func (m *HeaderSignerEntry) Reset() { *m = HeaderSignerEntry{} } +func (m *HeaderSignerEntry) String() string { return proto.CompactTextString(m) } +func (*HeaderSignerEntry) ProtoMessage() {} +func (*HeaderSignerEntry) Descriptor() ([]byte, []int) { + return fileDescriptor_5520440548912168, []int{0} +} +func (m *HeaderSignerEntry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *HeaderSignerEntry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_HeaderSignerEntry.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 *HeaderSignerEntry) XXX_Merge(src proto.Message) { + xxx_messageInfo_HeaderSignerEntry.Merge(m, src) +} +func (m *HeaderSignerEntry) XXX_Size() int { + return m.Size() +} +func (m *HeaderSignerEntry) XXX_DiscardUnknown() { + xxx_messageInfo_HeaderSignerEntry.DiscardUnknown(m) +} + +var xxx_messageInfo_HeaderSignerEntry proto.InternalMessageInfo + +func (m *HeaderSignerEntry) GetSequencerAddress() string { + if m != nil { + return m.SequencerAddress + } + return "" +} + +func (m *HeaderSignerEntry) GetClientId() string { + if m != nil { + return m.ClientId + } + return "" +} + +func (m *HeaderSignerEntry) GetHeight() uint64 { + if m != nil { + return m.Height + } + return 0 +} + type GenesisState struct { - CanonicalClients []CanonicalClient `protobuf:"bytes,1,rep,name=canonical_clients,json=canonicalClients,proto3" json:"canonical_clients"` - ConsensusStateSigners []ConsensusStateSigner `protobuf:"bytes,2,rep,name=consensus_state_signers,json=consensusStateSigners,proto3" json:"consensus_state_signers"` + 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"` } func (m *GenesisState) Reset() { *m = GenesisState{} } func (m *GenesisState) String() string { return proto.CompactTextString(m) } func (*GenesisState) ProtoMessage() {} func (*GenesisState) Descriptor() ([]byte, []int) { - return fileDescriptor_5520440548912168, []int{0} + return fileDescriptor_5520440548912168, []int{1} } func (m *GenesisState) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -68,9 +130,9 @@ func (m *GenesisState) GetCanonicalClients() []CanonicalClient { return nil } -func (m *GenesisState) GetConsensusStateSigners() []ConsensusStateSigner { +func (m *GenesisState) GetHeaderSigners() []HeaderSignerEntry { if m != nil { - return m.ConsensusStateSigners + return m.HeaderSigners } return nil } @@ -84,7 +146,7 @@ func (m *CanonicalClient) Reset() { *m = CanonicalClient{} } func (m *CanonicalClient) String() string { return proto.CompactTextString(m) } func (*CanonicalClient) ProtoMessage() {} func (*CanonicalClient) Descriptor() ([]byte, []int) { - return fileDescriptor_5520440548912168, []int{1} + return fileDescriptor_5520440548912168, []int{2} } func (m *CanonicalClient) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -127,73 +189,10 @@ func (m *CanonicalClient) GetIbcClientId() string { return "" } -type ConsensusStateSigner struct { - // ibc_client_id is the canonical IBC client which has accepted a client update optimistically - IbcClientId string `protobuf:"bytes,1,opt,name=ibc_client_id,json=ibcClientId,proto3" json:"ibc_client_id,omitempty"` - // height is the client height which was updated optimistically - Height uint64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` - // blockValHash is the valhash of the block which was updated optimistically - BlockValHash string `protobuf:"bytes,3,opt,name=blockValHash,proto3" json:"blockValHash,omitempty"` -} - -func (m *ConsensusStateSigner) Reset() { *m = ConsensusStateSigner{} } -func (m *ConsensusStateSigner) String() string { return proto.CompactTextString(m) } -func (*ConsensusStateSigner) ProtoMessage() {} -func (*ConsensusStateSigner) Descriptor() ([]byte, []int) { - return fileDescriptor_5520440548912168, []int{2} -} -func (m *ConsensusStateSigner) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *ConsensusStateSigner) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_ConsensusStateSigner.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 *ConsensusStateSigner) XXX_Merge(src proto.Message) { - xxx_messageInfo_ConsensusStateSigner.Merge(m, src) -} -func (m *ConsensusStateSigner) XXX_Size() int { - return m.Size() -} -func (m *ConsensusStateSigner) XXX_DiscardUnknown() { - xxx_messageInfo_ConsensusStateSigner.DiscardUnknown(m) -} - -var xxx_messageInfo_ConsensusStateSigner proto.InternalMessageInfo - -func (m *ConsensusStateSigner) GetIbcClientId() string { - if m != nil { - return m.IbcClientId - } - return "" -} - -func (m *ConsensusStateSigner) GetHeight() uint64 { - if m != nil { - return m.Height - } - return 0 -} - -func (m *ConsensusStateSigner) GetBlockValHash() string { - if m != nil { - return m.BlockValHash - } - return "" -} - func init() { + proto.RegisterType((*HeaderSignerEntry)(nil), "dymensionxyz.dymension.lightclient.HeaderSignerEntry") proto.RegisterType((*GenesisState)(nil), "dymensionxyz.dymension.lightclient.GenesisState") proto.RegisterType((*CanonicalClient)(nil), "dymensionxyz.dymension.lightclient.CanonicalClient") - proto.RegisterType((*ConsensusStateSigner)(nil), "dymensionxyz.dymension.lightclient.ConsensusStateSigner") } func init() { @@ -201,30 +200,72 @@ func init() { } var fileDescriptor_5520440548912168 = []byte{ - // 354 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xc1, 0x4e, 0xea, 0x40, - 0x14, 0x86, 0x3b, 0x40, 0x48, 0x18, 0xb8, 0xb9, 0xf7, 0x36, 0xa8, 0x8d, 0x89, 0x95, 0x74, 0xc5, - 0xaa, 0x35, 0xb2, 0x61, 0x0d, 0x0b, 0x65, 0x5b, 0x8c, 0x0b, 0x37, 0x4d, 0x3b, 0x1d, 0xdb, 0x89, - 0x65, 0xa6, 0xe1, 0x0c, 0x04, 0x7c, 0x0a, 0x1f, 0x8b, 0x25, 0x4b, 0x57, 0xc6, 0xc0, 0xde, 0x67, - 0x30, 0x9d, 0x16, 0x02, 0x82, 0xd1, 0xdd, 0xfc, 0x67, 0xce, 0xf7, 0xff, 0x67, 0x26, 0x07, 0x5f, - 0x85, 0xf3, 0x11, 0xe5, 0xc0, 0x04, 0x9f, 0xcd, 0x9f, 0x9d, 0xad, 0x70, 0x12, 0x16, 0xc5, 0x92, - 0x24, 0x8c, 0x72, 0xe9, 0x44, 0x94, 0x53, 0x60, 0x60, 0xa7, 0x63, 0x21, 0x85, 0x6e, 0xed, 0x12, - 0xf6, 0x56, 0xd8, 0x3b, 0xc4, 0x79, 0x33, 0x12, 0x91, 0x50, 0xed, 0x4e, 0x76, 0xca, 0x49, 0xeb, - 0x03, 0xe1, 0xc6, 0x4d, 0xee, 0x35, 0x94, 0xbe, 0xa4, 0xfa, 0x23, 0xfe, 0x4f, 0x7c, 0x2e, 0x38, - 0x23, 0x7e, 0xe2, 0xe5, 0x28, 0x18, 0xa8, 0x55, 0x6e, 0xd7, 0xaf, 0x3b, 0xf6, 0xcf, 0x31, 0x76, - 0x7f, 0x03, 0xf7, 0x95, 0xee, 0x55, 0x16, 0x6f, 0x97, 0x9a, 0xfb, 0x8f, 0xec, 0x97, 0x41, 0x9f, - 0xe2, 0x33, 0x22, 0x38, 0x50, 0x0e, 0x13, 0xf0, 0x20, 0x8b, 0xf6, 0x80, 0x45, 0x9c, 0x8e, 0xc1, - 0x28, 0xa9, 0xb4, 0xee, 0xaf, 0xd2, 0x36, 0x16, 0x6a, 0xf8, 0xa1, 0x32, 0x28, 0x22, 0x4f, 0xc8, - 0x91, 0x3b, 0xb0, 0xee, 0xf0, 0xdf, 0x2f, 0x23, 0xea, 0x17, 0x18, 0x8f, 0x45, 0x92, 0xf8, 0x69, - 0xea, 0xb1, 0xd0, 0x40, 0x2d, 0xd4, 0xae, 0xb9, 0xb5, 0xa2, 0x32, 0x08, 0x75, 0x0b, 0xff, 0x61, - 0x01, 0x29, 0xfe, 0x22, 0xeb, 0x28, 0xa9, 0x8e, 0x3a, 0x0b, 0x48, 0x6e, 0x30, 0x08, 0xad, 0x29, - 0x6e, 0x1e, 0x1b, 0xe5, 0x90, 0x45, 0x07, 0xac, 0x7e, 0x8a, 0xab, 0x31, 0xcd, 0xde, 0xa4, 0x8c, - 0x2b, 0x6e, 0xa1, 0x74, 0x0b, 0x37, 0x82, 0x44, 0x90, 0xa7, 0x7b, 0x3f, 0xb9, 0xf5, 0x21, 0x36, - 0xca, 0x0a, 0xdd, 0xab, 0xf5, 0xdc, 0xc5, 0xca, 0x44, 0xcb, 0x95, 0x89, 0xde, 0x57, 0x26, 0x7a, - 0x59, 0x9b, 0xda, 0x72, 0x6d, 0x6a, 0xaf, 0x6b, 0x53, 0x7b, 0xe8, 0x46, 0x4c, 0xc6, 0x93, 0xc0, - 0x26, 0x62, 0xe4, 0x7c, 0xb3, 0x4f, 0xd3, 0x8e, 0x33, 0xdb, 0x5b, 0x2a, 0x39, 0x4f, 0x29, 0x04, - 0x55, 0xb5, 0x19, 0x9d, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x49, 0x76, 0xae, 0x91, 0x87, 0x02, - 0x00, 0x00, + // 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, +} + +func (m *HeaderSignerEntry) 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 *HeaderSignerEntry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *HeaderSignerEntry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Height != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x18 + } + if len(m.ClientId) > 0 { + i -= len(m.ClientId) + copy(dAtA[i:], m.ClientId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ClientId))) + i-- + dAtA[i] = 0x12 + } + if len(m.SequencerAddress) > 0 { + i -= len(m.SequencerAddress) + copy(dAtA[i:], m.SequencerAddress) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.SequencerAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -247,10 +288,10 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.ConsensusStateSigners) > 0 { - for iNdEx := len(m.ConsensusStateSigners) - 1; iNdEx >= 0; iNdEx-- { + if len(m.HeaderSigners) > 0 { + for iNdEx := len(m.HeaderSigners) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.ConsensusStateSigners[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.HeaderSigners[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -258,7 +299,7 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a } } if len(m.CanonicalClients) > 0 { @@ -315,48 +356,6 @@ func (m *CanonicalClient) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *ConsensusStateSigner) 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 *ConsensusStateSigner) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *ConsensusStateSigner) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.BlockValHash) > 0 { - i -= len(m.BlockValHash) - copy(dAtA[i:], m.BlockValHash) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.BlockValHash))) - i-- - dAtA[i] = 0x1a - } - if m.Height != 0 { - i = encodeVarintGenesis(dAtA, i, uint64(m.Height)) - i-- - dAtA[i] = 0x10 - } - if len(m.IbcClientId) > 0 { - i -= len(m.IbcClientId) - copy(dAtA[i:], m.IbcClientId) - i = encodeVarintGenesis(dAtA, i, uint64(len(m.IbcClientId))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { offset -= sovGenesis(v) base := offset @@ -368,6 +367,26 @@ func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { dAtA[offset] = uint8(v) return base } +func (m *HeaderSignerEntry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SequencerAddress) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.ClientId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.Height != 0 { + n += 1 + sovGenesis(uint64(m.Height)) + } + return n +} + func (m *GenesisState) Size() (n int) { if m == nil { return 0 @@ -380,8 +399,8 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } - if len(m.ConsensusStateSigners) > 0 { - for _, e := range m.ConsensusStateSigners { + if len(m.HeaderSigners) > 0 { + for _, e := range m.HeaderSigners { l = e.Size() n += 1 + l + sovGenesis(uint64(l)) } @@ -406,33 +425,13 @@ func (m *CanonicalClient) Size() (n int) { return n } -func (m *ConsensusStateSigner) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.IbcClientId) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - if m.Height != 0 { - n += 1 + sovGenesis(uint64(m.Height)) - } - l = len(m.BlockValHash) - if l > 0 { - n += 1 + l + sovGenesis(uint64(l)) - } - return n -} - func sovGenesis(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } func sozGenesis(x uint64) (n int) { return sovGenesis(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *GenesisState) Unmarshal(dAtA []byte) error { +func (m *HeaderSignerEntry) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -455,17 +454,17 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") + return fmt.Errorf("proto: HeaderSignerEntry: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: HeaderSignerEntry: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CanonicalClients", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field SequencerAddress", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -475,31 +474,29 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.CanonicalClients = append(m.CanonicalClients, CanonicalClient{}) - if err := m.CanonicalClients[len(m.CanonicalClients)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.SequencerAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ConsensusStateSigners", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ClientId", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -509,26 +506,43 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.ConsensusStateSigners = append(m.ConsensusStateSigners, ConsensusStateSigner{}) - if err := m.ConsensusStateSigners[len(m.ConsensusStateSigners)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.ClientId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) @@ -550,7 +564,7 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { } return nil } -func (m *CanonicalClient) Unmarshal(dAtA []byte) error { +func (m *GenesisState) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -573,17 +587,17 @@ func (m *CanonicalClient) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: CanonicalClient: wiretype end group for non-group") + return fmt.Errorf("proto: GenesisState: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: CanonicalClient: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: GenesisState: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RollappId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field CanonicalClients", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -593,29 +607,31 @@ func (m *CanonicalClient) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.RollappId = string(dAtA[iNdEx:postIndex]) + m.CanonicalClients = append(m.CanonicalClients, CanonicalClient{}) + if err := m.CanonicalClients[len(m.CanonicalClients)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 2: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IbcClientId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field HeaderSigners", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -625,23 +641,25 @@ func (m *CanonicalClient) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.IbcClientId = string(dAtA[iNdEx:postIndex]) + m.HeaderSigners = append(m.HeaderSigners, HeaderSignerEntry{}) + if err := m.HeaderSigners[len(m.HeaderSigners)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex default: iNdEx = preIndex @@ -664,7 +682,7 @@ func (m *CanonicalClient) Unmarshal(dAtA []byte) error { } return nil } -func (m *ConsensusStateSigner) Unmarshal(dAtA []byte) error { +func (m *CanonicalClient) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -687,15 +705,15 @@ func (m *ConsensusStateSigner) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: ConsensusStateSigner: wiretype end group for non-group") + return fmt.Errorf("proto: CanonicalClient: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: ConsensusStateSigner: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: CanonicalClient: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field IbcClientId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field RollappId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -723,30 +741,11 @@ func (m *ConsensusStateSigner) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.IbcClientId = string(dAtA[iNdEx:postIndex]) + m.RollappId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) - } - m.Height = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Height |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BlockValHash", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field IbcClientId", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -774,7 +773,7 @@ func (m *ConsensusStateSigner) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.BlockValHash = string(dAtA[iNdEx:postIndex]) + m.IbcClientId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/x/lightclient/types/genesis_test.go b/x/lightclient/types/genesis_test.go index a0c3a9317..e5711c968 100644 --- a/x/lightclient/types/genesis_test.go +++ b/x/lightclient/types/genesis_test.go @@ -20,10 +20,6 @@ func TestGenesisValidate(t *testing.T) { {RollappId: "rollapp-1", IbcClientId: "client-1"}, {RollappId: "rollapp-2", IbcClientId: "client-2"}, }, - ConsensusStateSigners: []types.ConsensusStateSigner{ - {IbcClientId: "client-1", Height: 1, BlockValHash: "signer-1"}, - {IbcClientId: "client-1", Height: 2, BlockValHash: "signer-1"}, - }, }, valid: true, }, @@ -45,24 +41,7 @@ func TestGenesisValidate(t *testing.T) { }, valid: false, }, - { - name: "invalid height", - g: types.GenesisState{ - ConsensusStateSigners: []types.ConsensusStateSigner{ - {IbcClientId: "client-1", Height: 0, BlockValHash: "signer-1"}, - }, - }, - valid: false, - }, - { - name: "invalid blockvalhash", - g: types.GenesisState{ - ConsensusStateSigners: []types.ConsensusStateSigner{ - {IbcClientId: "client-1", Height: 1, BlockValHash: ""}, - }, - }, - valid: false, - }, + { name: "empty", g: types.GenesisState{}, diff --git a/x/lightclient/types/keys.go b/x/lightclient/types/keys.go index 0b654aa36..7cde722ff 100644 --- a/x/lightclient/types/keys.go +++ b/x/lightclient/types/keys.go @@ -1,10 +1,6 @@ package types -import ( - "bytes" - - sdk "github.com/cosmos/cosmos-sdk/types" -) +import "cosmossdk.io/collections" const ( // ModuleName defines the module name @@ -14,15 +10,12 @@ const ( StoreKey = ModuleName ) -const ( - keySeparator = "/" -) - var ( - RollappClientKey = []byte{0x01} - ConsensusStateValhashKey = []byte{0x03} - canonicalClientKey = []byte{0x04} - hardForkKey = []byte{0x05} + RollappClientKey = []byte{0x01} + canonicalClientKey = []byte{0x04} + hardForkKey = []byte{0x05} + HeaderSignersPrefixKey = collections.NewPrefix("headerSigners/") + ClientHeightToSigner = collections.NewPrefix("clientHeightToSigner/") ) func GetRollappClientKey(rollappId string) []byte { @@ -31,28 +24,12 @@ func GetRollappClientKey(rollappId string) []byte { return key } -func ConsensusStateValhashKeyByClientID(clientID string, height uint64) []byte { - key := ConsensusStateValhashKey - key = append(key, []byte(clientID)...) - key = append(key, keySeparator...) - key = append(key, sdk.Uint64ToBigEndian(height)...) - return key -} - func CanonicalClientKey(clientID string) []byte { key := canonicalClientKey key = append(key, []byte(clientID)...) return key } -func ParseConsensusStateValhashKey(key []byte) (clientID string, height uint64) { - key = key[len(ConsensusStateValhashKey):] - parts := bytes.Split(key, []byte(keySeparator)) - clientID = string(parts[0]) - height = sdk.BigEndianToUint64(parts[1]) - return -} - func HardForkKey(rollappID string) []byte { key := hardForkKey key = append(key, []byte(rollappID)...) diff --git a/x/lightclient/types/params.go b/x/lightclient/types/params.go index be9015ac4..e69fb338c 100644 --- a/x/lightclient/types/params.go +++ b/x/lightclient/types/params.go @@ -11,11 +11,14 @@ import ( commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ics23 "github.com/cosmos/ics23/go" - sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) func DefaultExpectedCanonicalClientParams() ibctm.ClientState { - return ExpectedCanonicalClientParams(sequencertypes.DefaultUnbondingTime) + // Note: need to be very sure that this is the same value that the + // relayer gets when it queries the rollapp (x/sequencers) + unbondingTime := time.Hour * 24 * 7 * 3 + + return ExpectedCanonicalClientParams(unbondingTime) } const ( diff --git a/x/lightclient/types/state.go b/x/lightclient/types/state.go index 2490704fd..bf6b5af52 100644 --- a/x/lightclient/types/state.go +++ b/x/lightclient/types/state.go @@ -5,10 +5,9 @@ import ( "errors" errorsmod "cosmossdk.io/errors" - abci "github.com/cometbft/cometbft/abci/types" - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - cmttypes "github.com/cometbft/cometbft/types" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) @@ -24,11 +23,11 @@ func CheckCompatibility(ibcState ibctm.ConsensusState, raState RollappState) err return errorsmod.Wrap(ErrStateRootsMismatch, "block descriptor state root does not match tendermint header app hash") } // Check if the nextValidatorHash matches for the sequencer for h+1 block descriptor - nextValHashFromStateInfo, err := GetValHashForSequencer(raState.NextBlockSequencer) + hash, err := raState.NextBlockSequencer.ValsetHash() if err != nil { - return errors.Join(ErrValidatorHashMismatch, err) + return errors.Join(err, gerrc.ErrInternal.Wrap("val set hash")) } - if !bytes.Equal(ibcState.NextValidatorsHash, nextValHashFromStateInfo) { + if !bytes.Equal(ibcState.NextValidatorsHash, hash) { return errorsmod.Wrap(ErrValidatorHashMismatch, "cons state next validator hash does not match the state info hash for sequencer for h+1") } if !raState.BlockDescriptor.Timestamp.IsZero() && !ibcState.Timestamp.Equal(raState.BlockDescriptor.Timestamp) { @@ -37,24 +36,7 @@ func CheckCompatibility(ibcState ibctm.ConsensusState, raState RollappState) err return nil } -// GetValHashForSequencer creates a dummy tendermint validatorset to -// calculate the nextValHash for the sequencer and returns it -func GetValHashForSequencer(sequencerTmPubKey tmprotocrypto.PublicKey) ([]byte, error) { - var nextValSet cmttypes.ValidatorSet - updates, err := cmttypes.PB2TM.ValidatorUpdates([]abci.ValidatorUpdate{{Power: 1, PubKey: sequencerTmPubKey}}) - if err != nil { - return nil, err - } - err = nextValSet.UpdateWithChangeSet(updates) - if err != nil { - return nil, err - } - return nextValSet.Hash(), nil -} - type RollappState struct { - // BlockDescriptor is the block descriptor for the required height - BlockDescriptor rollapptypes.BlockDescriptor - // NextBlockSequencer is the tendermint pubkey of the sequencer who submitted the block descriptor for the next height (h+1) - NextBlockSequencer tmprotocrypto.PublicKey + BlockDescriptor rollapptypes.BlockDescriptor + NextBlockSequencer sequencertypes.Sequencer } diff --git a/x/lightclient/types/state_test.go b/x/lightclient/types/state_test.go index 9c4cefa83..f797c90be 100644 --- a/x/lightclient/types/state_test.go +++ b/x/lightclient/types/state_test.go @@ -4,32 +4,32 @@ import ( "testing" "time" - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" commitmenttypes "github.com/cosmos/ibc-go/v7/modules/core/23-commitment/types" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" "github.com/dymensionxyz/dymension/v3/x/lightclient/types" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" "github.com/stretchr/testify/require" ) var ( sequencerPubKey = ed25519.GenPrivKey().PubKey() - tmPk, _ = cryptocodec.ToTmProtoPublicKey(sequencerPubKey) - valHash, _ = types.GetValHashForSequencer(tmPk) timestamp = time.Unix(1724392989, 0) + seq = sequencertypes.NewTestSequencer(sequencerPubKey) + validIBCState = ibctm.ConsensusState{ Root: commitmenttypes.NewMerkleRoot([]byte("root")), Timestamp: timestamp, - NextValidatorsHash: valHash, + NextValidatorsHash: seq.MustValsetHash(), } validRollappState = types.RollappState{ BlockDescriptor: rollapptypes.BlockDescriptor{ StateRoot: []byte("root"), Timestamp: timestamp, }, - NextBlockSequencer: tmPk, + NextBlockSequencer: seq, } ) diff --git a/x/rollapp/genesis.go b/x/rollapp/genesis.go index a30e0d4f0..0aa090ae3 100644 --- a/x/rollapp/genesis.go +++ b/x/rollapp/genesis.go @@ -44,6 +44,27 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) } } } + // Set all the sequencer height pairs + for _, elem := range genState.SequencerHeightPairs { + err := k.SaveSequencerHeight(ctx, elem.Sequencer, elem.Height) + if err != nil { + panic(err) + } + } + // Set all the vulnerable DRS versions + for _, elem := range genState.VulnerableDrsVersions { + err := k.SetVulnerableDRSVersion(ctx, elem) + if err != nil { + panic(err) + } + } + + for _, elem := range genState.SequencerHeightPairs { + err := k.SaveSequencerHeight(ctx, elem.Sequencer, elem.Height) + if err != nil { + panic(err) + } + } k.SetParams(ctx, genState.Params) } @@ -79,5 +100,17 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { } genesis.RegisteredDenoms = registeredRollappDenoms + var err error + genesis.SequencerHeightPairs, err = k.AllSequencerHeightPairs(ctx) + if err != nil { + panic(err) + } + + drsVersions, err := k.GetAllVulnerableDRSVersions(ctx) + if err != nil { + panic(err) + } + genesis.VulnerableDrsVersions = drsVersions + return genesis } diff --git a/x/rollapp/genesis_test.go b/x/rollapp/genesis_test.go index 1f931a42e..7511f8536 100644 --- a/x/rollapp/genesis_test.go +++ b/x/rollapp/genesis_test.go @@ -77,6 +77,30 @@ func TestInitExportGenesis(t *testing.T) { RollappId: rollappID2, }, }, + SequencerHeightPairs: []types.SequencerHeightPair{ + { + Sequencer: "seq1", + Height: 0, + }, + { + Sequencer: "seq2", + Height: 1, + }, + { + Sequencer: "seq3", + Height: 2, + }, + }, + LivenessEvents: []types.LivenessEvent{ + { + RollappId: rollappID2, + HubHeight: 42, + }, + { + RollappId: rollappID1, + HubHeight: 44, + }, + }, } k, ctx := keepertest.RollappKeeper(t) diff --git a/x/rollapp/genesisbridge/ibc_module.go b/x/rollapp/genesisbridge/ibc_module.go index 3ad69b939..20e9d5814 100644 --- a/x/rollapp/genesisbridge/ibc_module.go +++ b/x/rollapp/genesisbridge/ibc_module.go @@ -114,7 +114,7 @@ func (w IBCModule) OnRecvPacket( } // validate genesis info against the expected data set on the rollapp - err = w.ValidateGenesisBridge(ctx, ra, genesisBridgeData.GenesisInfo) + err = w.ValidateGenesisBridge(ra, genesisBridgeData.GenesisInfo) if err != nil { l.Error("Validate genesis info.", "err", err) return uevent.NewErrorAcknowledgement(ctx, errorsmod.Wrap(err, "validate genesis info")) @@ -151,13 +151,12 @@ func (w IBCModule) OnRecvPacket( return successAck } -func (w IBCModule) ValidateGenesisBridge(ctx sdk.Context, ra *types.Rollapp, data GenesisBridgeInfo) error { +func (w IBCModule) ValidateGenesisBridge(ra *types.Rollapp, data GenesisBridgeInfo) error { raInfo := ra.GenesisInfo - // TODO: validate genesis checksum - // if data.GenesisChecksum != raInfo.GenesisChecksum { - // return fmt.Errorf("genesis checksum mismatch: expected: %v, got: %v", raInfo.GenesisChecksum, data.GenesisChecksum) - // } + if data.GenesisChecksum != raInfo.GenesisChecksum { + return fmt.Errorf("genesis checksum mismatch: expected: %v, got: %v", raInfo.GenesisChecksum, data.GenesisChecksum) + } if data.Bech32Prefix != raInfo.Bech32Prefix { return fmt.Errorf("bech32 prefix mismatch: expected: %v, got: %v", raInfo.Bech32Prefix, data.Bech32Prefix) diff --git a/x/rollapp/keeper/block_height_to_finalization_queue.go b/x/rollapp/keeper/block_height_to_finalization_queue.go index c060721bf..bb6dd7c85 100644 --- a/x/rollapp/keeper/block_height_to_finalization_queue.go +++ b/x/rollapp/keeper/block_height_to_finalization_queue.go @@ -4,14 +4,55 @@ import ( "fmt" "slices" + "cosmossdk.io/collections" + errorsmod "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" + sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" "github.com/osmosis-labs/osmosis/v15/osmoutils" common "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) +func (k Keeper) CanUnbond(ctx sdk.Context, seq sequencertypes.Sequencer) error { + rng := collections.NewPrefixedPairRange[string, uint64](seq.Address) + return k.seqToUnfinalizedHeight.Walk(ctx, rng, func(key collections.Pair[string, uint64]) (stop bool, err error) { + // we found one! + return true, errorsmod.Wrapf(sequencertypes.ErrUnbondNotAllowed, "unfinalized height: h: %d", key.K2()) + }) +} + +// 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) + if err := k.seqToUnfinalizedHeight.Clear(ctx, rng); err != nil { + return errorsmod.Wrapf(err, "seq: %s", seqAddr) + } + } + return nil +} + +func (k Keeper) SaveSequencerHeight(ctx sdk.Context, seqAddr string, height uint64) error { + return k.seqToUnfinalizedHeight.Set(ctx, collections.Join(seqAddr, height)) +} + +func (k Keeper) DelSequencerHeight(ctx sdk.Context, seqAddr string, height uint64) error { + return k.seqToUnfinalizedHeight.Remove(ctx, collections.Join(seqAddr, height)) +} + +func (k Keeper) AllSequencerHeightPairs(ctx sdk.Context) ([]types.SequencerHeightPair, error) { + ret := make([]types.SequencerHeightPair, 0) + err := k.seqToUnfinalizedHeight.Walk(ctx, nil, func(key collections.Pair[string, uint64]) (stop bool, err error) { + ret = append(ret, types.SequencerHeightPair{Sequencer: key.K1(), Height: key.K2()}) + return false, nil + }) + return ret, err +} + // FinalizeRollappStates is called every block to finalize states when their dispute period over. func (k Keeper) FinalizeRollappStates(ctx sdk.Context) { if uint64(ctx.BlockHeight()) < k.DisputePeriodInBlocks(ctx) { @@ -78,6 +119,13 @@ func (k *Keeper) finalizePendingState(ctx sdk.Context, stateInfoIndex types.Stat k.SetStateInfo(ctx, stateInfo) // update the LatestStateInfoIndex of the rollapp k.SetLatestFinalizedStateIndex(ctx, stateInfoIndex) + + for _, bd := range stateInfo.BDs.BD { + if err := k.DelSequencerHeight(ctx, stateInfo.Sequencer, bd.Height); err != nil { + return errorsmod.Wrap(err, "del sequencer height") + } + } + // call the after-update-state hook err := k.GetHooks().AfterStateFinalized(ctx, stateInfoIndex.RollappId, &stateInfo) if err != nil { 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 87ee4d81e..178c31cd4 100644 --- a/x/rollapp/keeper/block_height_to_finalization_queue_test.go +++ b/x/rollapp/keeper/block_height_to_finalization_queue_test.go @@ -8,6 +8,7 @@ import ( "testing" "unsafe" + errorsmod "cosmossdk.io/errors" abci "github.com/cometbft/cometbft/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -16,6 +17,7 @@ import ( "github.com/dymensionxyz/dymension/v3/testutil/nullify" "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) // Prevent strconv unused error @@ -654,3 +656,34 @@ func (m mockRollappHooks) AfterStateFinalized(_ sdk.Context, _ string, stateInfo } return } + +func TestUnbondConditionFlow(t *testing.T) { + k, ctx := keepertest.RollappKeeper(t) + + seq := keepertest.Alice + + err := k.CanUnbond(ctx, seq) + require.NoError(t, err) + + for h := range 10 { + err := k.SaveSequencerHeight(ctx, seq.Address, uint64(h)) + require.NoError(t, err) + } + + 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) + + err = k.CanUnbond(ctx, seq) + require.True(t, errorsmod.IsOf(err, sequencertypes.ErrUnbondNotAllowed)) + + for h := range 7 { + err := k.DelSequencerHeight(ctx, seq.Address, uint64(h)) + require.NoError(t, err) + } + + err = k.CanUnbond(ctx, seq) + require.NoError(t, err) +} diff --git a/x/rollapp/keeper/expected_keepers.go b/x/rollapp/keeper/expected_keepers.go index 3982d543c..1da36d722 100644 --- a/x/rollapp/keeper/expected_keepers.go +++ b/x/rollapp/keeper/expected_keepers.go @@ -1,8 +1,11 @@ package keeper import ( + tmbytes "github.com/cometbft/cometbft/libs/bytes" sdk "github.com/cosmos/cosmos-sdk/types" + transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) @@ -21,9 +24,8 @@ type ChannelKeeper interface { type SequencerKeeper interface { SlashLiveness(ctx sdk.Context, rollappID string) error - JailLiveness(ctx sdk.Context, rollappID string) error - JailByAddr(ctx sdk.Context, seqAddr string) error - GetProposer(ctx sdk.Context, rollappId string) (val types.Sequencer, found bool) + PunishSequencer(ctx sdk.Context, seqAddr string) error + GetProposer(ctx sdk.Context, rollappId string) types.Sequencer } // BankKeeper defines the expected interface needed to retrieve account balances. @@ -35,3 +37,7 @@ type BankKeeper interface { type CanonicalLightClientKeeper interface { GetRollappForClientID(ctx sdk.Context, clientID string) (string, bool) } + +type TransferKeeper interface { + GetDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) (transfertypes.DenomTrace, bool) +} diff --git a/x/rollapp/keeper/fraud_proposal.go b/x/rollapp/keeper/fraud_proposal.go index 6e9e4b4d2..6c6dabe8f 100644 --- a/x/rollapp/keeper/fraud_proposal.go +++ b/x/rollapp/keeper/fraud_proposal.go @@ -38,6 +38,7 @@ func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappF } // validate the fraud height is already committed + // FIXME: allow the latest height +1 as well? sinfo, found := k.GetLatestStateInfo(ctx, msg.RollappId) if !found || sinfo.GetLatestHeight() < msg.FraudHeight { return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height not committed") @@ -49,14 +50,15 @@ func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappF return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height already finalized") } - // jail the sequencer if needed + // punish the sequencer if needed if msg.SlashSequencerAddress != "" { - err := k.sequencerKeeper.JailByAddr(ctx, msg.SlashSequencerAddress) + err := k.sequencerKeeper.PunishSequencer(ctx, msg.SlashSequencerAddress) if err != nil { return nil, errorsmod.Wrap(err, "jail sequencer") } } + // FIXME: remove hard fork bool from the msg err := k.HardFork(ctx, msg.RollappId, msg.FraudHeight) if err != nil { return nil, errorsmod.Wrap(err, "hard fork") diff --git a/x/rollapp/keeper/grpc_query_state_info.go b/x/rollapp/keeper/grpc_query_state_info.go index e4e3514b6..81143488e 100644 --- a/x/rollapp/keeper/grpc_query_state_info.go +++ b/x/rollapp/keeper/grpc_query_state_info.go @@ -94,5 +94,5 @@ func (k Keeper) FindStateInfoByHeight(ctx sdk.Context, rollappId string, height startInfoIndex = midIndex + 1 } } - return nil, errorsmod.Wrapf(types.ErrStateNotExists, "StateInfo wasn't found for rollappId=%s, height=%d", rollappId, height) + return nil, errorsmod.Wrapf(gerrc.ErrNotFound, "StateInfo wasn't found for rollappId=%s, height=%d", rollappId, height) } diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index 608e31c33..ec6d1174c 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -75,12 +75,22 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig return 0, errorsmod.Wrap(err, "update last state info") } - // clear state info + // clear pending states post the fraud height revertedStatesCount := 0 // Counter for reverted state updates lastIdx, _ := k.GetLatestStateInfoIndex(ctx, rollappID) for i := lastStateIdxToKeep + 1; i <= lastIdx.Index; i++ { + sInfo := k.MustGetStateInfo(ctx, rollappID, i) + + // clear the sequencer heights + for _, bd := range sInfo.BDs.BD { + if err := k.DelSequencerHeight(ctx, sInfo.Sequencer, bd.Height); err != nil { + return 0, errorsmod.Wrap(err, "del sequencer height") + } + } + // clear the state info k.RemoveStateInfo(ctx, rollappID, i) revertedStatesCount++ // Increment the counter + } k.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ RollappId: rollappID, @@ -127,13 +137,16 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig } ctx.Logger().Info(fmt.Sprintf("Reverted state updates for rollapp: %s, count: %d", rollappID, revertedStatesCount)) - return fraudHeight - 1, nil } // UpdateLastStateInfo truncates the state info to the last valid block before the fraud height. // It returns the index of the last state info to keep. func (k Keeper) UpdateLastStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) (uint64, error) { + if fraudHeight < stateInfo.StartHeight { + return 0, errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "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 @@ -141,15 +154,13 @@ func (k Keeper) UpdateLastStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, if !ok { return 0, errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "no state info found for rollapp: %s", stateInfo.StateInfoIndex.RollappId) } - } else if stateInfo.GetLatestHeight() > fraudHeight { + } 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 - } else { - return 0, errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "state info start height is greater than fraud height") } // Update the state info in the keeper diff --git a/x/rollapp/keeper/hard_fork_test.go b/x/rollapp/keeper/hard_fork_test.go index c3e6d0ba0..2ca4a54aa 100644 --- a/x/rollapp/keeper/hard_fork_test.go +++ b/x/rollapp/keeper/hard_fork_test.go @@ -4,8 +4,6 @@ import ( common "github.com/dymensionxyz/dymension/v3/x/common/types" ) -// FIXME: Liveness???? - // TestHardFork - Test the HardFork function // - deleted states // - pending queue is cleared up to the fraud height @@ -27,10 +25,11 @@ func (suite *RollappTestSuite) TestHardFork() { {"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}, - {"first batch not committed yet", 0, 0, 10, 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}, } diff --git a/x/rollapp/keeper/invariants.go b/x/rollapp/keeper/invariants.go index 402b1bd32..dbf0e34a6 100644 --- a/x/rollapp/keeper/invariants.go +++ b/x/rollapp/keeper/invariants.go @@ -266,7 +266,7 @@ func LivenessEventInvariant(k Keeper) sdk.Invariant { ) rollapps := k.GetAllRollapps(ctx) for _, ra := range rollapps { - if !ra.LastStateUpdateHeightIsSet() { + if ra.LivenessEventHeight == 0 { continue } events := k.GetLivenessEvents(ctx, &ra.LivenessEventHeight) diff --git a/x/rollapp/keeper/keeper.go b/x/rollapp/keeper/keeper.go index dc03062cd..e4e1663b1 100644 --- a/x/rollapp/keeper/keeper.go +++ b/x/rollapp/keeper/keeper.go @@ -28,11 +28,13 @@ type Keeper struct { channelKeeper ChannelKeeper sequencerKeeper SequencerKeeper bankKeeper BankKeeper + transferKeeper TransferKeeper vulnerableDRSVersions collections.KeySet[uint32] registeredRollappDenoms collections.KeySet[collections.Pair[string, string]] - finalizePending func(ctx sdk.Context, stateInfoIndex types.StateInfoIndex) error + finalizePending func(ctx sdk.Context, stateInfoIndex types.StateInfoIndex) error + seqToUnfinalizedHeight collections.KeySet[collections.Pair[string, uint64]] } func NewKeeper( @@ -44,6 +46,7 @@ func NewKeeper( ibcclientKeeper IBCClientKeeper, sequencerKeeper SequencerKeeper, bankKeeper BankKeeper, + transferKeeper TransferKeeper, authority string, canonicalClientKeeper CanonicalLightClientKeeper, ) *Keeper { @@ -56,6 +59,9 @@ func NewKeeper( panic(fmt.Errorf("invalid x/rollapp authority address: %w", err)) } + service := collcompat.NewKVStoreService(storeKey) + sb := collections.NewSchemaBuilder(service) + k := &Keeper{ cdc: cdc, storeKey: storeKey, @@ -67,8 +73,9 @@ func NewKeeper( ibcClientKeeper: ibcclientKeeper, sequencerKeeper: sequencerKeeper, bankKeeper: bankKeeper, + transferKeeper: transferKeeper, vulnerableDRSVersions: collections.NewKeySet( - collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey)), + sb, collections.NewPrefix(types.VulnerableDRSVersionsKeyPrefix), "vulnerable_drs_versions", collections.Uint32Key, @@ -81,6 +88,12 @@ func NewKeeper( ), finalizePending: nil, canonicalClientKeeper: canonicalClientKeeper, + seqToUnfinalizedHeight: collections.NewKeySet( + sb, + types.SeqToUnfinalizedHeightKeyPrefix, + "seq_to_unfinalized_height", + collections.PairKeyCodec(collections.StringKey, collections.Uint64Key), + ), } k.SetFinalizePendingFn(k.finalizePendingState) return k diff --git a/x/rollapp/keeper/liveness.go b/x/rollapp/keeper/liveness.go index e61e1ffc4..c1f2146aa 100644 --- a/x/rollapp/keeper/liveness.go +++ b/x/rollapp/keeper/liveness.go @@ -14,18 +14,16 @@ It will trigger slash/jail operations through the x/sequencers module, at interv See ADR for more info https://www.notion.so/dymension/ADR-x-Sequencer-Liveness-Slash-Phase-1-5131b4d557e34f4498855831f439d218 */ -// NextSlashOrJailHeight returns the next height on the HUB to slash or jail the rollapp +// NextSlashHeight returns the next height on the HUB to slash or jail the rollapp // It will respect all parameters passed in. // Assumes that if current hub height is already a slash height, then to schedule for the next one. -func NextSlashOrJailHeight( +func NextSlashHeight( blocksSlashNoUpdate uint64, // time until first slash if not updating blocksSlashInterval uint64, // gap between slash if still not updating - blocksJail uint64, // time until jail if not updating heightHub int64, // current height on the hub heightLastRollappUpdate int64, // when was the rollapp last updated ) ( heightEvent int64, // hub height to schedule event - isJail bool, // is it a jail event? (false -> slash) ) { // how long has the rollapp been down ? down := uint64(heightHub - heightLastRollappUpdate) @@ -36,7 +34,6 @@ func NextSlashOrJailHeight( interval += ((down-blocksSlashNoUpdate)/blocksSlashInterval + 1) * blocksSlashInterval } heightEvent = heightLastRollappUpdate + int64(interval) - isJail = blocksJail <= interval return } @@ -62,45 +59,37 @@ func (k Keeper) CheckLiveness(ctx sdk.Context) { // HandleLivenessEvent will slash or jail and then schedule a new event in the future. func (k Keeper) HandleLivenessEvent(ctx sdk.Context, e types.LivenessEvent) error { - if e.IsJail { - err := k.sequencerKeeper.JailLiveness(ctx, e.RollappId) - if err != nil { - return errorsmod.Wrap(err, "jail liveness") - } - } else { - err := k.sequencerKeeper.SlashLiveness(ctx, e.RollappId) - if err != nil { - return errorsmod.Wrap(err, "slash liveness") - } + err := k.sequencerKeeper.SlashLiveness(ctx, e.RollappId) + if err != nil { + return errorsmod.Wrap(err, "slash liveness") } ra := k.MustGetRollapp(ctx, e.RollappId) - k.RescheduleLivenessEvent(ctx, &ra) + k.ScheduleLivenessEvent(ctx, &ra) + k.SetRollapp(ctx, ra) return nil } -// IndicateLiveness will reschedule pending liveness events to a later block height. -// Modifies the passed-in rollapp object. func (k Keeper) IndicateLiveness(ctx sdk.Context, ra *types.Rollapp) { - ra.LastStateUpdateHeight = ctx.BlockHeight() - k.RescheduleLivenessEvent(ctx, ra) + k.ResetLivenessClock(ctx, ra) + k.ScheduleLivenessEvent(ctx, ra) } -func (k Keeper) RescheduleLivenessEvent(ctx sdk.Context, ra *types.Rollapp) { +// ResetLivenessClock will reschedule pending liveness events to a later block height. +// Modifies the passed-in rollapp object. +func (k Keeper) ResetLivenessClock(ctx sdk.Context, ra *types.Rollapp) { k.DelLivenessEvents(ctx, ra.LivenessEventHeight, ra.RollappId) - k.ScheduleLivenessEvent(ctx, ra) - k.SetRollapp(ctx, *ra) + ra.LastStateUpdateHeight = ctx.BlockHeight() + ra.LivenessEventHeight = 0 } // ScheduleLivenessEvent schedules a new liveness event. Assumes an event does not -// already exist for the rollapp. Assumes the rollapp has had at least one state update already. -// Modifies the passed-in rollapp object. +// already exist for the rollapp. Modifies the passed-in rollapp object. func (k Keeper) ScheduleLivenessEvent(ctx sdk.Context, ra *types.Rollapp) { params := k.GetParams(ctx) - nextH, isJail := NextSlashOrJailHeight( + nextH := NextSlashHeight( params.LivenessSlashBlocks, params.LivenessSlashInterval, - params.LivenessJailBlocks, ctx.BlockHeight(), ra.LastStateUpdateHeight, ) @@ -108,7 +97,6 @@ func (k Keeper) ScheduleLivenessEvent(ctx sdk.Context, ra *types.Rollapp) { k.PutLivenessEvent(ctx, types.LivenessEvent{ RollappId: ra.RollappId, HubHeight: nextH, - IsJail: isJail, }) } @@ -143,18 +131,10 @@ func (k Keeper) PutLivenessEvent(ctx sdk.Context, e types.LivenessEvent) { // DelLivenessEvents deletes all liveness events for the rollapp from the queue func (k Keeper) DelLivenessEvents(ctx sdk.Context, height int64, rollappID string) { - for _, jail := range []bool{true, false} { - k.DelLivenessEvent(ctx, types.LivenessEvent{ - RollappId: rollappID, - HubHeight: height, - IsJail: jail, - }) - } -} - -// DelLivenessEvent deletes all liveness events for the rollapp from the queue -func (k Keeper) DelLivenessEvent(ctx sdk.Context, e types.LivenessEvent) { store := ctx.KVStore(k.storeKey) - key := types.LivenessEventQueueKey(e) + key := types.LivenessEventQueueKey(types.LivenessEvent{ + RollappId: rollappID, + HubHeight: height, + }) store.Delete(key) } diff --git a/x/rollapp/keeper/liveness_test.go b/x/rollapp/keeper/liveness_test.go index 7c906e187..cfcc53419 100644 --- a/x/rollapp/keeper/liveness_test.go +++ b/x/rollapp/keeper/liveness_test.go @@ -19,40 +19,36 @@ import ( func TestLivenessArithmetic(t *testing.T) { t.Run("simple case", func(t *testing.T) { - hEvent, _ := keeper.NextSlashOrJailHeight( + hEvent := keeper.NextSlashHeight( 8, 4, - 1000, 0, 0, ) require.Equal(t, 8, int(hEvent)) }) t.Run("almost at the interval", func(t *testing.T) { - hEvent, _ := keeper.NextSlashOrJailHeight( + hEvent := keeper.NextSlashHeight( 8, 4, - 1000, 7, 0, ) require.Equal(t, 8, int(hEvent)) }) t.Run("do not schedule for next height", func(t *testing.T) { - hEvent, _ := keeper.NextSlashOrJailHeight( + hEvent := keeper.NextSlashHeight( 8, 4, - 1000, 8, 0, ) require.Equal(t, 12, int(hEvent)) }) t.Run("do not schedule for next height", func(t *testing.T) { - hEvent, _ := keeper.NextSlashOrJailHeight( + hEvent := keeper.NextSlashHeight( 8, 4, - 1000, 12, 0, ) @@ -67,7 +63,6 @@ func TestLivenessEventsStorage(t *testing.T) { rollapps := rapid.StringMatching("^[a-zA-Z0-9]{1,10}$") heights := rapid.Int64Range(0, 10) - isJail := rapid.Bool() rapid.Check(t, func(r *rapid.T) { k, ctx := keepertest.RollappKeeper(t) model := make(map[string]types.LivenessEvent) // model actual sdk storage @@ -79,7 +74,6 @@ func TestLivenessEventsStorage(t *testing.T) { e := types.LivenessEvent{ RollappId: rollapps.Draw(r, "rollapp"), HubHeight: heights.Draw(r, "h"), - IsJail: isJail.Draw(r, "jail"), } k.PutLivenessEvent(ctx, e) model[modelKey(e)] = e @@ -91,7 +85,6 @@ func TestLivenessEventsStorage(t *testing.T) { } k.DelLivenessEvents(ctx, e.HubHeight, e.RollappId) delete(model, modelKey(e)) - e.IsJail = true delete(model, modelKey(e)) }, "iterHeight": func(r *rapid.T) { @@ -150,11 +143,7 @@ func (suite *RollappTestSuite) TestLivenessFlow() { } elapsed := uint64(h - lastUpdate) p := suite.keeper().GetParams(suite.Ctx) - if elapsed <= p.LivenessJailBlocks { - require.Zero(r, tracker.jails[ra], "expect not jailed") - } else { - require.NotZero(r, tracker.jails[ra], "expect jailed") - } + if elapsed <= p.LivenessSlashBlocks { l := tracker.slashes[ra] require.Zero(r, l, "expect not slashed") @@ -173,6 +162,7 @@ func (suite *RollappTestSuite) TestLivenessFlow() { if !rollappIsDown[raID] { ra := suite.keeper().MustGetRollapp(suite.Ctx, raID) suite.keeper().IndicateLiveness(suite.Ctx, &ra) + suite.keeper().SetRollapp(suite.Ctx, ra) hLastUpdate[raID] = suite.Ctx.BlockHeight() tracker.clear(raID) } @@ -188,7 +178,11 @@ func (suite *RollappTestSuite) TestLivenessFlow() { type livenessMockSequencerKeeper struct { slashes map[string]int - jails map[string]int +} + +// PunishSequencer implements keeper.SequencerKeeper. +func (l livenessMockSequencerKeeper) PunishSequencer(ctx sdk.Context, seqAddr string) error { + panic("unimplemented") } // JailByAddr implements types.SequencerKeeper. @@ -199,7 +193,6 @@ func (l livenessMockSequencerKeeper) JailByAddr(ctx sdk.Context, seqAddr string) func newLivenessMockSequencerKeeper() livenessMockSequencerKeeper { return livenessMockSequencerKeeper{ make(map[string]int), - make(map[string]int), } } @@ -208,16 +201,10 @@ func (l livenessMockSequencerKeeper) SlashLiveness(ctx sdk.Context, rollappID st return nil } -func (l livenessMockSequencerKeeper) JailLiveness(ctx sdk.Context, rollappID string) error { - l.jails[rollappID]++ - return nil -} - -func (l livenessMockSequencerKeeper) GetProposer(ctx sdk.Context, rollappId string) (val seqtypes.Sequencer, found bool) { - return seqtypes.Sequencer{}, false +func (l livenessMockSequencerKeeper) GetProposer(ctx sdk.Context, rollappId string) seqtypes.Sequencer { + return seqtypes.Sequencer{} } func (l livenessMockSequencerKeeper) clear(rollappID string) { delete(l.slashes, rollappID) - delete(l.jails, rollappID) } diff --git a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go index c918c50e9..89d256820 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go +++ b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go @@ -8,6 +8,7 @@ import ( 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" ) @@ -67,9 +68,14 @@ func (k Keeper) MarkVulnerableRollapps(ctx sdk.Context, drsVersions []uint32) (i _, vulnerable := vulnerableVersions[bd.DrsVersion] if vulnerable { - err := k.HardForkToLatest(ctx, rollapp.RollappId) + // 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 { - logger.With("rollapp_id", rollapp.RollappId).Error("mark rollapp as vulnerable", "error", err) + // 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++ } diff --git a/x/rollapp/keeper/msg_server_update_rollapp_test.go b/x/rollapp/keeper/msg_server_update_rollapp_test.go index 0cd707ab9..6e5a50583 100644 --- a/x/rollapp/keeper/msg_server_update_rollapp_test.go +++ b/x/rollapp/keeper/msg_server_update_rollapp_test.go @@ -289,10 +289,9 @@ func (suite *RollappTestSuite) TestCreateAndUpdateRollapp() { // from this point on, the rollapp is launched and immutable fields cannot be updated err = suite.CreateSequencerByPubkey(suite.Ctx, rollappId, initSeqPubKey) suite.Require().NoError(err) - initSeq, ok := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addrInit) - suite.Require().True(ok) - proposer, found := suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().True(found) + initSeq, err := suite.App.SequencerKeeper.RealSequencer(suite.Ctx, addrInit) + suite.Require().NoError(err) + proposer := suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) suite.Require().Equal(initSeq, proposer) rollapp, ok := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappId) suite.Require().True(ok) @@ -308,8 +307,7 @@ func (suite *RollappTestSuite) TestCreateAndUpdateRollapp() { // 6. register another sequencer - should not be proposer newSeqAddr := suite.CreateDefaultSequencer(suite.Ctx, rollappId) - proposer, found = suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().True(found) + proposer = suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) suite.Require().NotEqual(proposer, newSeqAddr) // 7. create state update @@ -348,7 +346,7 @@ func (suite *RollappTestSuite) TestCreateAndUpdateRollapp() { Metadata: metadata, }) suite.Require().NoError(err) - initSeq, ok = suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addrInit) - suite.Require().True(ok) + initSeq, err = suite.App.SequencerKeeper.RealSequencer(suite.Ctx, addrInit) + suite.Require().NoError(err) suite.Require().Equal(metadata, initSeq.Metadata) } diff --git a/x/rollapp/keeper/msg_server_update_state.go b/x/rollapp/keeper/msg_server_update_state.go index f2a38c07a..d79f79c02 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -80,7 +80,7 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) // 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. - val, _ := k.sequencerKeeper.GetProposer(ctx, msg.RollappId) + val := k.sequencerKeeper.GetProposer(ctx, msg.RollappId) creationHeight := uint64(ctx.BlockHeight()) blockTime := ctx.BlockTime() @@ -124,7 +124,7 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) // 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, "after update state") + return nil, errorsmod.Wrap(err, "hook: after update state") } stateInfoIndex := stateInfo.GetIndex() @@ -143,9 +143,17 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) FinalizationQueue: newFinalizationQueue, }) + // FIXME: only single save can be done + 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") + } + } + // TODO: enforce `final_state_update_timeout` if sequencer rotation is in progress // https://github.com/dymensionxyz/dymension/issues/1085 k.IndicateLiveness(ctx, &rollapp) + k.SetRollapp(ctx, rollapp) events := stateInfo.GetEvents() diff --git a/x/rollapp/keeper/msg_server_update_state_test.go b/x/rollapp/keeper/msg_server_update_state_test.go index e55a33b0f..a1c8d4d0f 100644 --- a/x/rollapp/keeper/msg_server_update_state_test.go +++ b/x/rollapp/keeper/msg_server_update_state_test.go @@ -142,7 +142,7 @@ func (suite *RollappTestSuite) TestUpdateStateUnknownSequencer() { // update state _, err := suite.PostStateUpdate(suite.Ctx, rollappId, bob, 1, uint64(3)) - suite.ErrorIs(err, sequencertypes.ErrNotActiveSequencer) + suite.ErrorIs(err, sequencertypes.ErrNotProposer) } func (suite *RollappTestSuite) TestUpdateStateSequencerRollappMismatch() { @@ -153,7 +153,7 @@ func (suite *RollappTestSuite) TestUpdateStateSequencerRollappMismatch() { // update state from proposer of rollapp2 _, err := suite.PostStateUpdate(suite.Ctx, rollappId, seq_2, 1, uint64(3)) - suite.ErrorIs(err, sequencertypes.ErrNotActiveSequencer) + suite.ErrorIs(err, sequencertypes.ErrNotProposer) } func (suite *RollappTestSuite) TestUpdateStateErrLogicUnpermissioned() { @@ -190,7 +190,7 @@ func (suite *RollappTestSuite) TestUpdateStateErrLogicUnpermissioned() { } _, err := suite.msgServer.UpdateState(goCtx, &updateState) - suite.ErrorIs(err, sequencertypes.ErrNotActiveSequencer) + suite.ErrorIs(err, sequencertypes.ErrNotProposer) } func (suite *RollappTestSuite) TestFirstUpdateStateGenesisHeightGreaterThanZero() { @@ -264,7 +264,7 @@ func (suite *RollappTestSuite) TestUpdateStateErrNotActiveSequencer() { // update state from bob _, err := suite.PostStateUpdate(suite.Ctx, rollappId, addr2, 1, uint64(3)) - suite.ErrorIs(err, sequencertypes.ErrNotActiveSequencer) + suite.ErrorIs(err, sequencertypes.ErrNotProposer) } func (suite *RollappTestSuite) TestUpdateStateDowngradeTimestamp() { diff --git a/x/rollapp/keeper/params.go b/x/rollapp/keeper/params.go index eaca0da56..dd9f8b640 100644 --- a/x/rollapp/keeper/params.go +++ b/x/rollapp/keeper/params.go @@ -12,7 +12,6 @@ func (k Keeper) GetParams(ctx sdk.Context) types.Params { k.DisputePeriodInBlocks(ctx), k.LivenessSlashBlocks(ctx), k.LivenessSlashInterval(ctx), - k.LivenessJailBlocks(ctx), k.AppRegistrationFee(ctx), ) } @@ -38,11 +37,6 @@ func (k Keeper) LivenessSlashInterval(ctx sdk.Context) (res uint64) { return } -func (k Keeper) LivenessJailBlocks(ctx sdk.Context) (res uint64) { - k.paramstore.Get(ctx, types.KeyLivenessJailBlocks, &res) - return -} - // AppRegistrationFee returns the cost of adding an app func (k Keeper) AppRegistrationFee(ctx sdk.Context) (res sdk.Coin) { k.paramstore.Get(ctx, types.KeyAppRegistrationFee, &res) diff --git a/x/rollapp/keeper/rollapp.go b/x/rollapp/keeper/rollapp.go index 23e7491ff..a70383950 100644 --- a/x/rollapp/keeper/rollapp.go +++ b/x/rollapp/keeper/rollapp.go @@ -1,14 +1,17 @@ package keeper import ( + "errors" "fmt" errorsmod "cosmossdk.io/errors" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + transferTypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" "github.com/dymensionxyz/gerr-cosmos/gerrc" + udenom "github.com/dymensionxyz/dymension/v3/utils/denom" irotypes "github.com/dymensionxyz/dymension/v3/x/iro/types" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) @@ -197,6 +200,63 @@ func (k Keeper) GetRollappByName( return val, true } +// GetRollappByDenom tries to extract a rollapp ID from the provided denom and returns a rollapp object if found. +// Denom may be either IRO token or IBC token. +func (k Keeper) GetRollappByDenom(ctx sdk.Context, denom string) (*types.Rollapp, error) { + // by IRO token + // try to get the rollapp ID from the denom + rollappID, ok := irotypes.RollappIDFromIRODenom(denom) + if ok { + ra, ok := k.GetRollapp(ctx, rollappID) + if ok { + return &ra, nil + } + return nil, types.ErrUnknownRollappID + } + + // by IBC token + // first, validate that the denom is IBC + hexHash, ok := udenom.ValidateIBCDenom(denom) + if !ok { + return nil, errors.New("denom is neither IRO nor IBC") + } + + // parse IBC denom hash string + hash, err := transferTypes.ParseHexHash(hexHash) + if err != nil { + return nil, fmt.Errorf("parse IBC hex hash: %w", err) + } + // get IBC denom trace + trace, ok := k.transferKeeper.GetDenomTrace(ctx, hash) + if !ok { + return nil, errors.New("denom trace not found") + } + // try to get source port and channel from the trace + sourcePort, sourceChan, ok := udenom.SourcePortChanFromTracePath(trace.Path) + if !ok { + return nil, errors.New("invalid denom trace path") + } + + return k.GetRollappByPortChan(ctx, sourcePort, sourceChan) +} + +func (k Keeper) GetRollappOwnerByDenom(ctx sdk.Context, denom string) (sdk.AccAddress, error) { + ra, err := k.GetRollappByDenom(ctx, denom) + if err != nil { + return nil, fmt.Errorf("get rollapp by denom: %w", err) + } + owner, err := sdk.AccAddressFromBech32(ra.Owner) + if err != nil { + return nil, fmt.Errorf("owner account address: %w", err) + } + return owner, nil +} + +func (k Keeper) MustGetRollappOwner(ctx sdk.Context, rollappID string) sdk.AccAddress { + ra := k.MustGetRollapp(ctx, rollappID) + return sdk.MustAccAddressFromBech32(ra.Owner) +} + func (k Keeper) MustGetRollapp(ctx sdk.Context, rollappId string) types.Rollapp { ret, found := k.GetRollapp(ctx, rollappId) if !found { diff --git a/x/rollapp/keeper/sequencer_hooks.go b/x/rollapp/keeper/sequencer_hooks.go new file mode 100644 index 000000000..d9ee26e0d --- /dev/null +++ b/x/rollapp/keeper/sequencer_hooks.go @@ -0,0 +1,38 @@ +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 (h 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 := h.Keeper.MustGetRollapp(ctx, rollapp) + h.Keeper.ResetLivenessClock(ctx, &ra) + if !after.Sentinel() { + h.Keeper.ScheduleLivenessEvent(ctx, &ra) + } + h.Keeper.SetRollapp(ctx, ra) + + // recover from halt + // if the rollapp has a state info, set the next proposer to this sequencer + if before.Sentinel() && !after.Sentinel() { + sInfo, _ := h.Keeper.GetLatestStateInfo(ctx, rollapp) + sInfo.NextProposer = after.Address + h.Keeper.SetStateInfo(ctx, sInfo) + } + +} + +func (h SequencerHooks) AfterKickProposer(ctx sdk.Context, kicked sequencertypes.Sequencer) { + h.Keeper.HardForkToLatest(ctx, kicked.RollappId) +} diff --git a/x/rollapp/types/errors.go b/x/rollapp/types/errors.go index 04b7cd3ab..df24a33f5 100644 --- a/x/rollapp/types/errors.go +++ b/x/rollapp/types/errors.go @@ -19,7 +19,7 @@ var ( ErrInvalidGenesisChecksum = errorsmod.Register(ModuleName, 1010, "invalid genesis checksum") ErrInvalidStateRoot = errorsmod.Register(ModuleName, 1011, "invalid blocks state root") ErrAppRegistrationFeePayment = errorsmod.Register(ModuleName, 1013, "app registration fee payment error") - ErrStateNotExists = errorsmod.Register(ModuleName, 1017, "state of this height doesn't exist") + ErrStateNotExists = gerrc.ErrNotFound.Wrap("state of this height doesn't exist") ErrInvalidHeight = errorsmod.Register(ModuleName, 1018, "invalid rollapp height") ErrInvalidRollappID = errorsmod.Register(ModuleName, 1020, "invalid rollapp-id") ErrNoFinalizedStateYetForRollapp = errorsmod.Register(ModuleName, 1024, "no finalized state yet for rollapp") diff --git a/x/rollapp/types/genesis.go b/x/rollapp/types/genesis.go index 6723ba9b6..b2d129a70 100644 --- a/x/rollapp/types/genesis.go +++ b/x/rollapp/types/genesis.go @@ -85,5 +85,15 @@ func (gs GenesisState) Validate() error { appIndexMap[index] = struct{}{} } + // Check for duplicated index in vulnerable DRS versions + vulnerableDRSVersionIndexMap := make(map[uint32]struct{}) + + for _, elem := range gs.VulnerableDrsVersions { + if _, ok := vulnerableDRSVersionIndexMap[elem]; ok { + return errors.New("duplicated index for VulnerableDrsVersions") + } + vulnerableDRSVersionIndexMap[elem] = struct{}{} + } + return gs.Params.Validate() } diff --git a/x/rollapp/types/genesis.pb.go b/x/rollapp/types/genesis.pb.go index b296aa264..03cee006b 100644 --- a/x/rollapp/types/genesis.pb.go +++ b/x/rollapp/types/genesis.pb.go @@ -32,9 +32,12 @@ type GenesisState struct { LatestFinalizedStateIndexList []StateInfoIndex `protobuf:"bytes,5,rep,name=latestFinalizedStateIndexList,proto3" json:"latestFinalizedStateIndexList"` BlockHeightToFinalizationQueueList []BlockHeightToFinalizationQueue `protobuf:"bytes,6,rep,name=blockHeightToFinalizationQueueList,proto3" json:"blockHeightToFinalizationQueueList"` // LivenessEvents are scheduled upcoming liveness events - LivenessEvents []LivenessEvent `protobuf:"bytes,7,rep,name=livenessEvents,proto3" json:"livenessEvents"` - AppList []App `protobuf:"bytes,8,rep,name=appList,proto3" json:"appList"` - RegisteredDenoms []RollappRegisteredDenoms `protobuf:"bytes,9,rep,name=registeredDenoms,proto3" json:"registeredDenoms"` + LivenessEvents []LivenessEvent `protobuf:"bytes,7,rep,name=livenessEvents,proto3" json:"livenessEvents"` + 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"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -133,6 +136,72 @@ func (m *GenesisState) GetRegisteredDenoms() []RollappRegisteredDenoms { return nil } +func (m *GenesisState) GetSequencerHeightPairs() []SequencerHeightPair { + if m != nil { + return m.SequencerHeightPairs + } + return nil +} + +func (m *GenesisState) GetVulnerableDrsVersions() []uint32 { + if m != nil { + return m.VulnerableDrsVersions + } + return nil +} + +type SequencerHeightPair struct { + Sequencer string `protobuf:"bytes,1,opt,name=sequencer,proto3" json:"sequencer,omitempty"` + Height uint64 `protobuf:"varint,2,opt,name=height,proto3" json:"height,omitempty"` +} + +func (m *SequencerHeightPair) Reset() { *m = SequencerHeightPair{} } +func (m *SequencerHeightPair) String() string { return proto.CompactTextString(m) } +func (*SequencerHeightPair) ProtoMessage() {} +func (*SequencerHeightPair) Descriptor() ([]byte, []int) { + return fileDescriptor_b76890aebc09aa04, []int{1} +} +func (m *SequencerHeightPair) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *SequencerHeightPair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_SequencerHeightPair.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 *SequencerHeightPair) XXX_Merge(src proto.Message) { + xxx_messageInfo_SequencerHeightPair.Merge(m, src) +} +func (m *SequencerHeightPair) XXX_Size() int { + return m.Size() +} +func (m *SequencerHeightPair) XXX_DiscardUnknown() { + xxx_messageInfo_SequencerHeightPair.DiscardUnknown(m) +} + +var xxx_messageInfo_SequencerHeightPair proto.InternalMessageInfo + +func (m *SequencerHeightPair) GetSequencer() string { + if m != nil { + return m.Sequencer + } + return "" +} + +func (m *SequencerHeightPair) GetHeight() uint64 { + if m != nil { + return m.Height + } + return 0 +} + type RollappRegisteredDenoms struct { RollappId string `protobuf:"bytes,1,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` Denoms []string `protobuf:"bytes,2,rep,name=denoms,proto3" json:"denoms,omitempty"` @@ -142,7 +211,7 @@ func (m *RollappRegisteredDenoms) Reset() { *m = RollappRegisteredDenoms func (m *RollappRegisteredDenoms) String() string { return proto.CompactTextString(m) } func (*RollappRegisteredDenoms) ProtoMessage() {} func (*RollappRegisteredDenoms) Descriptor() ([]byte, []int) { - return fileDescriptor_b76890aebc09aa04, []int{1} + return fileDescriptor_b76890aebc09aa04, []int{2} } func (m *RollappRegisteredDenoms) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -187,6 +256,7 @@ func (m *RollappRegisteredDenoms) GetDenoms() []string { func init() { proto.RegisterType((*GenesisState)(nil), "dymensionxyz.dymension.rollapp.GenesisState") + proto.RegisterType((*SequencerHeightPair)(nil), "dymensionxyz.dymension.rollapp.SequencerHeightPair") proto.RegisterType((*RollappRegisteredDenoms)(nil), "dymensionxyz.dymension.rollapp.RollappRegisteredDenoms") } @@ -195,39 +265,45 @@ func init() { } var fileDescriptor_b76890aebc09aa04 = []byte{ - // 499 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0x4f, 0x8b, 0xd3, 0x40, - 0x18, 0xc6, 0x1b, 0x77, 0x6d, 0xed, 0x54, 0x45, 0x06, 0xd1, 0x50, 0xd8, 0xb8, 0x54, 0xd0, 0x8a, - 0x6e, 0x02, 0xbb, 0x82, 0x37, 0xc1, 0xba, 0xfe, 0x29, 0x2c, 0xba, 0x66, 0xf5, 0xa2, 0x87, 0x25, - 0xdd, 0xbc, 0x9b, 0x1d, 0x4c, 0x66, 0x42, 0x66, 0x5a, 0xda, 0x7e, 0x08, 0xf1, 0xe0, 0x87, 0xda, - 0xe3, 0x1e, 0x3d, 0x89, 0xb4, 0x5f, 0x44, 0x32, 0x79, 0x13, 0xea, 0x4a, 0x3b, 0x05, 0x4f, 0xe9, - 0x34, 0xcf, 0xf3, 0x7b, 0x9e, 0x0c, 0xef, 0x0c, 0x79, 0x12, 0x4e, 0x12, 0xe0, 0x92, 0x09, 0x3e, - 0x9e, 0x4c, 0xbd, 0x6a, 0xe1, 0x65, 0x22, 0x8e, 0x83, 0x34, 0xf5, 0x22, 0xe0, 0x20, 0x99, 0x74, - 0xd3, 0x4c, 0x28, 0x41, 0x9d, 0x45, 0xb5, 0x5b, 0x2d, 0x5c, 0x54, 0xb7, 0x6f, 0x47, 0x22, 0x12, - 0x5a, 0xea, 0xe5, 0xbf, 0x0a, 0x57, 0xfb, 0xb1, 0x21, 0x23, 0x0d, 0xb2, 0x20, 0xc1, 0x88, 0xb6, - 0xa9, 0x10, 0x3e, 0x51, 0xed, 0x19, 0xd4, 0x52, 0x05, 0x0a, 0x8e, 0x19, 0x3f, 0x2d, 0xbb, 0xec, - 0x18, 0x0c, 0x31, 0x1b, 0xe5, 0x5f, 0x5c, 0xb6, 0xe9, 0x1a, 0xe4, 0x55, 0x93, 0xce, 0xb7, 0x06, - 0xb9, 0xfe, 0xa6, 0xd8, 0xac, 0xa3, 0x3c, 0x94, 0xee, 0x93, 0x7a, 0xf1, 0x61, 0xb6, 0xb5, 0x6d, - 0x75, 0x5b, 0xbb, 0x0f, 0xdc, 0xd5, 0x9b, 0xe7, 0x1e, 0x6a, 0x75, 0x6f, 0xf3, 0xfc, 0xd7, 0xbd, - 0x9a, 0x8f, 0x5e, 0xfa, 0x9e, 0xb4, 0xf0, 0xfd, 0x01, 0x93, 0xca, 0xbe, 0xb2, 0xbd, 0xd1, 0x6d, - 0xed, 0x3e, 0x34, 0xa1, 0xfc, 0xe2, 0x89, 0xac, 0x45, 0x02, 0xfd, 0x44, 0x6e, 0xe8, 0x4d, 0xe9, - 0xf3, 0x53, 0xa1, 0x91, 0x1b, 0x1a, 0xf9, 0xc8, 0x84, 0x3c, 0x2a, 0x4d, 0x08, 0xfd, 0x9b, 0x42, - 0x53, 0x62, 0xc7, 0x81, 0x02, 0xa9, 0x2a, 0x5d, 0x9f, 0x87, 0x30, 0xd6, 0x09, 0x9b, 0x3a, 0xc1, - 0x5d, 0x3b, 0x41, 0x3b, 0x31, 0x66, 0x29, 0x95, 0x4e, 0xc9, 0x56, 0xf1, 0xee, 0x35, 0xe3, 0x41, - 0xcc, 0xa6, 0x10, 0xa2, 0xa8, 0x8c, 0xbd, 0xfa, 0x1f, 0xb1, 0xab, 0xd1, 0xf4, 0x87, 0x45, 0x3a, - 0x83, 0x58, 0x9c, 0x7c, 0x7d, 0x0b, 0x2c, 0x3a, 0x53, 0x1f, 0x05, 0x0a, 0x03, 0xc5, 0x04, 0xff, - 0x30, 0x84, 0x21, 0xe8, 0x06, 0x75, 0xdd, 0xe0, 0xb9, 0xa9, 0x41, 0x6f, 0x25, 0x09, 0x1b, 0xad, - 0x91, 0x47, 0xbf, 0x90, 0x9b, 0xe5, 0xfc, 0xbe, 0x1a, 0x01, 0x57, 0xd2, 0x6e, 0xe8, 0x06, 0x3b, - 0xa6, 0x06, 0x07, 0x8b, 0x2e, 0x0c, 0xbc, 0x84, 0xa2, 0x2f, 0x49, 0xa3, 0x9c, 0xc2, 0x6b, 0x9a, - 0x7a, 0xdf, 0x44, 0x7d, 0x51, 0x4d, 0x60, 0xe9, 0xa4, 0x8c, 0xdc, 0xca, 0x20, 0x62, 0x52, 0x41, - 0x06, 0xe1, 0x3e, 0x70, 0x91, 0x48, 0xbb, 0xa9, 0x69, 0xcf, 0xd6, 0x9c, 0x69, 0xff, 0x92, 0x1d, - 0x13, 0xfe, 0xc1, 0x76, 0x0e, 0xc9, 0xdd, 0x25, 0x16, 0xba, 0x45, 0x08, 0x52, 0x8f, 0x59, 0xa8, - 0x8f, 0x67, 0xd3, 0x6f, 0xe2, 0x3f, 0xfd, 0x90, 0xde, 0x21, 0xf5, 0xb0, 0xa8, 0x96, 0x1f, 0xb7, - 0xa6, 0x8f, 0xab, 0xde, 0xbb, 0xf3, 0x99, 0x63, 0x5d, 0xcc, 0x1c, 0xeb, 0xf7, 0xcc, 0xb1, 0xbe, - 0xcf, 0x9d, 0xda, 0xc5, 0xdc, 0xa9, 0xfd, 0x9c, 0x3b, 0xb5, 0xcf, 0x4f, 0x23, 0xa6, 0xce, 0x86, - 0x03, 0xf7, 0x44, 0x24, 0xcb, 0x6e, 0xa4, 0xd1, 0x9e, 0x37, 0xae, 0xae, 0x0d, 0x35, 0x49, 0x41, - 0x0e, 0xea, 0xfa, 0xe6, 0xd8, 0xfb, 0x13, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x9d, 0x0c, 0xa4, 0x84, - 0x05, 0x00, 0x00, + // 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, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -250,6 +326,38 @@ 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) + var j1 int + for _, num := range m.VulnerableDrsVersions { + for num >= 1<<7 { + dAtA2[j1] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j1++ + } + dAtA2[j1] = uint8(num) + j1++ + } + i -= j1 + copy(dAtA[i:], dAtA2[:j1]) + i = encodeVarintGenesis(dAtA, i, uint64(j1)) + i-- + dAtA[i] = 0x5a + } + if len(m.SequencerHeightPairs) > 0 { + for iNdEx := len(m.SequencerHeightPairs) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.SequencerHeightPairs[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + } if len(m.RegisteredDenoms) > 0 { for iNdEx := len(m.RegisteredDenoms) - 1; iNdEx >= 0; iNdEx-- { { @@ -375,6 +483,41 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *SequencerHeightPair) 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 *SequencerHeightPair) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *SequencerHeightPair) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Height != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.Height)) + i-- + dAtA[i] = 0x10 + } + if len(m.Sequencer) > 0 { + i -= len(m.Sequencer) + copy(dAtA[i:], m.Sequencer) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.Sequencer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *RollappRegisteredDenoms) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -481,6 +624,35 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } + if len(m.SequencerHeightPairs) > 0 { + for _, e := range m.SequencerHeightPairs { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.VulnerableDrsVersions) > 0 { + l = 0 + for _, e := range m.VulnerableDrsVersions { + l += sovGenesis(uint64(e)) + } + n += 1 + sovGenesis(uint64(l)) + l + } + return n +} + +func (m *SequencerHeightPair) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sequencer) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.Height != 0 { + n += 1 + sovGenesis(uint64(m.Height)) + } return n } @@ -843,6 +1015,217 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SequencerHeightPairs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SequencerHeightPairs = append(m.SequencerHeightPairs, SequencerHeightPair{}) + if err := m.SequencerHeightPairs[len(m.SequencerHeightPairs)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType == 0 { + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.VulnerableDrsVersions = append(m.VulnerableDrsVersions, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.VulnerableDrsVersions) == 0 { + m.VulnerableDrsVersions = make([]uint32, 0, elementCount) + } + for iNdEx < postIndex { + var v uint32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.VulnerableDrsVersions = append(m.VulnerableDrsVersions, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field VulnerableDrsVersions", wireType) + } + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SequencerHeightPair) 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 ErrIntOverflowGenesis + } + 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: SequencerHeightPair: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: SequencerHeightPair: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequencer", 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.Sequencer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Height", wireType) + } + m.Height = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Height |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/rollapp/types/genesis_test.go b/x/rollapp/types/genesis_test.go index 3468ca887..6df041e3d 100644 --- a/x/rollapp/types/genesis_test.go +++ b/x/rollapp/types/genesis_test.go @@ -61,6 +61,7 @@ func TestGenesisState_Validate(t *testing.T) { CreationHeight: 1, }, }, + VulnerableDrsVersions: []uint32{1, 2}, }, valid: true, }, @@ -108,17 +109,6 @@ func TestGenesisState_Validate(t *testing.T) { }, valid: false, }, - { - desc: "invalid LivenessJailBlocks", - genState: &types.GenesisState{ - Params: types.DefaultParams().WithLivenessJailBlocks(0), - RollappList: []types.Rollapp{{RollappId: "0"}}, - StateInfoList: []types.StateInfo{}, - LatestStateInfoIndexList: []types.StateInfoIndex{}, - BlockHeightToFinalizationQueueList: []types.BlockHeightToFinalizationQueue{}, - }, - valid: false, - }, { desc: "duplicated stateInfo", genState: &types.GenesisState{ @@ -152,6 +142,18 @@ func TestGenesisState_Validate(t *testing.T) { }, valid: false, }, + { + desc: "duplicated VulnerableDrsVersions", + genState: &types.GenesisState{ + Params: types.DefaultParams(), + RollappList: []types.Rollapp{}, + StateInfoList: []types.StateInfo{}, + LatestStateInfoIndexList: []types.StateInfoIndex{}, + BlockHeightToFinalizationQueueList: []types.BlockHeightToFinalizationQueue{}, + VulnerableDrsVersions: []uint32{1, 1}, + }, + valid: false, + }, } { t.Run(tc.desc, func(t *testing.T) { err := tc.genState.Validate() diff --git a/x/rollapp/types/keys.go b/x/rollapp/types/keys.go index 6239e5ef6..4a3e11639 100644 --- a/x/rollapp/types/keys.go +++ b/x/rollapp/types/keys.go @@ -1,5 +1,7 @@ package types +import "cosmossdk.io/collections" + const ( // ModuleName defines the module name ModuleName = "rollapp" @@ -26,3 +28,5 @@ const ( // KeyRegisteredDenomPrefix is the prefix to retrieve all RegisteredDenom KeyRegisteredDenomPrefix = "RegisteredDenom/value/" ) + +var SeqToUnfinalizedHeightKeyPrefix = collections.NewPrefix("seqToFinalizeHeight/") diff --git a/x/rollapp/types/liveness.go b/x/rollapp/types/liveness.go index db5d6ef5a..27f260c73 100644 --- a/x/rollapp/types/liveness.go +++ b/x/rollapp/types/liveness.go @@ -1,21 +1,17 @@ package types import ( - "bytes" "encoding/binary" ) var ( LivenessEventQueueKeyPrefix = []byte("LivenessEventQueue") LivenessEventQueueSlash = []byte("s") - LivenessEventQueueJail = []byte("j") ) func LivenessEventQueueKey(e LivenessEvent) []byte { v := LivenessEventQueueSlash - if e.IsJail { - v = LivenessEventQueueJail - } + ret := LivenessEventQueueIterHeightKey(e.HubHeight) ret = append(ret, []byte("/")...) ret = append(ret, v...) @@ -46,9 +42,6 @@ func LivenessEventQueueKeyToEvent(k []byte) LivenessEvent { j := i + 8 + 1 // 8 is from big endian, 1 is from '/' l := j + 1 + 1 // kind is 1 character and the other 1 is from '/' ret.HubHeight = int64(binary.BigEndian.Uint64(k[i : i+8])) - if bytes.Equal(k[j:j+1], LivenessEventQueueJail) { - ret.IsJail = true - } ret.RollappId = string(k[l:]) return ret } diff --git a/x/rollapp/types/liveness.pb.go b/x/rollapp/types/liveness.pb.go index b363f4594..666ee2ec2 100644 --- a/x/rollapp/types/liveness.pb.go +++ b/x/rollapp/types/liveness.pb.go @@ -30,8 +30,6 @@ type LivenessEvent struct { RollappId string `protobuf:"bytes,1,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` // HubHeight when event will occur HubHeight int64 `protobuf:"varint,2,opt,name=hub_height,json=hubHeight,proto3" json:"hub_height,omitempty"` - // IsJail is true iff the event is to jail rather than slash - IsJail bool `protobuf:"varint,3,opt,name=is_jail,json=isJail,proto3" json:"is_jail,omitempty"` } func (m *LivenessEvent) Reset() { *m = LivenessEvent{} } @@ -81,13 +79,6 @@ func (m *LivenessEvent) GetHubHeight() int64 { return 0 } -func (m *LivenessEvent) GetIsJail() bool { - if m != nil { - return m.IsJail - } - return false -} - func init() { proto.RegisterType((*LivenessEvent)(nil), "dymensionxyz.dymension.rollapp.LivenessEvent") } @@ -97,24 +88,23 @@ func init() { } var fileDescriptor_0e2dfe628b004fdb = []byte{ - // 268 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x4f, 0xcf, 0x4a, 0x84, 0x40, - 0x18, 0x77, 0x5a, 0xd8, 0x52, 0xe8, 0x22, 0x41, 0xb2, 0xd0, 0x20, 0x9d, 0xbc, 0xe4, 0xb0, 0x6c, - 0x4f, 0x10, 0x04, 0x15, 0xd1, 0xc1, 0x63, 0x17, 0x99, 0xd1, 0x59, 0xfd, 0x42, 0x67, 0x64, 0xbf, - 0x51, 0xd6, 0x9e, 0xa2, 0xc7, 0xea, 0xb8, 0xc7, 0x8e, 0xa1, 0x2f, 0x12, 0xeb, 0x9a, 0x74, 0x89, - 0xbd, 0xcd, 0xef, 0xdf, 0x7c, 0xbf, 0x9f, 0x73, 0x93, 0xb6, 0xa5, 0x54, 0x08, 0x5a, 0x6d, 0xdb, - 0x77, 0x36, 0x01, 0xb6, 0xd1, 0x45, 0xc1, 0xab, 0x8a, 0x15, 0xd0, 0x48, 0x25, 0x11, 0xc3, 0x6a, - 0xa3, 0x8d, 0x76, 0xe9, 0x5f, 0x7b, 0x38, 0x81, 0x70, 0xb4, 0x2f, 0x2e, 0x32, 0x9d, 0xe9, 0xc1, - 0xca, 0xf6, 0xaf, 0x43, 0x6a, 0xc1, 0x8e, 0x1c, 0x41, 0xc3, 0x8d, 0x8c, 0x41, 0xad, 0x7f, 0x03, - 0x34, 0xd1, 0x58, 0x6a, 0x64, 0x82, 0xa3, 0x64, 0xcd, 0x52, 0x48, 0xc3, 0x97, 0x2c, 0xd1, 0xa0, - 0x0e, 0xfa, 0xf5, 0xda, 0x39, 0x7f, 0x1e, 0x8b, 0xdd, 0x37, 0x52, 0x19, 0xf7, 0xca, 0x71, 0xc6, - 0xcf, 0x62, 0x48, 0x3d, 0xe2, 0x93, 0xc0, 0x8e, 0xec, 0x91, 0x79, 0x4c, 0xf7, 0x72, 0x5e, 0x8b, - 0x38, 0x97, 0x90, 0xe5, 0xc6, 0x3b, 0xf1, 0x49, 0x30, 0x8b, 0xec, 0xbc, 0x16, 0x0f, 0x03, 0xe1, - 0x5e, 0x3a, 0xa7, 0x80, 0xf1, 0x1b, 0x87, 0xc2, 0x9b, 0xf9, 0x24, 0x38, 0x8b, 0xe6, 0x80, 0x4f, - 0x1c, 0x8a, 0xbb, 0x97, 0xcf, 0x8e, 0x92, 0x5d, 0x47, 0xc9, 0x77, 0x47, 0xc9, 0x47, 0x4f, 0xad, - 0x5d, 0x4f, 0xad, 0xaf, 0x9e, 0x5a, 0xaf, 0xb7, 0x19, 0x98, 0xbc, 0x16, 0x61, 0xa2, 0xcb, 0xff, - 0xd6, 0x35, 0x2b, 0xb6, 0x9d, 0x26, 0x9a, 0xb6, 0x92, 0x28, 0xe6, 0x43, 0xfd, 0xd5, 0x4f, 0x00, - 0x00, 0x00, 0xff, 0xff, 0xe1, 0x3b, 0x38, 0x66, 0x76, 0x01, 0x00, 0x00, + // 252 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4d, 0xa9, 0xcc, 0x4d, + 0xcd, 0x2b, 0xce, 0xcc, 0xcf, 0xab, 0xa8, 0xac, 0xd2, 0x87, 0x73, 0xf4, 0x8b, 0xf2, 0x73, 0x72, + 0x12, 0x0b, 0x0a, 0xf4, 0x73, 0x32, 0xcb, 0x52, 0xf3, 0x52, 0x8b, 0x8b, 0xf5, 0x0a, 0x8a, 0xf2, + 0x4b, 0xf2, 0x85, 0xe4, 0x90, 0x95, 0xeb, 0xc1, 0x39, 0x7a, 0x50, 0xe5, 0x52, 0x22, 0xe9, 0xf9, + 0xe9, 0xf9, 0x60, 0xa5, 0xfa, 0x20, 0x16, 0x44, 0x97, 0x94, 0x3e, 0x01, 0x4b, 0x8a, 0x4b, 0x12, + 0x4b, 0x52, 0xe3, 0x33, 0xf3, 0xd2, 0x60, 0x1a, 0xe4, 0x92, 0xf3, 0x8b, 0x73, 0xf3, 0x8b, 0xf5, + 0x93, 0x12, 0x8b, 0x53, 0xf5, 0xcb, 0x0c, 0x93, 0x52, 0x4b, 0x12, 0x0d, 0xf5, 0x93, 0xf3, 0x33, + 0xf3, 0x20, 0xf2, 0x4a, 0xc1, 0x5c, 0xbc, 0x3e, 0x50, 0x87, 0xb9, 0x96, 0xa5, 0xe6, 0x95, 0x08, + 0xc9, 0x72, 0x71, 0x41, 0x0d, 0x8b, 0xcf, 0x4c, 0x91, 0x60, 0x54, 0x60, 0xd4, 0xe0, 0x0c, 0xe2, + 0x84, 0x8a, 0x78, 0xa6, 0x80, 0xa4, 0x33, 0x4a, 0x93, 0xe2, 0x33, 0x52, 0x33, 0xd3, 0x33, 0x4a, + 0x24, 0x98, 0x14, 0x18, 0x35, 0x98, 0x83, 0x38, 0x33, 0x4a, 0x93, 0x3c, 0xc0, 0x02, 0x5e, 0x2c, + 0x1c, 0xcc, 0x02, 0x2c, 0x4e, 0x7e, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8, 0xe0, + 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7, 0x10, + 0x65, 0x92, 0x9e, 0x59, 0x92, 0x51, 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0x8b, 0xcb, 0x2b, 0x65, 0xc6, + 0xfa, 0x15, 0x70, 0xff, 0x94, 0x54, 0x16, 0xa4, 0x16, 0x27, 0xb1, 0x81, 0xdd, 0x6a, 0x0c, 0x08, + 0x00, 0x00, 0xff, 0xff, 0x0d, 0x3f, 0x53, 0x4d, 0x63, 0x01, 0x00, 0x00, } func (m *LivenessEvent) Marshal() (dAtA []byte, err error) { @@ -137,16 +127,6 @@ func (m *LivenessEvent) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.IsJail { - i-- - if m.IsJail { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x18 - } if m.HubHeight != 0 { i = encodeVarintLiveness(dAtA, i, uint64(m.HubHeight)) i-- @@ -186,9 +166,6 @@ func (m *LivenessEvent) Size() (n int) { if m.HubHeight != 0 { n += 1 + sovLiveness(uint64(m.HubHeight)) } - if m.IsJail { - n += 2 - } return n } @@ -278,26 +255,6 @@ func (m *LivenessEvent) Unmarshal(dAtA []byte) error { break } } - case 3: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field IsJail", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowLiveness - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.IsJail = bool(v != 0) default: iNdEx = preIndex skippy, err := skipLiveness(dAtA[iNdEx:]) diff --git a/x/rollapp/types/params.go b/x/rollapp/types/params.go index 540c6c9dc..5b1240f02 100644 --- a/x/rollapp/types/params.go +++ b/x/rollapp/types/params.go @@ -22,7 +22,6 @@ var ( KeyLivenessSlashBlocks = []byte("LivenessSlashBlocks") KeyLivenessSlashInterval = []byte("LivenessSlashInterval") - KeyLivenessJailBlocks = []byte("LivenessJailBlocks") // KeyAppRegistrationFee defines the key to store the cost of the app KeyAppRegistrationFee = []byte("AppRegistrationFee") @@ -37,9 +36,8 @@ const ( // MinDisputePeriodInBlocks is the minimum number of blocks for dispute period MinDisputePeriodInBlocks uint64 = 1 - DefaultLivenessSlashBlocks = uint64(7200) // 12 hours at 1 block per 6 seconds - DefaultLivenessSlashInterval = uint64(3600) // 1 hour at 1 block per 6 seconds - DefaultLivenessJailBlocks = uint64(28800) // 48 hours at 1 block per 6 seconds + DefaultLivenessSlashBlocks = uint64(7200) // 12 hours at 1 block per 6 seconds + DefaultLivenessSlashInterval = uint64(3600) // 1 hour at 1 block per 6 seconds ) // ParamKeyTable the param key table for launch module @@ -52,14 +50,12 @@ func NewParams( disputePeriodInBlocks uint64, livenessSlashBlocks uint64, livenessSlashInterval uint64, - livenessJailBlocks uint64, appRegistrationFee sdk.Coin, ) Params { return Params{ DisputePeriodInBlocks: disputePeriodInBlocks, LivenessSlashBlocks: livenessSlashBlocks, LivenessSlashInterval: livenessSlashInterval, - LivenessJailBlocks: livenessJailBlocks, AppRegistrationFee: appRegistrationFee, } } @@ -69,7 +65,6 @@ func DefaultParams() Params { return NewParams(DefaultDisputePeriodInBlocks, DefaultLivenessSlashBlocks, DefaultLivenessSlashInterval, - DefaultLivenessJailBlocks, DefaultAppRegistrationFee, ) } @@ -80,7 +75,6 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyDisputePeriodInBlocks, &p.DisputePeriodInBlocks, validateDisputePeriodInBlocks), paramtypes.NewParamSetPair(KeyLivenessSlashBlocks, &p.LivenessSlashBlocks, validateLivenessSlashBlocks), paramtypes.NewParamSetPair(KeyLivenessSlashInterval, &p.LivenessSlashInterval, validateLivenessSlashInterval), - paramtypes.NewParamSetPair(KeyLivenessJailBlocks, &p.LivenessJailBlocks, validateLivenessJailBlocks), paramtypes.NewParamSetPair(KeyAppRegistrationFee, &p.AppRegistrationFee, validateAppRegistrationFee), } } @@ -100,11 +94,6 @@ func (p Params) WithLivenessSlashInterval(x uint64) Params { return p } -func (p Params) WithLivenessJailBlocks(x uint64) Params { - p.LivenessJailBlocks = x - return p -} - // Validate validates the set of params func (p Params) Validate() error { if err := validateDisputePeriodInBlocks(p.DisputePeriodInBlocks); err != nil { @@ -117,9 +106,6 @@ func (p Params) Validate() error { if err := validateLivenessSlashInterval(p.LivenessSlashInterval); err != nil { return errorsmod.Wrap(err, "liveness slash interval") } - if err := validateLivenessJailBlocks(p.LivenessJailBlocks); err != nil { - return errorsmod.Wrap(err, "liveness jail blocks") - } if err := validateAppRegistrationFee(p.AppRegistrationFee); err != nil { return errorsmod.Wrap(err, "app registration fee") @@ -141,10 +127,6 @@ func validateLivenessSlashInterval(i interface{}) error { return uparam.ValidatePositiveUint64(i) } -func validateLivenessJailBlocks(i interface{}) error { - return uparam.ValidatePositiveUint64(i) -} - // validateDisputePeriodInBlocks validates the DisputePeriodInBlocks param func validateDisputePeriodInBlocks(v interface{}) error { disputePeriodInBlocks, ok := v.(uint64) diff --git a/x/rollapp/types/params.pb.go b/x/rollapp/types/params.pb.go index e53d22453..c53369b75 100644 --- a/x/rollapp/types/params.pb.go +++ b/x/rollapp/types/params.pb.go @@ -34,8 +34,6 @@ type Params struct { LivenessSlashBlocks uint64 `protobuf:"varint,4,opt,name=liveness_slash_blocks,json=livenessSlashBlocks,proto3" json:"liveness_slash_blocks,omitempty" yaml:"liveness_slash_blocks"` // The min gap (num hub blocks) between a sequence of slashes if the sequencer continues to be down LivenessSlashInterval uint64 `protobuf:"varint,5,opt,name=liveness_slash_interval,json=livenessSlashInterval,proto3" json:"liveness_slash_interval,omitempty" yaml:"liveness_slash_interval"` - // The time (num hub blocks) a sequencer can be down after which he will be jailed rather than slashed - LivenessJailBlocks uint64 `protobuf:"varint,6,opt,name=liveness_jail_blocks,json=livenessJailBlocks,proto3" json:"liveness_jail_blocks,omitempty" yaml:"liveness_jail_blocks"` // app_registration_fee is the fee for registering an App AppRegistrationFee types.Coin `protobuf:"bytes,7,opt,name=app_registration_fee,json=appRegistrationFee,proto3" json:"app_registration_fee" yaml:"app_registration_fee"` } @@ -93,13 +91,6 @@ func (m *Params) GetLivenessSlashInterval() uint64 { return 0 } -func (m *Params) GetLivenessJailBlocks() uint64 { - if m != nil { - return m.LivenessJailBlocks - } - return 0 -} - func (m *Params) GetAppRegistrationFee() types.Coin { if m != nil { return m.AppRegistrationFee @@ -116,34 +107,33 @@ func init() { } var fileDescriptor_75a44aa904ae1ba5 = []byte{ - // 427 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0x4f, 0x6f, 0xd3, 0x30, - 0x18, 0x87, 0x13, 0x1a, 0xca, 0x14, 0x2e, 0x53, 0x68, 0x45, 0x19, 0xc8, 0xae, 0xbc, 0xcb, 0x24, - 0x24, 0x5b, 0x63, 0x9c, 0x76, 0x2c, 0x12, 0xd2, 0x7a, 0x40, 0x23, 0x70, 0x9a, 0x90, 0x22, 0xa7, - 0x35, 0x9d, 0xc1, 0xb1, 0xad, 0xd8, 0xab, 0x16, 0x3e, 0x05, 0x47, 0x8e, 0x7c, 0x9c, 0x1d, 0x77, - 0xe4, 0x14, 0xa1, 0xf6, 0x03, 0x20, 0xe5, 0x13, 0xa0, 0x3a, 0x7f, 0x28, 0x53, 0x77, 0xb3, 0x7f, - 0xef, 0xe3, 0xc7, 0xaf, 0xf4, 0xbe, 0xe1, 0xcb, 0x79, 0x91, 0x31, 0x69, 0xb8, 0x92, 0xd7, 0xc5, - 0x37, 0xd2, 0x5d, 0x48, 0xae, 0x84, 0xa0, 0x5a, 0x13, 0x4d, 0x73, 0x9a, 0x19, 0xac, 0x73, 0x65, - 0x55, 0x04, 0xb6, 0x61, 0xdc, 0x5d, 0x70, 0x03, 0x1f, 0x0c, 0x16, 0x6a, 0xa1, 0x1c, 0x4a, 0x36, - 0xa7, 0xfa, 0xd5, 0x01, 0x98, 0x29, 0x93, 0x29, 0x43, 0x52, 0x6a, 0x18, 0x59, 0x1e, 0xa7, 0xcc, - 0xd2, 0x63, 0x32, 0x53, 0x5c, 0xd6, 0x75, 0xf4, 0xa7, 0x17, 0xf6, 0xcf, 0xdd, 0x37, 0xd1, 0xa7, - 0x70, 0x34, 0xe7, 0x46, 0x5f, 0x59, 0x96, 0x68, 0x96, 0x73, 0x35, 0x4f, 0xb8, 0x4c, 0x52, 0xa1, - 0x66, 0x5f, 0xcd, 0xc8, 0x1f, 0xfb, 0x47, 0xc1, 0xe4, 0xb0, 0x2a, 0x21, 0x2c, 0x68, 0x26, 0x4e, - 0xd1, 0x7d, 0x24, 0x8a, 0x87, 0x4d, 0xe9, 0xdc, 0x55, 0xce, 0xe4, 0xc4, 0xe5, 0xd1, 0xc7, 0x70, - 0x28, 0xf8, 0x92, 0x49, 0x66, 0x4c, 0x62, 0x04, 0x35, 0x97, 0xad, 0x3a, 0x70, 0xea, 0x71, 0x55, - 0xc2, 0x17, 0xb5, 0x7a, 0x27, 0x86, 0xe2, 0x27, 0x6d, 0xfe, 0x61, 0x13, 0x37, 0xd6, 0x8b, 0xf0, - 0xe9, 0x1d, 0x9c, 0x4b, 0xcb, 0xf2, 0x25, 0x15, 0xa3, 0x87, 0xce, 0x8b, 0xaa, 0x12, 0x82, 0x9d, - 0xde, 0x16, 0x44, 0xf1, 0xf0, 0x3f, 0xf3, 0x59, 0x93, 0x47, 0xef, 0xc3, 0x41, 0xf7, 0xe4, 0x0b, - 0xe5, 0xa2, 0x6d, 0xb8, 0xef, 0xc4, 0xb0, 0x2a, 0xe1, 0xf3, 0x3b, 0xe2, 0x2d, 0x0a, 0xc5, 0x51, - 0x1b, 0x4f, 0x29, 0x17, 0x4d, 0xbb, 0x3a, 0x1c, 0x50, 0xad, 0x93, 0x9c, 0x2d, 0xb8, 0xb1, 0x39, - 0xb5, 0x5c, 0xc9, 0xe4, 0x33, 0x63, 0xa3, 0x47, 0x63, 0xff, 0xe8, 0xf1, 0xab, 0x67, 0xb8, 0x1e, - 0x16, 0xde, 0x0c, 0x0b, 0x37, 0xc3, 0xc2, 0x6f, 0x14, 0x97, 0x93, 0xc3, 0x9b, 0x12, 0x7a, 0xff, - 0x7e, 0xdc, 0x25, 0x41, 0x71, 0x44, 0xb5, 0x8e, 0xb7, 0xd2, 0xb7, 0x8c, 0x9d, 0x06, 0x3f, 0x7e, - 0x42, 0x6f, 0x1a, 0xec, 0x3d, 0xd8, 0xef, 0x4d, 0x83, 0xbd, 0xde, 0x7e, 0x30, 0x79, 0x77, 0xb3, - 0x02, 0xfe, 0xed, 0x0a, 0xf8, 0xbf, 0x57, 0xc0, 0xff, 0xbe, 0x06, 0xde, 0xed, 0x1a, 0x78, 0xbf, - 0xd6, 0xc0, 0xbb, 0x78, 0xbd, 0xe0, 0xf6, 0xf2, 0x2a, 0xc5, 0x33, 0x95, 0x91, 0x7b, 0x36, 0x73, - 0x79, 0x42, 0xae, 0xbb, 0xf5, 0xb4, 0x85, 0x66, 0x26, 0xed, 0xbb, 0x45, 0x3a, 0xf9, 0x1b, 0x00, - 0x00, 0xff, 0xff, 0xd4, 0xcf, 0x4a, 0xc3, 0xcd, 0x02, 0x00, 0x00, + // 405 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0x92, 0x41, 0x8b, 0xd3, 0x40, + 0x14, 0xc7, 0x13, 0x1b, 0xbb, 0x25, 0x5e, 0x4a, 0xdc, 0x62, 0x5c, 0x65, 0x52, 0xb2, 0x97, 0x05, + 0x61, 0x86, 0x75, 0x3d, 0xf5, 0x18, 0x41, 0x68, 0x0f, 0x52, 0xa2, 0xa7, 0x22, 0x84, 0x49, 0x3a, + 0xa6, 0x83, 0xc9, 0xcc, 0x90, 0x99, 0x86, 0xc6, 0x4f, 0xe1, 0xd1, 0xa3, 0xf8, 0x69, 0x7a, 0xec, + 0xd1, 0x53, 0x90, 0xf6, 0x1b, 0xe4, 0x13, 0x48, 0x93, 0xb4, 0xd4, 0xa5, 0xbd, 0xe5, 0xfd, 0xdf, + 0x2f, 0xbf, 0x07, 0x6f, 0x9e, 0xf9, 0x66, 0x5e, 0xa4, 0x84, 0x49, 0xca, 0xd9, 0xaa, 0xf8, 0x8e, + 0x8e, 0x05, 0xca, 0x78, 0x92, 0x60, 0x21, 0x90, 0xc0, 0x19, 0x4e, 0x25, 0x14, 0x19, 0x57, 0xdc, + 0x02, 0xa7, 0x30, 0x3c, 0x16, 0xb0, 0x85, 0x6f, 0xae, 0x63, 0x1e, 0xf3, 0x1a, 0x45, 0xfb, 0xaf, + 0xe6, 0xaf, 0x1b, 0x10, 0x71, 0x99, 0x72, 0x89, 0x42, 0x2c, 0x09, 0xca, 0xef, 0x43, 0xa2, 0xf0, + 0x3d, 0x8a, 0x38, 0x65, 0x4d, 0xdf, 0xfd, 0xdd, 0x31, 0xbb, 0xd3, 0x7a, 0x8c, 0xf5, 0xc5, 0xb4, + 0xe7, 0x54, 0x8a, 0xa5, 0x22, 0x81, 0x20, 0x19, 0xe5, 0xf3, 0x80, 0xb2, 0x20, 0x4c, 0x78, 0xf4, + 0x4d, 0xda, 0xfa, 0x50, 0xbf, 0x33, 0xbc, 0xdb, 0xaa, 0x74, 0x9c, 0x02, 0xa7, 0xc9, 0xc8, 0xbd, + 0x44, 0xba, 0xfe, 0xa0, 0x6d, 0x4d, 0xeb, 0xce, 0x98, 0x79, 0x75, 0x6e, 0x7d, 0x36, 0x07, 0x09, + 0xcd, 0x09, 0x23, 0x52, 0x06, 0x32, 0xc1, 0x72, 0x71, 0x50, 0x1b, 0xb5, 0x7a, 0x58, 0x95, 0xce, + 0xeb, 0x46, 0x7d, 0x16, 0x73, 0xfd, 0xe7, 0x87, 0xfc, 0xd3, 0x3e, 0x6e, 0xad, 0x33, 0xf3, 0xc5, + 0x23, 0x9c, 0x32, 0x45, 0xb2, 0x1c, 0x27, 0xf6, 0xd3, 0xda, 0xeb, 0x56, 0xa5, 0x03, 0xce, 0x7a, + 0x0f, 0xa0, 0xeb, 0x0f, 0xfe, 0x33, 0x8f, 0xdb, 0xdc, 0x12, 0xe6, 0x35, 0x16, 0x22, 0xc8, 0x48, + 0x4c, 0xa5, 0xca, 0xb0, 0xa2, 0x9c, 0x05, 0x5f, 0x09, 0xb1, 0xaf, 0x86, 0xfa, 0xdd, 0xb3, 0xb7, + 0x2f, 0x61, 0xb3, 0x59, 0xb8, 0xdf, 0x2c, 0x6c, 0x37, 0x0b, 0xdf, 0x73, 0xca, 0xbc, 0xdb, 0x75, + 0xe9, 0x68, 0x55, 0xe9, 0xbc, 0x6a, 0xe6, 0x9e, 0x93, 0xb8, 0xbe, 0x85, 0x85, 0xf0, 0x4f, 0xd2, + 0x0f, 0x84, 0x8c, 0x8c, 0x9f, 0xbf, 0x1c, 0x6d, 0x62, 0xf4, 0x9e, 0xf4, 0x3b, 0x13, 0xa3, 0xd7, + 0xe9, 0x1b, 0x13, 0xa3, 0xd7, 0xed, 0x5f, 0x79, 0x1f, 0xd7, 0x5b, 0xa0, 0x6f, 0xb6, 0x40, 0xff, + 0xbb, 0x05, 0xfa, 0x8f, 0x1d, 0xd0, 0x36, 0x3b, 0xa0, 0xfd, 0xd9, 0x01, 0x6d, 0xf6, 0x2e, 0xa6, + 0x6a, 0xb1, 0x0c, 0x61, 0xc4, 0x53, 0x74, 0xe1, 0x98, 0xf2, 0x07, 0xb4, 0x3a, 0x5e, 0x94, 0x2a, + 0x04, 0x91, 0x61, 0xb7, 0x7e, 0xfb, 0x87, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xd8, 0x08, + 0x19, 0x80, 0x02, 0x00, 0x00, } func (m *Params) Marshal() (dAtA []byte, err error) { @@ -176,11 +166,6 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { } i-- dAtA[i] = 0x3a - if m.LivenessJailBlocks != 0 { - i = encodeVarintParams(dAtA, i, uint64(m.LivenessJailBlocks)) - i-- - dAtA[i] = 0x30 - } if m.LivenessSlashInterval != 0 { i = encodeVarintParams(dAtA, i, uint64(m.LivenessSlashInterval)) i-- @@ -225,9 +210,6 @@ func (m *Params) Size() (n int) { if m.LivenessSlashInterval != 0 { n += 1 + sovParams(uint64(m.LivenessSlashInterval)) } - if m.LivenessJailBlocks != 0 { - n += 1 + sovParams(uint64(m.LivenessJailBlocks)) - } l = m.AppRegistrationFee.Size() n += 1 + l + sovParams(uint64(l)) return n @@ -325,25 +307,6 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } - case 6: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field LivenessJailBlocks", wireType) - } - m.LivenessJailBlocks = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowParams - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.LivenessJailBlocks |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } case 7: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field AppRegistrationFee", wireType) diff --git a/x/rollapp/types/rollapp.go b/x/rollapp/types/rollapp.go index 21916cfb5..6b8bbc217 100644 --- a/x/rollapp/types/rollapp.go +++ b/x/rollapp/types/rollapp.go @@ -51,10 +51,6 @@ func NewRollapp( } } -func (r Rollapp) LastStateUpdateHeightIsSet() bool { - return r.LastStateUpdateHeight != 0 -} - func (r Rollapp) ValidateBasic() error { _, err := sdk.AccAddressFromBech32(r.Owner) if err != nil { diff --git a/x/sequencer/client/cli/tx.go b/x/sequencer/client/cli/tx.go index 7dbd12aed..5c523f561 100644 --- a/x/sequencer/client/cli/tx.go +++ b/x/sequencer/client/cli/tx.go @@ -9,6 +9,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/sdk-utils/utils/ucli" "github.com/spf13/cobra" "github.com/dymensionxyz/dymension/v3/utils" @@ -32,6 +33,8 @@ func GetTxCmd() *cobra.Command { cmd.AddCommand(CmdUnbond()) cmd.AddCommand(CmdIncreaseBond()) cmd.AddCommand(CmdDecreaseBond()) + cmd.AddCommand(CmdKickProposer()) + cmd.AddCommand(CmdUpdateOptInStatus()) return cmd } @@ -196,10 +199,54 @@ func CmdUpdateWhitelistedRelayers() *cobra.Command { return cmd } +func CmdKickProposer() *cobra.Command { + cmd := &cobra.Command{ + Use: "kick", + Short: "Try to kick the current proposer", + Args: cobra.ExactArgs(0), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgKickProposer(clientCtx.GetFromAddress().String()) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + +func CmdUpdateOptInStatus() *cobra.Command { + cmd := &cobra.Command{ + Use: "opt-in [bool]", + Short: "Opt in or out of becoming selected as proposer or successor", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + msg := types.NewMsgUpdateOptInStatus(clientCtx.GetFromAddress().String(), ucli.Affirmative(args[0])) + + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + return cmd +} + func CmdUnbond() *cobra.Command { cmd := &cobra.Command{ Use: "unbond", - Short: "Unbond the sequencer", + Short: "Try to unbond the sequencer totally", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) (err error) { clientCtx, err := client.GetClientTxContext(cmd) @@ -207,9 +254,7 @@ func CmdUnbond() *cobra.Command { return err } - msg := types.NewMsgUnbond( - clientCtx.GetFromAddress().String(), - ) + msg := types.NewMsgUnbond(clientCtx.GetFromAddress().String()) return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) }, diff --git a/x/sequencer/genesis.go b/x/sequencer/genesis.go index cead5f647..05805eb7d 100644 --- a/x/sequencer/genesis.go +++ b/x/sequencer/genesis.go @@ -6,39 +6,35 @@ import ( "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) -// InitGenesis initializes the sequencer module's state from a provided genesis -func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) { +func InitGenesis(ctx sdk.Context, k *keeper.Keeper, genState types.GenesisState) { k.SetParams(ctx, genState.Params) - // Set all the sequencer for _, elem := range genState.SequencerList { k.SetSequencer(ctx, elem) - - // Set the unbonding queue for the sequencer - if elem.Status == types.Unbonding { - k.AddSequencerToUnbondingQueue(ctx, &elem) - } else if elem.IsNoticePeriodInProgress() { - k.AddSequencerToNoticePeriodQueue(ctx, &elem) + if err := k.SetSequencerByDymintAddr(ctx, elem.MustProposerAddr(), elem.Address); err != nil { + panic(err) } } + for _, s := range genState.NoticeQueue { + seq := k.GetSequencer(ctx, s) + k.AddToNoticeQueue(ctx, seq) + } + for _, elem := range genState.GenesisProposers { k.SetProposer(ctx, elem.RollappId, elem.Address) } - - for _, bondReduction := range genState.BondReductions { - k.SetDecreasingBondQueue(ctx, bondReduction) + for _, elem := range genState.GenesisSuccessors { + k.SetSuccessor(ctx, elem.RollappId, elem.Address) } } -// ExportGenesis returns the sequencer module's exported genesis. -func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { +func ExportGenesis(ctx sdk.Context, k *keeper.Keeper) *types.GenesisState { genesis := types.GenesisState{} genesis.Params = k.GetParams(ctx) - genesis.SequencerList = k.GetAllSequencers(ctx) - genesis.BondReductions = k.GetAllBondReductions(ctx) + genesis.SequencerList = k.AllSequencers(ctx) - proposers := k.GetAllProposers(ctx) + proposers := k.AllProposers(ctx) for _, proposer := range proposers { genesis.GenesisProposers = append(genesis.GenesisProposers, types.GenesisProposer{ RollappId: proposer.RollappId, @@ -46,5 +42,21 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { }) } + elems := k.AllSuccessors(ctx) + for _, elem := range elems { + genesis.GenesisSuccessors = append(genesis.GenesisSuccessors, types.GenesisProposer{ + RollappId: elem.RollappId, + Address: elem.Address, + }) + } + + notice, err := k.NoticeQueue(ctx, nil) + if err != nil { + panic(err) + } + for _, seq := range notice { + genesis.NoticeQueue = append(genesis.NoticeQueue, seq.Address) + } + return &genesis } diff --git a/x/sequencer/genesis_test.go b/x/sequencer/genesis_test.go index 52a41ddf2..113678476 100644 --- a/x/sequencer/genesis_test.go +++ b/x/sequencer/genesis_test.go @@ -4,14 +4,25 @@ import ( "testing" "time" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" "github.com/dymensionxyz/dymension/v3/x/sequencer" "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) +func anyPk(pk cryptotypes.PubKey) *codectypes.Any { + pkAny, err := codectypes.NewAnyWithValue(pk) + if err != nil { + panic(err) + } + return pkAny +} + func TestInitGenesis(t *testing.T) { timeToTest := time.Now().Round(0).UTC() @@ -22,69 +33,73 @@ func TestInitGenesis(t *testing.T) { // rollapp 1 // bonded - no tokens { - Address: "rollapp1_addr1", - RollappId: "rollapp1", - Status: types.Bonded, - Tokens: sdk.Coins(nil), + Address: "rollapp1_addr1", + RollappId: "rollapp1", + Status: types.Bonded, + Tokens: sdk.Coins(nil), + DymintPubKey: anyPk(ed25519.GenPrivKey().PubKey()), }, // bonded - 100 dym { - Address: "rollapp1_addr2", - RollappId: "rollapp1", - Status: types.Bonded, - Tokens: sdk.NewCoins(sdk.NewCoin("dym", sdk.NewInt(100))), - }, - // unbonding - { - Address: "rollapp1_addr3", - RollappId: "rollapp1", - Status: types.Unbonding, - Tokens: sdk.Coins(nil), - UnbondRequestHeight: 10, - UnbondTime: timeToTest, + Address: "rollapp1_addr2", + RollappId: "rollapp1", + Status: types.Bonded, + Tokens: sdk.NewCoins(sdk.NewCoin("dym", sdk.NewInt(100))), + DymintPubKey: anyPk(ed25519.GenPrivKey().PubKey()), }, + // unbonded { - Address: "rollapp1_addr4", - RollappId: "rollapp1", - Status: types.Unbonded, - Tokens: sdk.Coins(nil), + Address: "rollapp1_addr4", + RollappId: "rollapp1", + Status: types.Unbonded, + Tokens: sdk.Coins(nil), + DymintPubKey: anyPk(ed25519.GenPrivKey().PubKey()), }, // rollapp 2 { - Address: "rollapp2_addr1", - RollappId: "rollapp2", - Status: types.Bonded, - Tokens: sdk.Coins(nil), + Address: "rollapp2_addr1", + RollappId: "rollapp2", + Status: types.Bonded, + Tokens: sdk.Coins(nil), + DymintPubKey: anyPk(ed25519.GenPrivKey().PubKey()), }, - // unbonding + + // rollapp 3 + // proposer with notice period { - Address: "rollapp2_addr2", - RollappId: "rollapp2", - Status: types.Unbonding, - Tokens: sdk.Coins(nil), - UnbondRequestHeight: 10, - UnbondTime: timeToTest, + Address: "rollapp3_addr1", + RollappId: "rollapp3", + Status: types.Bonded, + Tokens: sdk.Coins(nil), + NoticePeriodTime: timeToTest, + DymintPubKey: anyPk(ed25519.GenPrivKey().PubKey()), }, - // rollapp 3 + // rollapp 4 // proposer with notice period { - Address: "rollapp3_addr1", - RollappId: "rollapp3", - Status: types.Bonded, - Tokens: sdk.Coins(nil), - UnbondRequestHeight: 20, - NoticePeriodTime: timeToTest, + Address: "rollapp4_addr1", + RollappId: "rollapp4", + Status: types.Bonded, + Tokens: sdk.Coins(nil), + NoticePeriodTime: timeToTest, + DymintPubKey: anyPk(ed25519.GenPrivKey().PubKey()), }, }, - BondReductions: []types.BondReduction{ + + GenesisProposers: []types.GenesisProposer{ { - SequencerAddress: "rollapp1_addr1", - DecreaseBondAmount: sdk.NewCoin("dym", sdk.NewInt(100)), - DecreaseBondTime: timeToTest, + Address: "rollapp1_addr1", + RollappId: "rollapp1", + }, + { + Address: "rollapp3_addr1", + RollappId: "rollapp3", }, + // rollapp2 has no proposer }, - GenesisProposers: []types.GenesisProposer{ + + GenesisSuccessors: []types.GenesisProposer{ { Address: "rollapp1_addr1", RollappId: "rollapp1", @@ -95,23 +110,22 @@ func TestInitGenesis(t *testing.T) { }, // rollapp2 has no proposer }, + + NoticeQueue: []string{"rollapp3_addr1", "rollapp4_addr1"}, } // change the params for assertion genesisState.Params.NoticePeriod = 100 k, ctx := keepertest.SequencerKeeper(t) - sequencer.InitGenesis(ctx, *k, genesisState) - - require.Len(t, k.GetMatureNoticePeriodSequencers(ctx, timeToTest), 1) - require.Len(t, k.GetMatureUnbondingSequencers(ctx, timeToTest), 2) - require.Len(t, k.GetAllProposers(ctx), 2) - require.Len(t, k.GetAllBondReductions(ctx), 1) + sequencer.InitGenesis(ctx, k, genesisState) - got := sequencer.ExportGenesis(ctx, *k) + got := sequencer.ExportGenesis(ctx, k) require.NotNil(t, got) + require.Equal(t, genesisState.Params, got.Params) require.ElementsMatch(t, genesisState.SequencerList, got.SequencerList) require.ElementsMatch(t, genesisState.GenesisProposers, got.GenesisProposers) - require.ElementsMatch(t, genesisState.BondReductions, got.BondReductions) + require.ElementsMatch(t, genesisState.GenesisSuccessors, got.GenesisSuccessors) + require.ElementsMatch(t, genesisState.NoticeQueue, got.NoticeQueue) } diff --git a/x/sequencer/handler.go b/x/sequencer/handler.go index 2cf9fdc03..da57555b7 100644 --- a/x/sequencer/handler.go +++ b/x/sequencer/handler.go @@ -3,15 +3,15 @@ package sequencer import ( "fmt" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) // NewHandler ... -func NewHandler(k keeper.Keeper) sdk.Handler { +func NewHandler(k *keeper.Keeper) sdk.Handler { msgServer := keeper.NewMsgServerImpl(k) return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { @@ -35,7 +35,7 @@ func NewHandler(k keeper.Keeper) sdk.Handler { return sdk.WrapServiceResult(ctx, res, err) default: errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg) - return nil, errorsmod.Wrap(types.ErrUnknownRequest, errMsg) + return nil, gerrc.ErrInvalidArgument.Wrap(errMsg) } } } diff --git a/x/sequencer/keeper/bond.go b/x/sequencer/keeper/bond.go new file mode 100644 index 000000000..e8731f757 --- /dev/null +++ b/x/sequencer/keeper/bond.go @@ -0,0 +1,69 @@ +package keeper + +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" +) + +// UnbondBlocker allows vetoing unbond attempts +type UnbondBlocker interface { + // CanUnbond should return a types.UnbondNotAllowed error with a reason, or nil (or another error) + CanUnbond(ctx sdk.Context, sequencer types.Sequencer) error +} + +// TryUnbond will try to either partially or totally unbond a sequencer. +// The sequencer may not be allowed to unbond, based on certain conditions. +// A partial unbonding refunds tokens, but doesn't allow the remaining bond to fall below a threshold. +// A total unbond refunds all tokens and changes status to unbonded. +func (k Keeper) TryUnbond(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coin) error { + if k.IsProposer(ctx, *seq) || k.IsSuccessor(ctx, *seq) { + return types.ErrUnbondProposerOrSuccessor + } + for _, c := range k.unbondBlockers { + if err := c.CanUnbond(ctx, *seq); err != nil { + return errorsmod.Wrap(err, "other module") + } + } + bond := seq.TokensCoin() + minBond := k.GetParams(ctx).MinBond + maxReduction, _ := bond.SafeSub(minBond) + isPartial := !amt.IsEqual(bond) + if isPartial && maxReduction.IsLT(amt) { + return errorsmod.Wrapf(types.ErrUnbondNotAllowed, + "attempted reduction: %s, max reduction: %s", + amt, ucoin.NonNegative(maxReduction), + ) + } + if err := k.refund(ctx, seq, amt); err != nil { + return errorsmod.Wrap(err, "refund") + } + if seq.Tokens.IsZero() { + return errorsmod.Wrap(k.unbond(ctx, seq), "unbond") + } + 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`) + } + seq.Status = types.Unbonded + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeUnbonded, + 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/bond_reductions.go b/x/sequencer/keeper/bond_reductions.go deleted file mode 100644 index fd8ce3773..000000000 --- a/x/sequencer/keeper/bond_reductions.go +++ /dev/null @@ -1,160 +0,0 @@ -package keeper - -import ( - "time" - - errorsmod "cosmossdk.io/errors" - "github.com/cosmos/cosmos-sdk/store/prefix" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" - "github.com/osmosis-labs/osmosis/v15/osmoutils" -) - -func (k Keeper) HandleBondReduction(ctx sdk.Context, currTime time.Time) { - bondReductionIDs := k.GetMatureDecreasingBondIDs(ctx, currTime) - for _, bondReductionID := range bondReductionIDs { - wrapFn := func(ctx sdk.Context) error { - return k.completeBondReduction(ctx, bondReductionID) - } - err := osmoutils.ApplyFuncIfNoError(ctx, wrapFn) - if err != nil { - k.Logger(ctx).Error("reducing sequencer bond", "error", err, "bond reduction ID", bondReductionID) - continue - } - } -} - -func (k Keeper) completeBondReduction(ctx sdk.Context, bondReductionID uint64) error { - reduction, found := k.GetBondReduction(ctx, bondReductionID) - if !found { - return errorsmod.Wrapf( - types.ErrUnknownBondReduction, - "bond reduction ID %d not found", - bondReductionID, - ) - } - seq := k.MustGetSequencer(ctx, reduction.SequencerAddress) - - if !seq.Tokens.IsAllGTE(sdk.NewCoins(reduction.DecreaseBondAmount)) { - return errorsmod.Wrapf( - types.ErrInsufficientBond, - "sequencer does not have enough bond to reduce insufficient bond: got %s, reducing by %s", - seq.Tokens.String(), - reduction.DecreaseBondAmount.String(), - ) - } - newBalance := seq.Tokens.Sub(reduction.DecreaseBondAmount) - // in case between unbonding queue and now, the minbond value is increased, - // handle it by only returning upto minBond amount and not all - minBond := k.GetParams(ctx).MinBond - if !newBalance.IsAllGTE(sdk.NewCoins(minBond)) { - diff := minBond.SubAmount(newBalance.AmountOf(minBond.Denom)) - reduction.DecreaseBondAmount = reduction.DecreaseBondAmount.Sub(diff) - } - seqAddr := sdk.MustAccAddressFromBech32(reduction.SequencerAddress) - err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, seqAddr, sdk.NewCoins(reduction.DecreaseBondAmount)) - if err != nil { - return err - } - - seq.Tokens = seq.Tokens.Sub(reduction.DecreaseBondAmount) - k.SetSequencer(ctx, seq) - k.removeBondReduction(ctx, bondReductionID, reduction) - - return nil -} - -// GetMatureDecreasingBondIDs returns all decreasing bond IDs for the given time -func (k Keeper) GetMatureDecreasingBondIDs(ctx sdk.Context, endTime time.Time) (bondReductionIDs []uint64) { - store := ctx.KVStore(k.storeKey) - iterator := store.Iterator(types.DecreasingBondQueueKey, sdk.PrefixEndBytes(types.DecreasingBondQueueByTimeKey(endTime))) - defer iterator.Close() // nolint: errcheck - for ; iterator.Valid(); iterator.Next() { - bondReductionID := sdk.BigEndianToUint64(iterator.Value()) - bondReductionIDs = append(bondReductionIDs, bondReductionID) - } - return -} - -// SetDecreasingBondQueue sets the bond reduction item in the decreasing bond queue -func (k Keeper) SetDecreasingBondQueue(ctx sdk.Context, bondReduction types.BondReduction) { - store := ctx.KVStore(k.storeKey) - bondReductionID := k.increamentDecreasingBondID(ctx) - b := k.cdc.MustMarshal(&bondReduction) - store.Set(types.GetDecreasingBondQueueKey(bondReduction.SequencerAddress, bondReduction.DecreaseBondTime), sdk.Uint64ToBigEndian(bondReductionID)) - store.Set(append(types.GetDecreasingBondSequencerKey(bondReduction.SequencerAddress), sdk.Uint64ToBigEndian(bondReductionID)...), sdk.Uint64ToBigEndian(bondReductionID)) - store.Set(types.GetDecreasingBondIndexKey(bondReductionID), b) -} - -// GetBondReduction returns the bond reduction item given bond reduction ID -func (k Keeper) GetBondReduction(ctx sdk.Context, bondReductionID uint64) (types.BondReduction, bool) { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.GetDecreasingBondIndexKey(bondReductionID)) - if bz == nil { - return types.BondReduction{}, false - } - var bd types.BondReduction - k.cdc.MustUnmarshal(bz, &bd) - return bd, true -} - -func (k Keeper) GetAllBondReductions(ctx sdk.Context) (bds []types.BondReduction) { - store := ctx.KVStore(k.storeKey) - iterator := sdk.KVStorePrefixIterator(store, types.DecreasingBondIndexKey) - defer iterator.Close() // nolint: errcheck - for ; iterator.Valid(); iterator.Next() { - var bd types.BondReduction - k.cdc.MustUnmarshal(iterator.Value(), &bd) - bds = append(bds, bd) - } - return -} - -// removeBondReduction removes the bond reduction item from the decreasing bond queue -func (k Keeper) removeBondReduction(ctx sdk.Context, bondReductionID uint64, bondReduction types.BondReduction) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.GetDecreasingBondQueueKey(bondReduction.SequencerAddress, bondReduction.DecreaseBondTime)) - store.Delete(append(types.GetDecreasingBondSequencerKey(bondReduction.SequencerAddress), sdk.Uint64ToBigEndian(bondReductionID)...)) - store.Delete(types.GetDecreasingBondIndexKey(bondReductionID)) -} - -// GetBondReductionsBySequencer returns the bond reduction item given sequencer address -func (k Keeper) GetBondReductionsBySequencer(ctx sdk.Context, sequencerAddr string) (bondReductions []types.BondReduction) { - bondReductionIDs := k.getBondReductionIDsBySequencer(ctx, sequencerAddr) - for _, bondReductionID := range bondReductionIDs { - bd, found := k.GetBondReduction(ctx, bondReductionID) - if found { - bondReductions = append(bondReductions, bd) - } - } - return -} - -// getBondReductionIDsBySequencer returns the bond reduction item given sequencer address -func (k Keeper) getBondReductionIDsBySequencer(ctx sdk.Context, sequencerAddr string) (bondReductionIDs []uint64) { - prefixKey := types.GetDecreasingBondSequencerKey(sequencerAddr) - store := prefix.NewStore(ctx.KVStore(k.storeKey), prefixKey) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() // nolint: errcheck - - for ; iterator.Valid(); iterator.Next() { - bondReductionID := sdk.BigEndianToUint64(iterator.Value()) - bondReductionIDs = append(bondReductionIDs, bondReductionID) - } - return -} - -// increamentDecreasingBondID increments the decreasing bond ID anad returns the new ID -func (k Keeper) increamentDecreasingBondID(ctx sdk.Context) (decreasingBondID uint64) { - store := ctx.KVStore(k.storeKey) - bz := store.Get(types.GetDecreasingBondIDKey()) - if bz != nil { - decreasingBondID = sdk.BigEndianToUint64(bz) - } - decreasingBondID++ - - bz = sdk.Uint64ToBigEndian(decreasingBondID) - store.Set(types.GetDecreasingBondIDKey(), bz) - return -} diff --git a/x/sequencer/keeper/bond_reductions_test.go b/x/sequencer/keeper/bond_reductions_test.go deleted file mode 100644 index 46f2c05d2..000000000 --- a/x/sequencer/keeper/bond_reductions_test.go +++ /dev/null @@ -1,141 +0,0 @@ -package keeper_test - -import ( - "testing" - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" - "github.com/stretchr/testify/require" -) - -const ( - seq1 = "dym1wg8p6j0pxpnsvhkwfu54ql62cnrumf0v634mft" - seq2 = "dym1d0wlmz987qlurs6e3kc6zd25z6wsdmnwx8tafy" -) - -func TestGetMatureDecreasingBondIDs(t *testing.T) { - keeper, ctx := keepertest.SequencerKeeper(t) - - t.Run("No mature bonds", func(t *testing.T) { - ids := keeper.GetMatureDecreasingBondIDs(ctx, time.Now()) - require.Len(t, ids, 0) - }) - - t.Run("Mature bonds of multiple sequencers", func(t *testing.T) { - bondReductionTime := time.Now() - keeper.SetDecreasingBondQueue(ctx, types.BondReduction{ - SequencerAddress: seq1, - DecreaseBondTime: bondReductionTime, - DecreaseBondAmount: sdk.NewInt64Coin(sdk.DefaultBondDenom, 100), - }) - keeper.SetDecreasingBondQueue(ctx, types.BondReduction{ - SequencerAddress: seq2, - DecreaseBondTime: bondReductionTime, - DecreaseBondAmount: sdk.NewInt64Coin(sdk.DefaultBondDenom, 100), - }) - // Not mature - keeper.SetDecreasingBondQueue(ctx, types.BondReduction{ - SequencerAddress: seq2, - DecreaseBondTime: bondReductionTime.Add(time.Hour), - DecreaseBondAmount: sdk.NewInt64Coin(sdk.DefaultBondDenom, 100), - }) - - ids := keeper.GetMatureDecreasingBondIDs(ctx, bondReductionTime) - require.Len(t, ids, 2) - }) -} - -func TestGetBondReductionsBySequencer(t *testing.T) { - keeper, ctx := keepertest.SequencerKeeper(t) - - t.Run("No bond reductions", func(t *testing.T) { - ids := keeper.GetBondReductionsBySequencer(ctx, seq1) - require.Len(t, ids, 0) - }) - - t.Run("Bond reductions of multiple sequencers", func(t *testing.T) { - bondReductionTime := time.Now() - keeper.SetDecreasingBondQueue(ctx, types.BondReduction{ - SequencerAddress: seq1, - DecreaseBondTime: bondReductionTime, - DecreaseBondAmount: sdk.NewInt64Coin(sdk.DefaultBondDenom, 100), - }) - keeper.SetDecreasingBondQueue(ctx, types.BondReduction{ - SequencerAddress: seq2, - DecreaseBondTime: bondReductionTime, - DecreaseBondAmount: sdk.NewInt64Coin(sdk.DefaultBondDenom, 100), - }) - keeper.SetDecreasingBondQueue(ctx, types.BondReduction{ - SequencerAddress: seq2, - DecreaseBondTime: bondReductionTime.Add(time.Hour), - DecreaseBondAmount: sdk.NewInt64Coin(sdk.DefaultBondDenom, 100), - }) - - ids := keeper.GetBondReductionsBySequencer(ctx, seq1) - require.Len(t, ids, 1) - - ids = keeper.GetBondReductionsBySequencer(ctx, seq2) - require.Len(t, ids, 2) - }) -} - -func (suite *SequencerTestSuite) TestHandleBondReduction() { - suite.SetupTest() - bondDenom := types.DefaultParams().MinBond.Denom - rollappId, pk := suite.CreateDefaultRollapp() - // Create a sequencer with bond amount of minBond + 100 - defaultSequencerAddress := suite.CreateSequencerWithBond(suite.Ctx, rollappId, bond.AddAmount(sdk.NewInt(100)), pk) - resp, err := suite.msgServer.DecreaseBond(suite.Ctx, &types.MsgDecreaseBond{ - Creator: defaultSequencerAddress, - DecreaseAmount: sdk.NewInt64Coin(bondDenom, 50), - }) - suite.Require().NoError(err) - expectedCompletionTime := suite.Ctx.BlockHeader().Time.Add(suite.App.SequencerKeeper.UnbondingTime(suite.Ctx)) - suite.Require().Equal(expectedCompletionTime, resp.CompletionTime) - // Execute HandleBondReduction - suite.Ctx = suite.Ctx.WithBlockTime(expectedCompletionTime) - suite.App.SequencerKeeper.HandleBondReduction(suite.Ctx, suite.Ctx.BlockHeader().Time) - // Check if the bond has been reduced - sequencer, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, defaultSequencerAddress) - suite.Require().Equal(bond.AddAmount(sdk.NewInt(50)), sequencer.Tokens[0]) - // ensure the bond decresing queue is empty - reds := suite.App.SequencerKeeper.GetMatureDecreasingBondIDs(suite.Ctx, expectedCompletionTime) - suite.Require().Len(reds, 0) -} - -func (suite *SequencerTestSuite) TestHandleBondReduction_MinBondIncrease() { - suite.SetupTest() - bondDenom := types.DefaultParams().MinBond.Denom - rollappId, pk := suite.CreateDefaultRollapp() - // Create a sequencer with bond amount of minBond + 100 - defaultSequencerAddress := suite.CreateSequencerWithBond(suite.Ctx, rollappId, bond.AddAmount(sdk.NewInt(100)), pk) - resp, err := suite.msgServer.DecreaseBond(suite.Ctx, &types.MsgDecreaseBond{ - Creator: defaultSequencerAddress, - DecreaseAmount: sdk.NewInt64Coin(bondDenom, 50), - }) - suite.Require().NoError(err) - expectedCompletionTime := suite.Ctx.BlockHeader().Time.Add(suite.App.SequencerKeeper.UnbondingTime(suite.Ctx)) - suite.Require().Equal(expectedCompletionTime, resp.CompletionTime) - curBalance := suite.App.BankKeeper.GetBalance(suite.Ctx, sdk.MustAccAddressFromBech32(defaultSequencerAddress), bondDenom) - suite.Require().Equal(sdk.ZeroInt(), curBalance.Amount) - - // Increase the minBond param - params := suite.App.SequencerKeeper.GetParams(suite.Ctx) - params.MinBond = bond.AddAmount(sdk.NewInt(60)) - suite.App.SequencerKeeper.SetParams(suite.Ctx, params) - - // Execute HandleBondReduction - suite.Ctx = suite.Ctx.WithBlockTime(expectedCompletionTime) - suite.App.SequencerKeeper.HandleBondReduction(suite.Ctx, suite.Ctx.BlockHeader().Time) - // Check if the bond has been reduced - but is the same as new min bond value - sequencer, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, defaultSequencerAddress) - suite.Require().Equal(bond.AddAmount(sdk.NewInt(60)), sequencer.Tokens[0]) - // ensure the bond decresing queue is empty - reds := suite.App.SequencerKeeper.GetMatureDecreasingBondIDs(suite.Ctx, expectedCompletionTime) - suite.Require().Len(reds, 0) - // Ensure the bond has been refunded - curBalance = suite.App.BankKeeper.GetBalance(suite.Ctx, sdk.MustAccAddressFromBech32(defaultSequencerAddress), bondDenom) - suite.Require().Equal(sdk.NewInt(40), curBalance.Amount) -} diff --git a/x/sequencer/keeper/bond_test.go b/x/sequencer/keeper/bond_test.go new file mode 100644 index 000000000..2e2dd5fda --- /dev/null +++ b/x/sequencer/keeper/bond_test.go @@ -0,0 +1,26 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" +) + +type DummyBlocker struct { + called bool +} + +func (b *DummyBlocker) CanUnbond(ctx sdk.Context, sequencer types.Sequencer) error { + b.called = true + return nil +} + +// simple check that blocker is wired in +func (s *SequencerTestSuite) TestBondBlockers() { + ra := s.createRollapp() + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) + s.k().SetProposer(s.Ctx, ra.RollappId, pkAddr(bob)) // ensure alice is not proposer + db := DummyBlocker{} + s.k().SetUnbondBlockers(&db) + _ = s.k().TryUnbond(s.Ctx, &seq, seq.TokensCoin()) + s.Require().True(db.called) +} diff --git a/x/sequencer/keeper/fraud.go b/x/sequencer/keeper/fraud.go new file mode 100644 index 000000000..f37274103 --- /dev/null +++ b/x/sequencer/keeper/fraud.go @@ -0,0 +1,110 @@ +package keeper + +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" + "github.com/dymensionxyz/sdk-utils/utils/uevent" +) + +// 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 { + ra := kicker.RollappId + + proposer := k.GetProposer(ctx, ra) + + if !k.Kickable(ctx, proposer) { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "not kickable") + } + // FIXME: slash remaining funds if any? + if err := k.unbond(ctx, &proposer); err != nil { + return errorsmod.Wrap(err, "unbond") + } + k.SetSequencer(ctx, proposer) + + // This will call hard fork on the rollapp, which will also optOut all sequencers + k.hooks.AfterKickProposer(ctx, proposer) + + // optIn the kicker + if err := kicker.SetOptedIn(ctx, true); err != nil { + return errorsmod.Wrap(err, "set opted in") + } + k.SetSequencer(ctx, kicker) + + if err := uevent.EmitTypedEvent(ctx, &types.EventKickedProposer{ + Rollapp: ra, + Kicker: kicker.Address, + Proposer: proposer.Address, + }); err != nil { + return err + } + + // this will choose kicker as next proposer, since he is the only opted in and bonded + // sequencer remaining. + if err := k.UpdateProposerIfNeeded(ctx, ra); err != nil { + return errorsmod.Wrap(err, "choose proposer") + } + + return nil +} + +func (k Keeper) SlashLiveness(ctx sdk.Context, rollappID string) error { + seq := k.GetProposer(ctx, rollappID) + if seq.Sentinel() { + return nil + } + + // correct formula is e.g. min(sequencer tokens, max(1, sequencer tokens * 0.01 )) + + mul := k.GetParams(ctx).LivenessSlashMinMultiplier + abs := k.GetParams(ctx).LivenessSlashMinAbsolute + tokens := seq.TokensCoin() + tokensMul := ucoin.MulDec(mul, tokens) + amt := ucoin.SimpleMin(tokens, ucoin.SimpleMax(abs, tokensMul[0])) + err := errorsmod.Wrap(k.slash(ctx, &seq, amt, sdk.ZeroDec(), nil), "slash") + k.SetSequencer(ctx, seq) + return err +} + +func (k Keeper) PunishSequencer(ctx sdk.Context, seqAddr string) error { + seq, err := k.RealSequencer(ctx, seqAddr) + if err != nil { + return err + } + + err = k.slash(ctx, &seq, seq.TokensCoin(), sdk.ZeroDec(), nil) + if err != nil { + return errorsmod.Wrap(err, "slash") + } + err = k.unbond(ctx, &seq) + if err != nil { + return errorsmod.Wrap(err, "unbond") + } + + k.SetSequencer(ctx, seq) + return nil +} + +func (k Keeper) slash(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coin, rewardMul sdk.Dec, rewardee sdk.AccAddress) error { + rewardCoin := ucoin.MulDec(rewardMul, amt)[0] + if !rewardCoin.IsZero() { + err := k.sendFromModule(ctx, seq, rewardCoin, rewardee) + if err != nil { + return errorsmod.Wrap(err, "send") + } + } + remainder := amt.Sub(rewardCoin) + err := errorsmod.Wrap(k.burn(ctx, seq, remainder), "burn") + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeSlashed, + sdk.NewAttribute(types.AttributeKeySequencer, seq.Address), + sdk.NewAttribute(types.AttributeKeyRemainingAmt, seq.TokensCoin().String()), + sdk.NewAttribute(types.AttributeKeyAmt, amt.String()), + ), + ) + return err +} diff --git a/x/sequencer/keeper/fraud_test.go b/x/sequencer/keeper/fraud_test.go new file mode 100644 index 000000000..7440fd453 --- /dev/null +++ b/x/sequencer/keeper/fraud_test.go @@ -0,0 +1,113 @@ +package keeper_test + +import ( + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/sdk-utils/utils/ucoin" +) + +// Can eventually slash to below kickable threshold +func (s *SequencerTestSuite) TestSlashLivenessFlow() { + ra := s.createRollapp() + s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) + seq := s.seq(alice) + s.Require().True(s.k().IsProposer(s.Ctx, seq)) + + s.Require().False(s.k().Kickable(s.Ctx, seq)) + ok := false + last := seq.TokensCoin() + for range 100000000 { + err := s.k().SlashLiveness(s.Ctx, ra.RollappId) + s.Require().NoError(err) + s.Require().True(s.k().IsProposer(s.Ctx, seq)) + seq = s.seq(alice) + mod := s.moduleBalance() + s.Require().True(mod.Equal(seq.TokensCoin())) + s.Require().True(seq.TokensCoin().IsLT(last)) + if s.k().Kickable(s.Ctx, seq) { + ok = true + break + } + } + s.Require().True(ok) +} + +// check the basic properties and that funds are allocated to the right place +func (s *SequencerTestSuite) TestFraud() { + ra := s.createRollapp() + + s.Run("unbonded and not proposer anymore", 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().PunishSequencer(s.Ctx, seq.Address) + 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()) + }) + 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().PunishSequencer(s.Ctx, seq.Address) + s.Require().NoError(err) + + seq = s.seq(bob) + mod := s.moduleBalance() + s.Require().True(seq.TokensCoin().IsZero()) + s.Require().True(mod.Equal(seq.TokensCoin())) + }) +} + +// a full flow 'e2e' to make sure things are sensible +// There are many many different scenarios that could be tested +// Here pick one which might be typical/realistic +// 1. Sequencer is active +// 2. Sequencer is does notice and starts to rotate +// 3. Sequencer does a fraud +// 4. Another sequencer opts in and becomes proposer +func (s *SequencerTestSuite) TestFraudFullFlowDuringRotation() { + ra := s.createRollapp() + s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, ucoin.SimpleMul(bond, 3)) + s.createSequencerWithBond(s.Ctx, ra.RollappId, bob, ucoin.SimpleMul(bond, 2)) + s.createSequencerWithBond(s.Ctx, ra.RollappId, charlie, ucoin.SimpleMul(bond, 1)) + s.Require().True(s.k().IsProposer(s.Ctx, s.seq(alice))) + s.Require().False(s.k().IsSuccessor(s.Ctx, s.seq(bob))) + + // proposer tries to unbond + mUnbond := &types.MsgUnbond{Creator: pkAddr(alice)} + res, err := s.msgServer.Unbond(s.Ctx, mUnbond) + s.Require().NoError(err) + + // advance clock past notice + s.Require().True(res.GetNoticePeriodCompletionTime().After(s.Ctx.BlockTime())) + s.Ctx = s.Ctx.WithBlockTime(*res.GetNoticePeriodCompletionTime()) + + // notice period has now elapsed + err = s.k().ChooseSuccessorForFinishedNotices(s.Ctx, s.Ctx.BlockTime()) + s.Require().NoError(err) + s.Require().True(s.k().IsSuccessor(s.Ctx, s.seq(bob))) + + // instead of submitting last, proposer does a fraud + 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))) + s.Require().False(s.k().IsProposer(s.Ctx, s.seq(charlie))) + s.Require().False(s.k().IsSuccessor(s.Ctx, s.seq(charlie))) + s.Require().False(s.seq(bob).OptedIn) + s.Require().False(s.seq(charlie).OptedIn) + + mOptIn := &types.MsgUpdateOptInStatus{Creator: pkAddr(bob), OptedIn: true} + _, err = s.msgServer.UpdateOptInStatus(s.Ctx, mOptIn) + s.Require().NoError(err) + s.Require().True(s.seq(bob).OptedIn) + + s.Require().True(s.k().IsProposer(s.Ctx, s.seq(bob))) +} diff --git a/x/sequencer/keeper/funds.go b/x/sequencer/keeper/funds.go new file mode 100644 index 000000000..c8d6c252f --- /dev/null +++ b/x/sequencer/keeper/funds.go @@ -0,0 +1,55 @@ +package keeper + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" +) + +func (k Keeper) bondDenom(ctx sdk.Context) string { + return k.GetParams(ctx).MinBond.Denom +} + +func (k Keeper) validBondDenom(ctx sdk.Context, c sdk.Coin) error { + d := k.bondDenom(ctx) + if c.Denom != d { + return errorsmod.Wrapf(types.ErrInvalidDenom, "expect: %s", d) + } + return nil +} + +func (k Keeper) sufficientBond(ctx sdk.Context, c sdk.Coin) error { + if err := k.validBondDenom(ctx, c); err != nil { + return err + } + minBond := k.GetParams(ctx).MinBond + if c.IsLT(minBond) { + return errorsmod.Wrapf(types.ErrInsufficientBond, "min: %s", minBond.Amount) + } + return nil +} + +func (k Keeper) Kickable(ctx sdk.Context, proposer types.Sequencer) bool { + kickThreshold := k.GetParams(ctx).KickThreshold + return !proposer.Sentinel() && proposer.TokensCoin().IsLTE(kickThreshold) +} + +func (k Keeper) burn(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coin) error { + seq.SetTokensCoin(seq.TokensCoin().Sub(amt)) + return k.bankKeeper.BurnCoins(ctx, types.ModuleName, sdk.NewCoins(amt)) +} + +// Refund reduces the sequencer token balance by amt and refunds amt to the addr +func (k Keeper) refund(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coin) error { + return errorsmod.Wrap(k.sendFromModule(ctx, seq, amt, seq.AccAddr()), "send tokens") +} + +func (k Keeper) sendFromModule(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coin, recipient sdk.AccAddress) error { + seq.SetTokensCoin(seq.TokensCoin().Sub(amt)) + return k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, recipient, sdk.NewCoins(amt)) +} + +func (k Keeper) sendToModule(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coin) error { + seq.SetTokensCoin(seq.TokensCoin().Add(amt)) + return k.bankKeeper.SendCoinsFromAccountToModule(ctx, seq.AccAddr(), types.ModuleName, sdk.NewCoins(amt)) +} diff --git a/x/sequencer/keeper/get_and_set.go b/x/sequencer/keeper/get_and_set.go new file mode 100644 index 000000000..a4a9ea54b --- /dev/null +++ b/x/sequencer/keeper/get_and_set.go @@ -0,0 +1,191 @@ +package keeper + +import ( + "time" + + "cosmossdk.io/collections" + errorsmod "cosmossdk.io/errors" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + "github.com/cosmos/cosmos-sdk/store/prefix" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" +) + +// SetSequencer : write to store indexed by address, and also by status +// Note: do not call with sentinel sequencer +func (k Keeper) SetSequencer(ctx sdk.Context, seq types.Sequencer) { + store := ctx.KVStore(k.storeKey) + b := k.cdc.MustMarshal(&seq) + store.Set(types.SequencerKey(seq.Address), b) + + for _, status := range types.AllStatus { + oldKey := types.SequencerByRollappByStatusKey(seq.RollappId, seq.Address, status) + ctx.KVStore(k.storeKey).Delete(oldKey) + } + + seqByRollappKey := types.SequencerByRollappByStatusKey(seq.RollappId, seq.Address, seq.Status) + store.Set(seqByRollappKey, b) +} + +// SetSequencerByDymintAddr : allows reverse lookup of sequencer by dymint address +func (k Keeper) SetSequencerByDymintAddr(ctx sdk.Context, dymint cryptotypes.Address, addr string) error { + // could move this inside SetSequencer but it would require propogating error up a lot + return k.dymintProposerAddrToAccAddr.Set(ctx, dymint, addr) +} + +// SetProposer : passing sentinel is allowed +func (k Keeper) SetProposer(ctx sdk.Context, rollapp, seqAddr string) { + store := ctx.KVStore(k.storeKey) + addressBytes := []byte(seqAddr) + activeKey := types.ProposerByRollappKey(rollapp) + store.Set(activeKey, addressBytes) +} + +// SetSuccessor : passing sentinel is allowed +func (k Keeper) SetSuccessor(ctx sdk.Context, rollapp, seqAddr string) { + store := ctx.KVStore(k.storeKey) + addressBytes := []byte(seqAddr) + nextProposerKey := types.SuccessorByRollappKey(rollapp) + store.Set(nextProposerKey, addressBytes) +} + +func (k Keeper) AddToNoticeQueue(ctx sdk.Context, seq types.Sequencer) { + store := ctx.KVStore(k.storeKey) + noticePeriodKey := types.NoticeQueueBySeqTimeKey(seq.Address, seq.NoticePeriodTime) + store.Set(noticePeriodKey, []byte(seq.Address)) +} + +func (k Keeper) removeFromNoticeQueue(ctx sdk.Context, seq types.Sequencer) { + store := ctx.KVStore(k.storeKey) + noticePeriodKey := types.NoticeQueueBySeqTimeKey(seq.Address, seq.NoticePeriodTime) + store.Delete(noticePeriodKey) +} + +func (k Keeper) RollappSequencers(ctx sdk.Context, rollappId string) []types.Sequencer { + return k.prefixSequencers(ctx, types.SequencersByRollappKey(rollappId)) +} + +func (k Keeper) RollappSequencersByStatus(ctx sdk.Context, rollappId string, status types.OperatingStatus) []types.Sequencer { + return k.prefixSequencers(ctx, types.SequencersByRollappByStatusKey(rollappId, status)) +} + +func (k Keeper) RollappBondedSequencers(ctx sdk.Context, rollappId string) []types.Sequencer { + return k.RollappSequencersByStatus(ctx, rollappId, types.Bonded) +} + +func (k Keeper) AllSequencers(ctx sdk.Context) (list []types.Sequencer) { + return k.prefixSequencers(ctx, types.SequencersKeyPrefix) +} + +func (k Keeper) prefixSequencers(ctx sdk.Context, prefixKey []byte) []types.Sequencer { + store := prefix.NewStore(ctx.KVStore(k.storeKey), prefixKey) + it := sdk.KVStorePrefixIterator(store, []byte{}) + + defer it.Close() // nolint: errcheck + + ret := []types.Sequencer{} + for ; it.Valid(); it.Next() { + var val types.Sequencer + k.cdc.MustUnmarshal(it.Value(), &val) + ret = append(ret, val) + } + + return ret +} + +// GetSequencer returns the sentinel sequencer if not found. Use GetRealSequencer if expecting +// to get a real sequencer. +func (k Keeper) GetSequencer(ctx sdk.Context, addr string) types.Sequencer { + seq, err := k.RealSequencer(ctx, addr) + if err != nil { + return k.SentinelSequencer(ctx) + } + return seq +} + +// RealSequencer tries to get a real (non sentinel) sequencer. +func (k Keeper) RealSequencer(ctx sdk.Context, addr string) (types.Sequencer, error) { + store := ctx.KVStore(k.storeKey) + b := store.Get(types.SequencerKey(addr)) + if b == nil { + return types.Sequencer{}, types.ErrSequencerNotFound + } + ret := types.Sequencer{} + k.cdc.MustUnmarshal(b, &ret) + return ret, nil +} + +func (k Keeper) SequencerByDymintAddr(ctx sdk.Context, addr cryptotypes.Address) (types.Sequencer, error) { + accAddr, err := k.dymintProposerAddrToAccAddr.Get(ctx, addr) + if err != nil { + if errorsmod.IsOf(err, collections.ErrNotFound) { + return types.Sequencer{}, gerrc.ErrNotFound + } + return types.Sequencer{}, err + } + return k.RealSequencer(ctx, accAddr) +} + +func (k Keeper) AllProposers(ctx sdk.Context) (list []types.Sequencer) { + return k.prefixSequencerAddrs(ctx, types.ProposerByRollappKey("")) +} + +func (k Keeper) AllSuccessors(ctx sdk.Context) []types.Sequencer { + return k.prefixSequencerAddrs(ctx, types.SuccessorByRollappKey("")) +} + +func (k Keeper) prefixSequencerAddrs(ctx sdk.Context, pref []byte) []types.Sequencer { + store := prefix.NewStore(ctx.KVStore(k.storeKey), pref) + iterator := sdk.KVStorePrefixIterator(store, []byte{}) + defer iterator.Close() // nolint: errcheck + ret := []types.Sequencer{} + for ; iterator.Valid(); iterator.Next() { + address := string(iterator.Value()) + seq := k.GetSequencer(ctx, address) + ret = append(ret, seq) + } + return ret +} + +func (k Keeper) GetProposer(ctx sdk.Context, rollapp string) types.Sequencer { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ProposerByRollappKey(rollapp)) + if bz == nil { + return k.SentinelSequencer(ctx) + } + return k.GetSequencer(ctx, string(bz)) +} + +func (k Keeper) GetSuccessor(ctx sdk.Context, rollapp string) types.Sequencer { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.SuccessorByRollappKey(rollapp)) + if bz == nil { + return k.SentinelSequencer(ctx) + } + return k.GetSequencer(ctx, string(bz)) +} + +// NoticeQueue - the entire notice queue +func (k Keeper) NoticeQueue(ctx sdk.Context, endTime *time.Time) ([]types.Sequencer, error) { + ret := []types.Sequencer{} + store := ctx.KVStore(k.storeKey) + prefix := types.NoticePeriodQueueKey + if endTime != nil { + prefix = types.NoticeQueueByTimeKey(*endTime) + } + iterator := store.Iterator(types.NoticePeriodQueueKey, sdk.PrefixEndBytes(prefix)) + + defer iterator.Close() // nolint: errcheck + + for ; iterator.Valid(); iterator.Next() { + addr := string(iterator.Value()) + seq, err := k.RealSequencer(ctx, string(iterator.Value())) + if err != nil { + return nil, gerrc.ErrInternal.Wrapf("sequencer in notice queue but missing sequencer object: addr: %s", addr) + } + ret = append(ret, seq) + } + + return ret, nil +} diff --git a/x/sequencer/keeper/get_and_set_test.go b/x/sequencer/keeper/get_and_set_test.go new file mode 100644 index 000000000..8fe200a32 --- /dev/null +++ b/x/sequencer/keeper/get_and_set_test.go @@ -0,0 +1,57 @@ +package keeper_test + +import ( + "testing" + + _ "github.com/cosmos/cosmos-sdk/crypto/codec" + keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" + "github.com/dymensionxyz/dymension/v3/testutil/nullify" + "github.com/stretchr/testify/require" +) + +func TestSequencerGet(t *testing.T) { + k, ctx := keepertest.SequencerKeeper(t) + items := createNSequencers(k, ctx, 10) + for _, item := range items { + item := item + rst, err := k.RealSequencer(ctx, + item.Address, + ) + require.NoError(t, err) + require.Equal(t, + nullify.Fill(&item), + nullify.Fill(&rst), + ) + } +} + +func TestSequencerGetAll(t *testing.T) { + k, ctx := keepertest.SequencerKeeper(t) + items := createNSequencers(k, ctx, 10) + require.ElementsMatch(t, + nullify.Fill(items), + nullify.Fill(k.AllSequencers(ctx)), + ) +} + +func TestSequencersByRollappGet(t *testing.T) { + k, ctx := keepertest.SequencerKeeper(t) + items := createNSequencers(k, ctx, 10) + rst := k.RollappSequencers(ctx, + items[0].RollappId, + ) + + require.Equal(t, len(rst), len(items)) + require.ElementsMatch(t, + nullify.Fill(items), + nullify.Fill(rst), + ) +} + +func (s *SequencerTestSuite) TestByProposerAddr() { + ra := s.createRollapp() + seqExp := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) + seqGot, err := s.k().SequencerByDymintAddr(s.Ctx, seqExp.MustProposerAddr()) + s.Require().NoError(err) + s.Require().Equal(seqExp.Address, seqGot.Address) +} diff --git a/x/sequencer/keeper/grpc_query_params_test.go b/x/sequencer/keeper/grpc_query_params_test.go index f1ce68fdc..0b8ab4280 100644 --- a/x/sequencer/keeper/grpc_query_params_test.go +++ b/x/sequencer/keeper/grpc_query_params_test.go @@ -14,7 +14,6 @@ func TestParamsQuery(t *testing.T) { keeper, ctx := testkeeper.SequencerKeeper(t) wctx := sdk.WrapSDKContext(ctx) params := types.DefaultParams() - params.UnbondingTime = 1234 keeper.SetParams(ctx, params) response, err := keeper.Params(wctx, &types.QueryParamsRequest{}) diff --git a/x/sequencer/keeper/grpc_query_sequencer.go b/x/sequencer/keeper/grpc_query_sequencer.go index 0480ce187..83faba062 100644 --- a/x/sequencer/keeper/grpc_query_sequencer.go +++ b/x/sequencer/keeper/grpc_query_sequencer.go @@ -6,20 +6,18 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" ) func (k Keeper) Sequencers(c context.Context, req *types.QuerySequencersRequest) (*types.QuerySequencersResponse, error) { if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") + return nil, gerrc.ErrInvalidArgument } - - var sequencers []types.Sequencer ctx := sdk.UnwrapSDKContext(c) + var seqs []types.Sequencer + store := ctx.KVStore(k.storeKey) sequencerStore := prefix.NewStore(store, types.SequencersKey()) @@ -28,25 +26,25 @@ func (k Keeper) Sequencers(c context.Context, req *types.QuerySequencersRequest) if err := k.cdc.Unmarshal(value, &sequencer); err != nil { return err } - sequencers = append(sequencers, sequencer) + seqs = append(seqs, sequencer) return nil }) if err != nil { - return nil, status.Error(codes.Internal, err.Error()) + return nil, err } - return &types.QuerySequencersResponse{Sequencers: sequencers, Pagination: pageRes}, nil + return &types.QuerySequencersResponse{Sequencers: seqs, Pagination: pageRes}, nil } func (k Keeper) Sequencer(c context.Context, req *types.QueryGetSequencerRequest) (*types.QueryGetSequencerResponse, error) { if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") + return nil, gerrc.ErrInvalidArgument } ctx := sdk.UnwrapSDKContext(c) - seq, found := k.GetSequencer(ctx, req.SequencerAddress) - if !found { - return nil, status.Error(codes.NotFound, "not found") + seq, err := k.RealSequencer(ctx, req.SequencerAddress) + if err != nil { + return nil, err } return &types.QueryGetSequencerResponse{Sequencer: seq}, nil diff --git a/x/sequencer/keeper/grpc_query_sequencer_test.go b/x/sequencer/keeper/grpc_query_sequencer_test.go index de4ef0579..346e49894 100644 --- a/x/sequencer/keeper/grpc_query_sequencer_test.go +++ b/x/sequencer/keeper/grpc_query_sequencer_test.go @@ -6,19 +6,18 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" "github.com/dymensionxyz/dymension/v3/testutil/nullify" "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" + "github.com/dymensionxyz/sdk-utils/utils/utest" + "github.com/stretchr/testify/require" ) func TestSequencerQuerySingle(t *testing.T) { keeper, ctx := keepertest.SequencerKeeper(t) wctx := sdk.WrapSDKContext(ctx) - sequencers := createNSequencer(keeper, ctx, 2) + sequencers := createNSequencers(keeper, ctx, 2) for _, tc := range []struct { desc string request *types.QueryGetSequencerRequest @@ -48,17 +47,17 @@ func TestSequencerQuerySingle(t *testing.T) { request: &types.QueryGetSequencerRequest{ SequencerAddress: strconv.Itoa(100000), }, - err: status.Error(codes.NotFound, "not found"), + err: gerrc.ErrNotFound, }, { desc: "InvalidRequest", - err: status.Error(codes.InvalidArgument, "invalid request"), + err: gerrc.ErrInvalidArgument, }, } { t.Run(tc.desc, func(t *testing.T) { response, err := keeper.Sequencer(wctx, tc.request) if tc.err != nil { - require.ErrorIs(t, err, tc.err) + utest.IsErr(require.New(t), err, tc.err) } else { require.NoError(t, err) require.Equal(t, @@ -73,7 +72,7 @@ func TestSequencerQuerySingle(t *testing.T) { func TestSequencersQueryPaginated(t *testing.T) { keeper, ctx := keepertest.SequencerKeeper(t) wctx := sdk.WrapSDKContext(ctx) - sequencers := createNSequencer(keeper, ctx, 5) + sequencers := createNSequencers(keeper, ctx, 5) request := func(next []byte, offset, limit uint64, total bool) *types.QuerySequencersRequest { return &types.QuerySequencersRequest{ @@ -122,6 +121,6 @@ func TestSequencersQueryPaginated(t *testing.T) { }) t.Run("InvalidRequest", func(t *testing.T) { _, err := keeper.Sequencers(wctx, nil) - require.ErrorIs(t, err, status.Error(codes.InvalidArgument, "invalid request")) + utest.IsErr(require.New(t), err, gerrc.ErrInvalidArgument) }) } diff --git a/x/sequencer/keeper/grpc_query_sequencers_by_rollapp.go b/x/sequencer/keeper/grpc_query_sequencers_by_rollapp.go index 26054665a..07d579ca1 100644 --- a/x/sequencer/keeper/grpc_query_sequencers_by_rollapp.go +++ b/x/sequencer/keeper/grpc_query_sequencers_by_rollapp.go @@ -2,16 +2,12 @@ package keeper import ( "context" - "errors" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" - "github.com/dymensionxyz/gerr-cosmos/gerrc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" ) func (k Keeper) SequencersByRollapp(c context.Context, req *types.QueryGetSequencersByRollappRequest) (*types.QueryGetSequencersByRollappResponse, error) { @@ -20,13 +16,8 @@ func (k Keeper) SequencersByRollapp(c context.Context, req *types.QueryGetSequen } ctx := sdk.UnwrapSDKContext(c) - if _, ok := k.rollappKeeper.GetRollapp(ctx, req.RollappId); !ok { - return nil, errors.Join(gerrc.ErrNotFound, types.ErrUnknownRollappID) - } - - sequencers := k.GetSequencersByRollapp(ctx, req.RollappId) return &types.QueryGetSequencersByRollappResponse{ - Sequencers: sequencers, + Sequencers: k.RollappSequencers(ctx, req.RollappId), }, nil } @@ -36,73 +27,58 @@ func (k Keeper) SequencersByRollappByStatus(c context.Context, req *types.QueryG } ctx := sdk.UnwrapSDKContext(c) - if _, ok := k.rollappKeeper.GetRollapp(ctx, req.RollappId); !ok { - return nil, errors.Join(gerrc.ErrNotFound, types.ErrUnknownRollappID) - } - - sequencers := k.GetSequencersByRollappByStatus( - ctx, - req.RollappId, - req.Status, - ) - return &types.QueryGetSequencersByRollappByStatusResponse{ - Sequencers: sequencers, + Sequencers: k.RollappSequencersByStatus(ctx, req.RollappId, req.Status), }, nil } -// GetProposerByRollapp implements types.QueryServer. func (k Keeper) GetProposerByRollapp(c context.Context, req *types.QueryGetProposerByRollappRequest) (*types.QueryGetProposerByRollappResponse, error) { if req == nil { return nil, gerrc.ErrInvalidArgument } ctx := sdk.UnwrapSDKContext(c) - seq, ok := k.GetProposer(ctx, req.RollappId) - if !ok { - return nil, types.ErrNoProposer - } - return &types.QueryGetProposerByRollappResponse{ - ProposerAddr: seq.Address, + ProposerAddr: k.GetProposer(ctx, req.RollappId).Address, }, nil } -// GetNextProposerByRollapp implements types.QueryServer. func (k Keeper) GetNextProposerByRollapp(c context.Context, req *types.QueryGetNextProposerByRollappRequest) (*types.QueryGetNextProposerByRollappResponse, error) { if req == nil { return nil, gerrc.ErrInvalidArgument } ctx := sdk.UnwrapSDKContext(c) - // if rotation is not in progress, we return the expected next proposer in case for the next rotation - expectedNext := k.ExpectedNextProposer(ctx, req.RollappId) + successor := k.GetSuccessor(ctx, req.RollappId) + inProgress := k.AwaitingLastProposerBlock(ctx, req.RollappId) + return &types.QueryGetNextProposerByRollappResponse{ - NextProposerAddr: expectedNext.Address, - RotationInProgress: k.IsRotating(ctx, req.RollappId), + NextProposerAddr: successor.Address, + RotationInProgress: inProgress, }, nil } func (k Keeper) Proposers(c context.Context, req *types.QueryProposersRequest) (*types.QueryProposersResponse, error) { if req == nil { - return nil, status.Error(codes.InvalidArgument, "invalid request") + return nil, gerrc.ErrInvalidArgument } + ctx := sdk.UnwrapSDKContext(c) var proposers []types.Sequencer - ctx := sdk.UnwrapSDKContext(c) store := ctx.KVStore(k.storeKey) sequencerStore := prefix.NewStore(store, types.ProposerByRollappKey("")) pageRes, err := query.Paginate(sequencerStore, req.Pagination, func(key []byte, value []byte) error { - proposer, ok := k.GetSequencer(ctx, string(value)) - if ok { - proposers = append(proposers, proposer) + proposer, err := k.RealSequencer(ctx, string(value)) + if err != nil { + return err } + proposers = append(proposers, proposer) return nil }) if err != nil { - return nil, status.Error(codes.Internal, err.Error()) + return nil, err } return &types.QueryProposersResponse{Proposers: proposers, Pagination: pageRes}, nil diff --git a/x/sequencer/keeper/grpc_query_sequencers_by_rollapp_test.go b/x/sequencer/keeper/grpc_query_sequencers_by_rollapp_test.go index 2296904cc..d38a8ecd7 100644 --- a/x/sequencer/keeper/grpc_query_sequencers_by_rollapp_test.go +++ b/x/sequencer/keeper/grpc_query_sequencers_by_rollapp_test.go @@ -1,41 +1,32 @@ package keeper_test import ( - "strconv" "testing" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/dymensionxyz/sdk-utils/utils/utest" "github.com/stretchr/testify/require" "github.com/dymensionxyz/dymension/v3/testutil/nullify" - "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" "github.com/dymensionxyz/dymension/v3/x/sequencer/types" "github.com/dymensionxyz/gerr-cosmos/gerrc" ) -func (suite *SequencerTestSuite) TestSequencersByRollappQuery3() { - rollappId, pk11 := suite.CreateDefaultRollapp() - pk12 := ed25519.GenPrivKey().PubKey() - rollappId2, pk21 := suite.CreateDefaultRollapp() - pk22 := ed25519.GenPrivKey().PubKey() +func (s *SequencerTestSuite) TestSequencersByRollappQuery() { + ra1 := s.createRollapp() + ra2 := s.createRollapp() + pk11 := pks[0] + pk12 := pks[1] + pk21 := pks[2] + pk22 := pks[3] + seq1 := s.createSequencerWithBond(s.Ctx, ra1.RollappId, pk11, bond) + seq2 := s.createSequencerWithBond(s.Ctx, ra1.RollappId, pk12, bond) + seq3 := s.createSequencerWithBond(s.Ctx, ra2.RollappId, pk21, bond) + seq4 := s.createSequencerWithBond(s.Ctx, ra2.RollappId, pk22, bond) - // create 2 sequencer - addr11 := suite.CreateSequencer(suite.Ctx, rollappId, pk11) - addr21 := suite.CreateSequencer(suite.Ctx, rollappId, pk12) - seq1, found := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr11) - require.True(suite.T(), found) - seq2, found := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr21) - require.True(suite.T(), found) seq1Response := types.QueryGetSequencersByRollappResponse{ Sequencers: []types.Sequencer{seq1, seq2}, } - addr12 := suite.CreateSequencer(suite.Ctx, rollappId2, pk21) - addr22 := suite.CreateSequencer(suite.Ctx, rollappId2, pk22) - seq3, found := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr12) - require.True(suite.T(), found) - seq4, found := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr22) - require.True(suite.T(), found) seq2Response := types.QueryGetSequencersByRollappResponse{ Sequencers: []types.Sequencer{seq3, seq4}, } @@ -49,33 +40,26 @@ func (suite *SequencerTestSuite) TestSequencersByRollappQuery3() { { desc: "First", request: &types.QueryGetSequencersByRollappRequest{ - RollappId: rollappId, + RollappId: ra1.RollappId, }, response: &seq1Response, }, { desc: "Second", request: &types.QueryGetSequencersByRollappRequest{ - RollappId: rollappId2, + RollappId: ra2.RollappId, }, response: &seq2Response, }, - { - desc: "KeyNotFound", - request: &types.QueryGetSequencersByRollappRequest{ - RollappId: strconv.Itoa(100000), - }, - err: types.ErrUnknownRollappID, - }, { desc: "InvalidRequest", err: gerrc.ErrInvalidArgument, }, } { - suite.T().Run(tc.desc, func(t *testing.T) { - response, err := suite.App.SequencerKeeper.SequencersByRollapp(suite.Ctx, tc.request) + s.T().Run(tc.desc, func(t *testing.T) { + response, err := s.k().SequencersByRollapp(s.Ctx, tc.request) if tc.err != nil { - require.ErrorIs(t, err, tc.err) + utest.IsErr(require.New(t), err, tc.err) } else { require.NoError(t, err) require.Equal(t, @@ -87,86 +71,67 @@ func (suite *SequencerTestSuite) TestSequencersByRollappQuery3() { } } -func (suite *SequencerTestSuite) TestSequencersByRollappByStatusQuery() { - msgserver := keeper.NewMsgServerImpl(suite.App.SequencerKeeper) +func (s *SequencerTestSuite) TestSequencersByRollappByStatusQuery() { + ra1 := s.createRollapp() + ra2 := s.createRollapp() + pk11 := pks[0] + pk12 := pks[1] + pk21 := pks[2] + pk22 := pks[3] + addr11 := s.createSequencerWithBond(s.Ctx, ra1.RollappId, pk11, bond).Address + addr12 := s.createSequencerWithBond(s.Ctx, ra1.RollappId, pk12, bond).Address + addr21 := s.createSequencerWithBond(s.Ctx, ra2.RollappId, pk21, bond).Address + addr22 := s.createSequencerWithBond(s.Ctx, ra2.RollappId, pk22, bond).Address - rollappId, pk11 := suite.CreateDefaultRollapp() - pk12 := ed25519.GenPrivKey().PubKey() - // create 2 sequencers on rollapp1 - addr11 := suite.CreateSequencer(suite.Ctx, rollappId, pk11) - addr21 := suite.CreateSequencer(suite.Ctx, rollappId, pk12) - _, err := msgserver.Unbond(suite.Ctx, &types.MsgUnbond{ - Creator: addr21, - }) - require.NoError(suite.T(), err) - - // create 2 sequencers on rollapp2 - rollappId2, pk21 := suite.CreateDefaultRollapp() - pk22 := ed25519.GenPrivKey().PubKey() - addr12 := suite.CreateSequencer(suite.Ctx, rollappId2, pk21) - addr22 := suite.CreateSequencer(suite.Ctx, rollappId2, pk22) + _, err := s.msgServer.Unbond(s.Ctx, &types.MsgUnbond{Creator: addr12}) + s.Require().NoError(err) for _, tc := range []struct { - desc string - request *types.QueryGetSequencersByRollappByStatusRequest - response_addr []string - err error + desc string + request *types.QueryGetSequencersByRollappByStatusRequest + responseAddr []string + err error }{ { desc: "First - Bonded", request: &types.QueryGetSequencersByRollappByStatusRequest{ - RollappId: rollappId, + RollappId: ra1.RollappId, Status: types.Bonded, }, - response_addr: []string{addr11}, - }, - { - desc: "First - Unbonding", - request: &types.QueryGetSequencersByRollappByStatusRequest{ - RollappId: rollappId, - Status: types.Unbonding, - }, - response_addr: []string{addr21}, + responseAddr: []string{addr11}, }, { desc: "First - Unbonded", request: &types.QueryGetSequencersByRollappByStatusRequest{ - RollappId: rollappId, + RollappId: ra1.RollappId, Status: types.Unbonded, }, - response_addr: []string{}, + responseAddr: []string{addr12}, }, { desc: "Second", request: &types.QueryGetSequencersByRollappByStatusRequest{ - RollappId: rollappId2, + RollappId: ra2.RollappId, Status: types.Bonded, }, - response_addr: []string{addr12, addr22}, - }, - { - desc: "KeyNotFound", - request: &types.QueryGetSequencersByRollappByStatusRequest{ - RollappId: strconv.Itoa(100000), - }, - err: types.ErrUnknownRollappID, + responseAddr: []string{addr21, addr22}, }, { desc: "InvalidRequest", err: gerrc.ErrInvalidArgument, }, } { - suite.T().Run(tc.desc, func(t *testing.T) { - response, err := suite.App.SequencerKeeper.SequencersByRollappByStatus(suite.Ctx, tc.request) + s.T().Run(tc.desc, func(t *testing.T) { + response, err := s.k().SequencersByRollappByStatus(s.Ctx, tc.request) if tc.err != nil { - require.ErrorIs(t, err, tc.err) + utest.IsErr(require.New(t), err, tc.err) } else { require.NoError(t, err) - require.Len(t, response.Sequencers, len(tc.response_addr)) + require.Len(t, response.Sequencers, len(tc.responseAddr)) - for _, seqAddr := range tc.response_addr { - seq, found := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, seqAddr) - require.True(t, found) + for _, seqAddr := range tc.responseAddr { + seq, err := s.k().RealSequencer(s.Ctx, seqAddr) + require.NoError(t, err) require.Contains(t, response.Sequencers, seq) } } diff --git a/x/sequencer/keeper/hook_listener.go b/x/sequencer/keeper/hook_listener.go index 3ea185a73..4dc208ddb 100644 --- a/x/sequencer/keeper/hook_listener.go +++ b/x/sequencer/keeper/hook_listener.go @@ -1,48 +1,34 @@ package keeper import ( + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) var _ rollapptypes.RollappHooks = rollappHook{} -// Hooks wrapper struct for rollapp keeper. type rollappHook struct { rollapptypes.StubRollappCreatedHooks k Keeper } -// RollappHooks returns the wrapper struct. func (k Keeper) RollappHooks() rollapptypes.RollappHooks { return rollappHook{k: k} } -// BeforeUpdateState checks various conditions before updating the state. -// It verifies if the sequencer has been registered, if the rollappId matches the one of the sequencer, -// if there is a proposer for the given rollappId, and if the sequencer is the active one. -// If the lastStateUpdateBySequencer flag is true, it also checks if the rollappId is rotating and -// performs a rotation of the proposer. -// Returns an error if any of the checks fail, otherwise returns nil. +// BeforeUpdateState will reject if the caller is not proposer, or if they are proposer but haven't +// finished their rotation notice period. +// If valid, it will set the successor as proposer func (hook rollappHook) BeforeUpdateState(ctx sdk.Context, seqAddr, rollappId string, lastStateUpdateBySequencer bool) error { - proposer, ok := hook.k.GetProposer(ctx, rollappId) - if !ok { - return types.ErrNoProposer - } + proposer := hook.k.GetProposer(ctx, rollappId) if seqAddr != proposer.Address { - return types.ErrNotActiveSequencer + return types.ErrNotProposer } if lastStateUpdateBySequencer { - // last state update received by sequencer - // it's expected that the sequencer produced a last block which handovers the proposer role on the L2 - // any divergence from this is considered fraud - err := hook.k.CompleteRotation(ctx, rollappId) - if err != nil { - return err - } + return errorsmod.Wrap(hook.k.OnProposerLastBlock(ctx, proposer), "on proposer last block") } return nil @@ -52,5 +38,14 @@ func (hook rollappHook) BeforeUpdateState(ctx sdk.Context, seqAddr, rollappId st // 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 { - return hook.k.InstantUnbondAllSequencers(ctx, rollappID) + 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/hooks_test.go b/x/sequencer/keeper/hooks_test.go deleted file mode 100644 index 876077b10..000000000 --- a/x/sequencer/keeper/hooks_test.go +++ /dev/null @@ -1,59 +0,0 @@ -package keeper_test - -import ( - "time" - - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -func (suite *SequencerTestSuite) TestFraudSubmittedHook() { - suite.Ctx = suite.Ctx.WithBlockHeight(10) - suite.Ctx = suite.Ctx.WithBlockTime(time.Now()) - - keeper := suite.App.SequencerKeeper - - rollappId, pk := suite.CreateDefaultRollapp() - - numOfSequencers := 5 - - // create 5 sequencers for rollapp1 - seqAddrs := make([]string, numOfSequencers) - seqAddrs[0] = suite.CreateSequencerWithBond(suite.Ctx, rollappId, bond.AddAmount(sdk.NewInt(20)), pk) - - for i := 1; i < numOfSequencers; i++ { - pki := ed25519.GenPrivKey().PubKey() - seqAddrs[i] = suite.CreateSequencer(suite.Ctx, rollappId, pki) - } - - proposer := seqAddrs[0] - p, found := keeper.GetProposer(suite.Ctx, rollappId) - suite.Require().True(found) - suite.Require().Equal(proposer, p.Address) - - // queue the third sequencer to reduce bond - decreaseBondMsg := types.MsgDecreaseBond{Creator: seqAddrs[0], DecreaseAmount: sdk.NewInt64Coin(bond.Denom, 10)} - resp, err := suite.msgServer.DecreaseBond(suite.Ctx, &decreaseBondMsg) - suite.Require().NoError(err) - bds := keeper.GetMatureDecreasingBondIDs(suite.Ctx, resp.GetCompletionTime()) - suite.Require().Len(bds, 1) - - err = keeper.RollappHooks().OnHardFork(suite.Ctx, rollappId, 0) - suite.Require().NoError(err) - - // check if other sequencers are unbonded - for i := 0; i < numOfSequencers; i++ { - sequencer, found := keeper.GetSequencer(suite.Ctx, seqAddrs[i]) - suite.Require().True(found) - suite.Require().Equal(sequencer.Status, types.Unbonded) - } - - // check no proposer is set for the rollapp after fraud - _, ok := keeper.GetProposer(suite.Ctx, rollappId) - suite.Require().False(ok) - // check if bond reduction queue is pruned - bds = keeper.GetMatureDecreasingBondIDs(suite.Ctx, resp.GetCompletionTime()) - suite.Require().Len(bds, 0) -} diff --git a/x/sequencer/keeper/invariants.go b/x/sequencer/keeper/invariants.go index 2ce6c9272..f36556803 100644 --- a/x/sequencer/keeper/invariants.go +++ b/x/sequencer/keeper/invariants.go @@ -10,24 +10,6 @@ import ( func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) { ir.RegisterRoute(types.ModuleName, "sequencers-count", SequencersCountInvariant(k)) ir.RegisterRoute(types.ModuleName, "sequencer-proposer-bonded", ProposerBondedInvariant(k)) - ir.RegisterRoute(types.ModuleName, "sequencer-positive-balance-post-bond-reduction", SequencerPositiveBalancePostBondReduction(k)) -} - -// AllInvariants runs all invariants of the x/sequencer module. -func AllInvariants(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - res, stop := SequencersCountInvariant(k)(ctx) - if stop { - return res, stop - } - - res, stop = ProposerBondedInvariant(k)(ctx) - if stop { - return res, stop - } - - return "", false - } } func SequencersCountInvariant(k Keeper) sdk.Invariant { @@ -37,19 +19,18 @@ func SequencersCountInvariant(k Keeper) sdk.Invariant { msg string ) - sequencers := k.GetAllSequencers(ctx) + sequencers := k.AllSequencers(ctx) rollapps := k.rollappKeeper.GetAllRollapps(ctx) totalCount := 0 for _, rollapp := range rollapps { - seqByRollapp := k.GetSequencersByRollapp(ctx, rollapp.RollappId) - bonded := k.GetSequencersByRollappByStatus(ctx, rollapp.RollappId, types.Bonded) - unbonding := k.GetSequencersByRollappByStatus(ctx, rollapp.RollappId, types.Unbonding) - unbonded := k.GetSequencersByRollappByStatus(ctx, rollapp.RollappId, types.Unbonded) + seqByRollapp := k.RollappSequencers(ctx, rollapp.RollappId) + bonded := k.RollappSequencersByStatus(ctx, rollapp.RollappId, types.Bonded) + unbonded := k.RollappSequencersByStatus(ctx, rollapp.RollappId, types.Unbonded) - if len(seqByRollapp) != len(bonded)+len(unbonding)+len(unbonded) { + if len(seqByRollapp) != len(bonded)+len(unbonded) { broken = true - msg += "sequencer by rollapp length is not equal to sum of bonded, unbonding and unbonded " + rollapp.RollappId + "\n" + msg += "sequencer by rollapp length is not equal to sum of bonded, and unbonded " + rollapp.RollappId + "\n" } totalCount += len(seqByRollapp) @@ -77,56 +58,21 @@ func ProposerBondedInvariant(k Keeper) sdk.Invariant { rollapps := k.rollappKeeper.GetAllRollapps(ctx) for _, rollapp := range rollapps { - active, ok := k.GetProposer(ctx, rollapp.RollappId) - if ok && active.Status != types.Bonded { + proposer := k.GetProposer(ctx, rollapp.RollappId) + if !proposer.Bonded() { broken = true - msg += "active sequencer is not bonded " + rollapp.RollappId + "\n" + msg += "proposer is not bonded " + rollapp.RollappId + "\n" } - - next := k.ExpectedNextProposer(ctx, rollapp.RollappId) - if !next.IsEmpty() && next.Status != types.Bonded { - broken = true - msg += "next sequencer is not bonded " + rollapp.RollappId + "\n" - } - } - - return sdk.FormatInvariant( - types.ModuleName, "sequencer-bonded", - msg, - ), broken - } -} - -// SequencerPositiveBalancePostBondReduction checks if the sequencer maintains a non-negative balance after all bond reductions are applied -func SequencerPositiveBalancePostBondReduction(k Keeper) sdk.Invariant { - return func(ctx sdk.Context) (string, bool) { - var ( - broken bool - msg string - ) - sequencers := k.GetAllSequencers(ctx) - for _, seq := range sequencers { - effectiveBond := seq.Tokens - - // assert single denom for bond - if effectiveBond.Len() != 1 { + successor := k.GetSuccessor(ctx, rollapp.RollappId) + if !successor.Bonded() { broken = true - msg += "sequencer has multiple denoms " + seq.Address + "\n" + msg += "successor is not bonded " + rollapp.RollappId + "\n" } - if bondReductions := k.GetBondReductionsBySequencer(ctx, seq.Address); len(bondReductions) > 0 { - for _, bd := range bondReductions { - effectiveBond = effectiveBond.Sub(bd.DecreaseBondAmount) - } - } - if effectiveBond.IsAnyNegative() { - broken = true - msg += "sequencer will have negative balance after bond reduction " + seq.Address + "\n" - } } return sdk.FormatInvariant( - types.ModuleName, "sequencer-positive-balance-post-bond-reduction", + types.ModuleName, "sequencer-bonded", msg, ), broken } diff --git a/x/sequencer/keeper/invariants_test.go b/x/sequencer/keeper/invariants_test.go index 820b3dfce..e407f15fe 100644 --- a/x/sequencer/keeper/invariants_test.go +++ b/x/sequencer/keeper/invariants_test.go @@ -1,69 +1,3 @@ package keeper_test -import ( - "time" - - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - - "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -func (suite *SequencerTestSuite) TestInvariants() { - suite.SetupTest() - initialheight := uint64(10) - initialTime := time.Now() - - numOfRollapps := 5 - numOfSequencers := 5 - - var ( - rollappToTest string - timeToMature time.Time - ) - - // create rollapps and sequencers - for i := 0; i < numOfRollapps; i++ { - rollapp, pk := suite.CreateDefaultRollapp() - - // create sequencers - seqAddr := make([]string, numOfSequencers) - seqAddr[0] = suite.CreateSequencer(suite.Ctx, rollapp, pk) - for j := 1; j < numOfSequencers; j++ { - pki := ed25519.GenPrivKey().PubKey() - seqAddr[j] = suite.CreateSequencer(suite.Ctx, rollapp, pki) - } - - // unbonding some sequencers - for j := uint64(0); j < uint64(numOfSequencers-1); j++ { - suite.Ctx = suite.Ctx.WithBlockHeight(int64(initialheight + j)).WithBlockTime(initialTime.Add(time.Duration(j) * time.Second)) - res, err := suite.msgServer.Unbond(suite.Ctx, &types.MsgUnbond{Creator: seqAddr[j]}) - suite.Require().NoError(err) - if i == 1 && j == 1 { - rollappToTest = rollapp - timeToMature = *res.GetUnbondingCompletionTime() - } - } - } - - rollappid := rollappToTest - seqUnbonding := suite.App.SequencerKeeper.GetSequencersByRollappByStatus(suite.Ctx, rollappid, types.Unbonding) - suite.Require().True(len(seqUnbonding) > 0) - - // unbond some unbonding sequencers - suite.App.SequencerKeeper.UnbondAllMatureSequencers(suite.Ctx, timeToMature) - - // Test the test: make sure all status have entries - seqBonded := suite.App.SequencerKeeper.GetSequencersByRollappByStatus(suite.Ctx, rollappid, types.Bonded) - seqUnbonding = suite.App.SequencerKeeper.GetSequencersByRollappByStatus(suite.Ctx, rollappid, types.Unbonding) - seqUnbonded := suite.App.SequencerKeeper.GetSequencersByRollappByStatus(suite.Ctx, rollappid, types.Unbonded) - - if len(seqBonded) == 0 || len(seqUnbonding) == 0 || len(seqUnbonded) == 0 { - suite.T().Fatal("Test setup failed") - } - // additional rollapp with no sequencers - suite.CreateDefaultRollapp() - - msg, ok := keeper.AllInvariants(suite.App.SequencerKeeper)(suite.Ctx) - suite.Require().False(ok, msg) -} +// TODO:! bring back diff --git a/x/sequencer/keeper/keeper.go b/x/sequencer/keeper/keeper.go index 84ffcb677..eaf3025fe 100644 --- a/x/sequencer/keeper/keeper.go +++ b/x/sequencer/keeper/keeper.go @@ -3,7 +3,9 @@ package keeper import ( "fmt" + "cosmossdk.io/collections" "github.com/cometbft/cometbft/libs/log" + "github.com/dymensionxyz/dymension/v3/internal/collcompat" "github.com/cosmos/cosmos-sdk/codec" storetypes "github.com/cosmos/cosmos-sdk/store/types" @@ -15,10 +17,14 @@ import ( type Keeper struct { authority string // authority is the x/gov module account - cdc codec.BinaryCodec - storeKey storetypes.StoreKey - bankKeeper types.BankKeeper - rollappKeeper types.RollappKeeper + cdc codec.BinaryCodec + storeKey storetypes.StoreKey + bankKeeper types.BankKeeper + rollappKeeper types.RollappKeeper + unbondBlockers []UnbondBlocker + hooks types.Hooks + + dymintProposerAddrToAccAddr collections.Map[[]byte, string] } func NewKeeper( @@ -32,16 +38,35 @@ func NewKeeper( if err != nil { panic(fmt.Errorf("invalid x/sequencer authority address: %w", err)) } + service := collcompat.NewKVStoreService(storeKey) + sb := collections.NewSchemaBuilder(service) return &Keeper{ - cdc: cdc, - storeKey: storeKey, - bankKeeper: bankKeeper, - rollappKeeper: rollappKeeper, - authority: authority, + cdc: cdc, + storeKey: storeKey, + bankKeeper: bankKeeper, + rollappKeeper: rollappKeeper, + authority: authority, + unbondBlockers: []UnbondBlocker{}, + hooks: types.NoOpHooks{}, + dymintProposerAddrToAccAddr: collections.NewMap( + sb, + types.DymintProposerAddrToAccAddrKeyPrefix, + "dymintProposerAddrToAccAddr", + collections.BytesKey, + collections.StringValue, + ), } } func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } + +func (k *Keeper) SetUnbondBlockers(ubs ...UnbondBlocker) { + k.unbondBlockers = ubs +} + +func (k *Keeper) SetHooks(h types.Hooks) { + k.hooks = h +} diff --git a/x/sequencer/keeper/msg_server.go b/x/sequencer/keeper/msg_server.go index 3ed9e161c..58e34b219 100644 --- a/x/sequencer/keeper/msg_server.go +++ b/x/sequencer/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/sequencer/keeper/msg_server_bond.go b/x/sequencer/keeper/msg_server_bond.go new file mode 100644 index 000000000..936c3bfc3 --- /dev/null +++ b/x/sequencer/keeper/msg_server_bond.go @@ -0,0 +1,98 @@ +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" + "github.com/dymensionxyz/sdk-utils/utils/uevent" +) + +func (k msgServer) IncreaseBond(goCtx context.Context, msg *types.MsgIncreaseBond) (*types.MsgIncreaseBondResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + seq, err := k.RealSequencer(ctx, msg.GetCreator()) + if err != nil { + return nil, err + } + defer func() { + k.SetSequencer(ctx, seq) + }() + + if err := k.validBondDenom(ctx, msg.AddAmount); err != nil { + return nil, err + } + + if err := k.sendToModule(ctx, &seq, msg.AddAmount); err != nil { + return nil, err + } + + // emit a typed event which includes the added amount and the active bond amount + return &types.MsgIncreaseBondResponse{}, uevent.EmitTypedEvent(ctx, + &types.EventIncreasedBond{ + Sequencer: msg.Creator, + Bond: seq.Tokens, + AddedAmount: msg.AddAmount, + }, + ) +} + +func (k msgServer) DecreaseBond(goCtx context.Context, msg *types.MsgDecreaseBond) (*types.MsgDecreaseBondResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + seq, err := k.RealSequencer(ctx, msg.GetCreator()) + 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") + } + + return &types.MsgDecreaseBondResponse{}, nil +} + +func (k msgServer) Unbond(goCtx context.Context, msg *types.MsgUnbond) (*types.MsgUnbondResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + seq, err := k.RealSequencer(ctx, msg.Creator) + if err != nil { + return nil, err + } + defer func() { + k.SetSequencer(ctx, seq) + }() + + // 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) + } + return &types.MsgUnbondResponse{ + CompletionTime: &types.MsgUnbondResponse_NoticePeriodCompletionTime{ + NoticePeriodCompletionTime: &seq.NoticePeriodTime, + }, + }, nil + } + if err != nil { + return nil, errorsmod.Wrap(err, "try unbond") + } + + return &types.MsgUnbondResponse{}, nil +} diff --git a/x/sequencer/keeper/msg_server_bond_test.go b/x/sequencer/keeper/msg_server_bond_test.go new file mode 100644 index 000000000..5383c939e --- /dev/null +++ b/x/sequencer/keeper/msg_server_bond_test.go @@ -0,0 +1,180 @@ +package keeper_test + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" + "github.com/dymensionxyz/sdk-utils/utils/ucoin" + "github.com/dymensionxyz/sdk-utils/utils/utest" +) + +func (s *SequencerTestSuite) TestIncreaseBondBasic() { + ra := s.createRollapp() + expect := bond + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, expect) + m := &types.MsgIncreaseBond{ + Creator: seq.Address, + AddAmount: bond, + } + for range 2 { + s.fundSequencer(seq.MustPubKey(), m.AddAmount) + _, err := s.msgServer.IncreaseBond(s.Ctx, m) + s.Require().NoError(err) + expect = expect.Add(bond) + seq = s.k().GetSequencer(s.Ctx, seq.Address) + s.Require().True(expect.Equal(seq.TokensCoin())) + s.Require().True(expect.Equal(s.moduleBalance())) + } +} + +func (s *SequencerTestSuite) TestIncreaseBondRestrictions() { + ra := s.createRollapp() + + s.Run("wrong denom", func() { + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) + m := &types.MsgIncreaseBond{ + Creator: seq.Address, + AddAmount: bond, + } + m.AddAmount.Denom = "foo" + _, err := s.msgServer.IncreaseBond(s.Ctx, m) + utest.IsErr(s.Require(), err, gerrc.ErrInvalidArgument) + }) + s.Run("sequencer not found", func() { + // do not create sequencer + m := &types.MsgIncreaseBond{ + Creator: pkAddr(bob), + AddAmount: bond, + } + _, err := s.msgServer.IncreaseBond(s.Ctx, m) + utest.IsErr(s.Require(), err, gerrc.ErrNotFound) + }) + s.Run("insufficient funds", func() { + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, charlie, bond) + m := &types.MsgIncreaseBond{ + Creator: seq.Address, + AddAmount: bond, + } + // do not fund + _, err := s.msgServer.IncreaseBond(s.Ctx, m) + utest.IsErr(s.Require(), err, sdkerrors.ErrInsufficientFunds) + }) +} + +func (s *SequencerTestSuite) TestDecreaseBondBasic() { + ra := s.createRollapp() + expect := ucoin.SimpleMul(bond, 10) // plenty + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, expect) + m := &types.MsgDecreaseBond{ + Creator: seq.Address, + DecreaseAmount: bond, + } + s.k().SetProposer(s.Ctx, ra.RollappId, pkAddr(randomTMPubKey())) // make not proposer so it's allowed + for range 2 { + _, err := s.msgServer.DecreaseBond(s.Ctx, m) + s.Require().NoError(err) + expect = expect.Sub(bond) + seq = s.k().GetSequencer(s.Ctx, seq.Address) + s.Require().True(expect.Equal(seq.TokensCoin())) + s.Require().True(expect.Equal(s.moduleBalance())) + } +} + +func (s *SequencerTestSuite) TestDecreaseBondRestrictions() { + ra := s.createRollapp() + + s.Run("sequencer not found", func() { + // do not create sequencer + m := &types.MsgDecreaseBond{ + Creator: pkAddr(alice), + DecreaseAmount: bond, + } + _, err := s.msgServer.DecreaseBond(s.Ctx, m) + utest.IsErr(s.Require(), err, gerrc.ErrNotFound) + }) + s.Run("proposer", func() { + currBond := ucoin.SimpleMul(bond, 3) + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, bob, currBond) + s.k().SetProposer(s.Ctx, ra.RollappId, seq.Address) + m := &types.MsgDecreaseBond{ + Creator: seq.Address, + DecreaseAmount: bond, + } + _, err := s.msgServer.DecreaseBond(s.Ctx, m) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) + }) + s.Run("successor", func() { + currBond := ucoin.SimpleMul(bond, 3) + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, charlie, currBond) + s.k().SetSuccessor(s.Ctx, ra.RollappId, seq.Address) + m := &types.MsgDecreaseBond{ + Creator: seq.Address, + DecreaseAmount: bond, + } + _, err := s.msgServer.DecreaseBond(s.Ctx, m) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) + }) + s.Run("fall below min", func() { + currBond := ucoin.MulDec(sdk.MustNewDecFromStr("1.5"), bond)[0] + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, pks[3], currBond) + m := &types.MsgDecreaseBond{ + Creator: seq.Address, + DecreaseAmount: bond, // too much + } + _, err := s.msgServer.DecreaseBond(s.Ctx, m) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) + }) +} + +func (s *SequencerTestSuite) TestUnbondBasic() { + ra := s.createRollapp() + expect := bond + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, expect) + s.k().SetProposer(s.Ctx, ra.RollappId, pkAddr(randomTMPubKey())) // make not proposer so it's allowed + m := &types.MsgUnbond{ + Creator: seq.Address, + } + _, err := s.msgServer.Unbond(s.Ctx, m) + s.Require().NoError(err) + seq = s.k().GetSequencer(s.Ctx, seq.Address) + s.Require().Equal(types.Unbonded, seq.Status) + s.Require().True(s.moduleBalance().IsZero()) + s.Require().True(seq.TokensCoin().IsZero()) +} + +func (s *SequencerTestSuite) TestUnbondRestrictions() { + ra := s.createRollapp() + + s.Run("sequencer not found", func() { + // do not create sequencer + m := &types.MsgUnbond{ + Creator: pkAddr(alice), + } + _, err := s.msgServer.Unbond(s.Ctx, m) + utest.IsErr(s.Require(), err, gerrc.ErrNotFound) + }) + s.Run("proposer - start notice", func() { + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, bob, bond) + s.k().SetProposer(s.Ctx, ra.RollappId, seq.Address) + m := &types.MsgUnbond{ + Creator: seq.Address, + } + res, err := s.msgServer.Unbond(s.Ctx, m) + s.Require().NoError(err) + s.Require().False(res.GetNoticePeriodCompletionTime().IsZero()) + seq = s.k().GetSequencer(s.Ctx, seq.Address) + s.Require().True(seq.NoticeInProgress(s.Ctx.BlockTime())) + s.Require().True(s.k().IsProposer(s.Ctx, seq)) + s.Require().False(seq.OptedIn) + }) + s.Run("successor - not allowed", func() { + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, charlie, bond) + s.k().SetSuccessor(s.Ctx, ra.RollappId, seq.Address) + m := &types.MsgUnbond{ + Creator: seq.Address, + } + _, err := s.msgServer.Unbond(s.Ctx, m) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) + }) +} diff --git a/x/sequencer/keeper/msg_server_create.go b/x/sequencer/keeper/msg_server_create.go new file mode 100644 index 000000000..88cd766df --- /dev/null +++ b/x/sequencer/keeper/msg_server_create.go @@ -0,0 +1,124 @@ +package keeper + +import ( + "context" + "slices" + "strconv" + "strings" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" + + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" +) + +func (k msgServer) CreateSequencer(goCtx context.Context, msg *types.MsgCreateSequencer) (*types.MsgCreateSequencerResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // check to see if the rollapp has been registered before + rollapp, found := k.rollappKeeper.GetRollapp(ctx, msg.RollappId) + if !found { + return nil, rollapptypes.ErrRollappNotFound + } + + // check to see if the seq has been registered before + if _, err := k.RealSequencer(ctx, msg.Creator); err == nil { + return nil, types.ErrSequencerAlreadyExists + } + + pkAddr, err := types.PubKeyAddr(msg.DymintPubKey) + if err != nil { + return nil, errorsmod.Wrap(err, "pub key addr") + } + if _, err := k.SequencerByDymintAddr(ctx, pkAddr); err == nil { + return nil, gerrc.ErrAlreadyExists.Wrap("pub key in use") + } + + /* + If we are awaiting the last block from the proposer we stop new sequencer registrations, because + we don't want to set a new successor while the last block from the proposer is in flight. + TODO: possible to simplify? + */ + if k.AwaitingLastProposerBlock(ctx, msg.RollappId) { + return nil, types.ErrRegisterSequencerWhileAwaitingLastProposerBlock + } + + if err := k.sufficientBond(ctx, msg.Bond); err != nil { + return nil, err + } + + if err := msg.VMSpecificValidate(rollapp.VmType); err != nil { + return nil, errorsmod.Wrap(err, "vm specific validate") + } + + // In case InitialSequencer is set to one or more bech32 addresses, only one of them can be the first to register, + // and is automatically selected as the first proposer, allowing the Rollapp to be set to 'launched' + // (provided that all the immutable fields are set in the Rollapp). + // This limitation prevents scenarios such as: + // a) any unintended initial seq getting registered before the immutable fields are set in the Rollapp. + // b) situation when seq "X" is registered prior to the initial seq, + // after which the initial seq's address is set to seq X's address, effectively preventing: + // 1. the initial seq from getting selected as the first proposer, + // 2. the rollapp from getting launched again + // In case the InitialSequencer is set to the "*" wildcard, any seq can be the first to register. + if !rollapp.Launched { + isInitialSeq := slices.Contains(strings.Split(rollapp.InitialSequencer, ","), msg.Creator) + anyAllowed := rollapp.InitialSequencer == "*" + if !anyAllowed && !isInitialSeq { + return nil, types.ErrNotInitialSequencer + } + + // check pre launch time. + // skipped if no pre launch time is set + if rollapp.PreLaunchTime != nil && rollapp.PreLaunchTime.After(ctx.BlockTime()) { + return nil, types.ErrBeforePreLaunchTime + } + + if err := k.rollappKeeper.SetRollappAsLaunched(ctx, &rollapp); err != nil { + return nil, err + } + } + + seq := k.NewSequencer(ctx, msg.RollappId) + + // set a reward address. if empty, use a creator address. + rewardAddr := msg.RewardAddr + if msg.RewardAddr == "" { + rewardAddr = msg.Creator + } + + seq.RewardAddr = rewardAddr + seq.DymintPubKey = msg.DymintPubKey + seq.Address = msg.Creator + seq.Status = types.Bonded + seq.Metadata = msg.Metadata + seq.OptedIn = true + seq.SetWhitelistedRelayers(msg.WhitelistedRelayers) + + if err := k.sendToModule(ctx, seq, msg.Bond); err != nil { + return nil, err + } + + k.SetSequencer(ctx, *seq) + if err := k.SetSequencerByDymintAddr(ctx, pkAddr, seq.Address); err != nil { + return nil, err + } + + if err := k.UpdateProposerIfNeeded(ctx, msg.RollappId); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeCreateSequencer, + sdk.NewAttribute(types.AttributeKeyRollappId, msg.RollappId), + sdk.NewAttribute(types.AttributeKeySequencer, msg.Creator), + sdk.NewAttribute(types.AttributeKeyBond, msg.Bond.String()), + sdk.NewAttribute(types.AttributeKeyProposer, strconv.FormatBool(k.IsProposer(ctx, *seq))), + ), + ) + + return &types.MsgCreateSequencerResponse{}, nil +} diff --git a/x/sequencer/keeper/msg_server_create_sequencer.go b/x/sequencer/keeper/msg_server_create_sequencer.go deleted file mode 100644 index c64d3cd1c..000000000 --- a/x/sequencer/keeper/msg_server_create_sequencer.go +++ /dev/null @@ -1,131 +0,0 @@ -package keeper - -import ( - "context" - "errors" - "slices" - "strconv" - "strings" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -// CreateSequencer defines a method for creating a new sequencer -func (k msgServer) CreateSequencer(goCtx context.Context, msg *types.MsgCreateSequencer) (*types.MsgCreateSequencerResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - // check to see if the rollapp has been registered before - rollapp, found := k.rollappKeeper.GetRollapp(ctx, msg.RollappId) - if !found { - return nil, types.ErrUnknownRollappID - } - - if err := msg.VMSpecificValidate(rollapp.VmType); err != nil { - return nil, errors.Join(types.ErrInvalidRequest, err) - } - - // check to see if the sequencer has been registered before - if _, found = k.GetSequencer(ctx, msg.Creator); found { - return nil, types.ErrSequencerExists - } - - // In case InitialSequencer is set to one or more bech32 addresses, only one of them can be the first to register, - // and is automatically selected as the first proposer, allowing the Rollapp to be set to 'launched' - // (provided that all the immutable fields are set in the Rollapp). - // This limitation prevents scenarios such as: - // a) any unintended initial sequencer getting registered before the immutable fields are set in the Rollapp. - // b) situation when sequencer "X" is registered prior to the initial sequencer, - // after which the initial sequencer's address is set to sequencer X's address, effectively preventing: - // 1. the initial sequencer from getting selected as the first proposer, - // 2. the rollapp from getting launched again - // In case the InitialSequencer is set to the "*" wildcard, any sequencer can be the first to register. - if !rollapp.Launched { - isInitialOrAllAllowed := slices.Contains(strings.Split(rollapp.InitialSequencer, ","), msg.Creator) || rollapp.InitialSequencer == "*" - if !isInitialOrAllAllowed { - return nil, types.ErrNotInitialSequencer - } - - // check pre launch time. - // skipped if no pre launch time is set - if rollapp.PreLaunchTime != nil && rollapp.PreLaunchTime.After(ctx.BlockTime()) { - return nil, types.ErrBeforePreLaunchTime - } - - if err := k.rollappKeeper.SetRollappAsLaunched(ctx, &rollapp); err != nil { - return nil, err - } - } - - // validate bond requirement - minBond := k.GetParams(ctx).MinBond - if !msg.Bond.IsGTE(minBond) { - return nil, errorsmod.Wrapf( - types.ErrInsufficientBond, "got %s, expected %s", msg.Bond, minBond, - ) - } - - // send bond to module account - seqAcc := sdk.MustAccAddressFromBech32(msg.Creator) - err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, seqAcc, types.ModuleName, sdk.NewCoins(msg.Bond)) - if err != nil { - return nil, err - } - - // set a reward address. if empty, use a creator address. - rewardAddr := msg.RewardAddr - if msg.RewardAddr == "" { - rewardAddr = msg.Creator - } - - bond := sdk.NewCoins(msg.Bond) - sequencer := types.Sequencer{ - Address: msg.Creator, - DymintPubKey: msg.DymintPubKey, - RollappId: msg.RollappId, - Metadata: msg.Metadata, - Status: types.Bonded, - Tokens: bond, - RewardAddr: rewardAddr, - } - sequencer.SetWhitelistedRelayers(msg.WhitelistedRelayers) - - // we currently only support setting next proposer (or empty one) before the rotation started. This is in order to - // avoid handling the case a potential next proposer bonds in the middle of a rotation. - // This will be handled in next iteration. - nextProposer, ok := k.GetNextProposer(ctx, msg.RollappId) - if ok && nextProposer.IsEmpty() { - k.Logger(ctx).Info("rotation in progress. sequencer registration disabled", "rollappId", sequencer.RollappId) - return nil, types.ErrRotationInProgress - } - - // if no proposer set for he rollapp, set this sequencer as the proposer - _, proposerExists := k.GetProposer(ctx, msg.RollappId) - if !proposerExists { - k.SetProposer(ctx, sequencer.RollappId, sequencer.Address) - - // recover from hard fork - // if the rollapp has a state info, set the next proposer to this sequencer - sInfo, ok := k.rollappKeeper.GetLatestStateInfo(ctx, sequencer.RollappId) - if ok { - sInfo.NextProposer = sequencer.Address - k.rollappKeeper.SetStateInfo(ctx, sInfo) - } - } - - k.SetSequencer(ctx, sequencer) - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeCreateSequencer, - sdk.NewAttribute(types.AttributeKeyRollappId, msg.RollappId), - sdk.NewAttribute(types.AttributeKeySequencer, msg.Creator), - sdk.NewAttribute(types.AttributeKeyBond, msg.Bond.String()), - sdk.NewAttribute(types.AttributeKeyProposer, strconv.FormatBool(!proposerExists)), - ), - ) - - return &types.MsgCreateSequencerResponse{}, nil -} diff --git a/x/sequencer/keeper/msg_server_create_sequencer_test.go b/x/sequencer/keeper/msg_server_create_sequencer_test.go deleted file mode 100644 index 67518981b..000000000 --- a/x/sequencer/keeper/msg_server_create_sequencer_test.go +++ /dev/null @@ -1,575 +0,0 @@ -package keeper_test - -import ( - "errors" - "fmt" - "reflect" - "slices" - "time" - - errorsmod "cosmossdk.io/errors" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/query" - bankutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" - "github.com/dymensionxyz/sdk-utils/utils/urand" - - "github.com/dymensionxyz/dymension/v3/testutil/sample" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -const ( - alice = "cosmos1jmjfq0tplp9tmx4v9uemw72y4d2wa5nr3xn9d3" - bech32Prefix = "eth" -) - -var bond = types.DefaultParams().MinBond - -func (suite *SequencerTestSuite) TestMinBond() { - panicErr := errors.New("panic") - - testCases := []struct { - name string - requiredBond sdk.Coin - bond sdk.Coin - expectedError error - }{ - { - name: "Valid bond", - requiredBond: bond, - bond: bond, - expectedError: nil, - }, - { - name: "Insufficient bond", - requiredBond: bond, - bond: sdk.NewCoin(bond.Denom, bond.Amount.Quo(sdk.NewInt(2))), - expectedError: types.ErrInsufficientBond, - }, - { - name: "wrong bond denom", - requiredBond: bond, - bond: sdk.NewCoin("nonbonddenom", bond.Amount), - expectedError: panicErr, - }, - } - - for _, tc := range testCases { - suite.Run(tc.name, func() { - seqParams := types.DefaultParams() - seqParams.MinBond = tc.requiredBond - suite.App.SequencerKeeper.SetParams(suite.Ctx, seqParams) - - rollappId, pk := suite.CreateDefaultRollapp() - - // fund account - addr := sdk.AccAddress(pk.Address()) - pkAny, err := codectypes.NewAnyWithValue(pk) - suite.Require().Nil(err) - err = bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, addr, sdk.NewCoins(tc.bond)) - suite.Require().Nil(err) - - sequencerMsg1 := types.MsgCreateSequencer{ - Creator: addr.String(), - DymintPubKey: pkAny, - Bond: tc.bond, - RollappId: rollappId, - Metadata: types.SequencerMetadata{ - Rpcs: []string{"https://rpc.wpd.evm.rollapp.noisnemyd.xyz:443"}, - }, - } - - // Use a defer and recover to catch potential panics - var createErr error - func() { - defer func() { - if r := recover(); r != nil { - createErr = errorsmod.Wrapf(panicErr, "panic: %v", r) - } - }() - _, createErr = suite.msgServer.CreateSequencer(suite.Ctx, &sequencerMsg1) - }() - - if tc.expectedError != nil { - suite.Require().ErrorAs(createErr, &tc.expectedError, tc.name) - } else { - suite.Require().NoError(createErr) - sequencer, found := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr.String()) - suite.Require().True(found, tc.name) - if tc.requiredBond.IsNil() { - suite.Require().True(sequencer.Tokens.IsZero(), tc.name) - } else { - suite.Require().Equal(sdk.NewCoins(tc.requiredBond), sequencer.Tokens, tc.name) - } - } - }) - } -} - -func (suite *SequencerTestSuite) TestCreateSequencer() { - suite.SetupTest() - goCtx := sdk.WrapSDKContext(suite.Ctx) - - // sequencersExpect is the expected result of query all - sequencersExpect := []*types.Sequencer{} - - // rollappSequencersExpect is a map from rollappId to a map of sequencer addresses list - type rollappSequencersExpectKey struct { - rollappId, sequencerAddress string - } - rollappSequencersExpect := make(map[rollappSequencersExpectKey]string) - rollappExpectedProposers := make(map[string]string) - - const numRollapps = 3 - rollappIDs := make([]string, numRollapps) - // for 3 rollapps, test 10 sequencers creations - for j := 0; j < numRollapps; j++ { - rollapp := rollapptypes.Rollapp{ - RollappId: urand.RollappID(), - Owner: alice, - Launched: true, - Metadata: &rollapptypes.RollappMetadata{ - Website: "https://dymension.xyz", - Description: "Sample description", - LogoUrl: "https://dymension.xyz/logo.png", - Telegram: "https://t.me/rolly", - X: "https://x.dymension.xyz", - }, - GenesisInfo: rollapptypes.GenesisInfo{ - Bech32Prefix: bech32Prefix, - GenesisChecksum: "1234567890abcdefg", - InitialSupply: sdk.NewInt(1000), - NativeDenom: rollapptypes.DenomMetadata{ - Display: "DEN", - Base: "aden", - Exponent: 18, - }, - }, - } - suite.App.RollappKeeper.SetRollapp(suite.Ctx, rollapp) - - rollappId := rollapp.GetRollappId() - rollappIDs[j] = rollappId - - for i := 0; i < 10; i++ { - pubkey := ed25519.GenPrivKey().PubKey() - addr := sdk.AccAddress(pubkey.Address()) - addr1 := sdk.AccAddress(pubkey.Address()) - err := bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, addr, sdk.NewCoins(bond)) - suite.Require().NoError(err) - pkAny, err := codectypes.NewAnyWithValue(pubkey) - suite.Require().Nil(err) - - // sequencer is the sequencer to create - sequencerMsg := types.MsgCreateSequencer{ - Creator: addr.String(), - DymintPubKey: pkAny, - Bond: bond, - RollappId: rollappId, - Metadata: types.SequencerMetadata{ - Rpcs: []string{"https://rpc.wpd.evm.rollapp.noisnemyd.xyz:443"}, - }, - RewardAddr: addr1.String(), - WhitelistedRelayers: []string{addr.String()}, - } - // sequencerExpect is the expected result of creating a sequencer - sequencerExpect := types.Sequencer{ - Address: sequencerMsg.GetCreator(), - DymintPubKey: sequencerMsg.GetDymintPubKey(), - Status: types.Bonded, - RollappId: rollappId, - Tokens: sdk.NewCoins(bond), - Metadata: sequencerMsg.GetMetadata(), - RewardAddr: addr1.String(), - WhitelistedRelayers: []string{addr.String()}, - } - - // create sequencer - createResponse, err := suite.msgServer.CreateSequencer(goCtx, &sequencerMsg) - suite.Require().Nil(err) - suite.Require().EqualValues(types.MsgCreateSequencerResponse{}, *createResponse) - - // query the specific sequencer - queryResponse, err := suite.queryClient.Sequencer(goCtx, &types.QueryGetSequencerRequest{ - SequencerAddress: sequencerMsg.GetCreator(), - }) - suite.Require().Nil(err) - suite.equalSequencer(&sequencerExpect, &queryResponse.Sequencer) - - // add the sequencer to the list of get all expected list - sequencersExpect = append(sequencersExpect, &sequencerExpect) - - if i == 0 { - rollappExpectedProposers[rollappId] = sequencerExpect.Address - } - - sequencersRes, totalRes := getAll(suite) - suite.Require().EqualValues(len(sequencersExpect), totalRes) - // verify that query all contains all the sequencers that were created - suite.verifyAll(sequencersExpect, sequencersRes) - - // add the sequencer to the list of specific rollapp - rollappSequencersExpect[rollappSequencersExpectKey{rollappId, sequencerExpect.Address}] = sequencerExpect.Address - } - } - - totalFound := 0 - // check query by rollapp - for i := 0; i < numRollapps; i++ { - rollappId := rollappIDs[i] - queryAllResponse, err := suite.queryClient.SequencersByRollapp(goCtx, - &types.QueryGetSequencersByRollappRequest{RollappId: rollappId}) - suite.Require().Nil(err) - // verify that all the addresses of the rollapp are found - for _, sequencer := range queryAllResponse.Sequencers { - suite.Require().EqualValues(rollappSequencersExpect[rollappSequencersExpectKey{rollappId, sequencer.Address}], - sequencer.Address) - } - totalFound += len(queryAllResponse.Sequencers) - - // check that the first sequencer created is the active sequencer - proposer, err := suite.queryClient.GetProposerByRollapp(goCtx, - &types.QueryGetProposerByRollappRequest{RollappId: rollappId}) - suite.Require().Nil(err) - suite.Require().EqualValues(proposer.ProposerAddr, rollappExpectedProposers[rollappId]) - } - suite.Require().EqualValues(totalFound, len(rollappSequencersExpect)) -} - -func (suite *SequencerTestSuite) TestCreateSequencerAlreadyExists() { - suite.SetupTest() - goCtx := sdk.WrapSDKContext(suite.Ctx) - - rollappId, pk := suite.CreateDefaultRollapp() - addr := sdk.AccAddress(pk.Address()) - err := bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, addr, sdk.NewCoins(bond)) - suite.Require().NoError(err) - - pkAny, err := codectypes.NewAnyWithValue(pk) - suite.Require().Nil(err) - sequencerMsg := types.MsgCreateSequencer{ - Creator: addr.String(), - DymintPubKey: pkAny, - Bond: bond, - RollappId: rollappId, - Metadata: types.SequencerMetadata{ - Rpcs: []string{"https://rpc.wpd.evm.rollapp.noisnemyd.xyz:443"}, - }, - } - _, err = suite.msgServer.CreateSequencer(goCtx, &sequencerMsg) - suite.Require().Nil(err) - - _, err = suite.msgServer.CreateSequencer(goCtx, &sequencerMsg) - suite.EqualError(err, types.ErrSequencerExists.Error()) - - // unbond the sequencer - unbondMsg := types.MsgUnbond{Creator: addr.String()} - _, err = suite.msgServer.Unbond(goCtx, &unbondMsg) - suite.Require().NoError(err) - - // create the sequencer again, expect to fail anyway - _, err = suite.msgServer.CreateSequencer(goCtx, &sequencerMsg) - suite.EqualError(err, types.ErrSequencerExists.Error()) -} - -func (suite *SequencerTestSuite) TestCreateSequencerInitialSequencerAsProposer() { - const alex = "dym1te3lcav5c2jn8tdcrhnyl8aden6lglw266kcdd" - - type sequencer struct { - creatorName string - expProposer bool - } - testCases := []struct { - name, - rollappInitialSeq string - sequencers []sequencer - malleate func(rollappID string) - expErr error - }{ - { - name: "Single initial sequencer is the first proposer", - sequencers: []sequencer{{creatorName: "alex", expProposer: true}}, - rollappInitialSeq: alex, - }, { - name: "Two sequencers - one is the proposer", - sequencers: []sequencer{{creatorName: "alex", expProposer: true}, {creatorName: "bob", expProposer: false}}, - rollappInitialSeq: fmt.Sprintf("%s,%s", alice, alex), - }, { - name: "One sequencer - failed because no initial sequencer", - sequencers: []sequencer{{creatorName: "bob", expProposer: false}}, - rollappInitialSeq: alice, - expErr: types.ErrNotInitialSequencer, - }, { - name: "Any sequencer can be the first proposer", - sequencers: []sequencer{{creatorName: "bob", expProposer: true}, {creatorName: "steve", expProposer: false}}, - rollappInitialSeq: "*", - }, { - name: "success - any sequencer can be the first proposer, rollapp launched", - sequencers: []sequencer{{creatorName: "bob", expProposer: false}}, - rollappInitialSeq: alice, - malleate: func(rollappID string) { - r, _ := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappID) - r.Launched = true - suite.App.RollappKeeper.SetRollapp(suite.Ctx, r) - }, - expErr: nil, - }, { - name: "success - no initial sequencer, rollapp launched", - sequencers: []sequencer{{creatorName: "bob", expProposer: false}}, - rollappInitialSeq: "*", - malleate: func(rollappID string) { - r, _ := suite.App.RollappKeeper.GetRollapp(suite.Ctx, rollappID) - r.Launched = true - suite.App.RollappKeeper.SetRollapp(suite.Ctx, r) - }, - expErr: nil, - }, - } - - for _, tc := range testCases { - suite.SetupTest() - - goCtx := sdk.WrapSDKContext(suite.Ctx) - rollappId := suite.CreateRollappWithInitialSequencer(tc.rollappInitialSeq) - - if tc.malleate != nil { - tc.malleate(rollappId) - } - - for _, seq := range tc.sequencers { - addr, pk := sample.AccFromSecret(seq.creatorName) - pkAny, _ := codectypes.NewAnyWithValue(pk) - - err := bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, addr, sdk.NewCoins(bond)) - suite.Require().NoError(err) - - sequencerMsg := types.MsgCreateSequencer{ - Creator: addr.String(), - DymintPubKey: pkAny, - Bond: bond, - RollappId: rollappId, - Metadata: types.SequencerMetadata{ - Rpcs: []string{"https://rpc.wpd.evm.rollapp.noisnemyd.xyz:443"}, - }, - } - _, err = suite.msgServer.CreateSequencer(goCtx, &sequencerMsg) - suite.Require().ErrorIs(err, tc.expErr, tc.name) - - if tc.expErr != nil { - return - } - - // check that the sequencer is the proposer - proposer, ok := suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - if seq.expProposer { - suite.Require().Equal(addr.String(), proposer.Address, tc.name) - } else { - suite.Require().NotEqual(addr.String(), proposer.Address, tc.name) - } - } - } -} - -func (suite *SequencerTestSuite) TestCreateSequencerUnknownRollappId() { - suite.SetupTest() - goCtx := sdk.WrapSDKContext(suite.Ctx) - - pubkey := ed25519.GenPrivKey().PubKey() - addr := sdk.AccAddress(pubkey.Address()) - err := bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, addr, sdk.NewCoins(bond)) - suite.Require().NoError(err) - - pkAny, err := codectypes.NewAnyWithValue(pubkey) - suite.Require().Nil(err) - sequencerMsg := types.MsgCreateSequencer{ - Creator: addr.String(), - DymintPubKey: pkAny, - Bond: bond, - RollappId: "rollappId", - Metadata: types.SequencerMetadata{}, - } - - _, err = suite.msgServer.CreateSequencer(goCtx, &sequencerMsg) - suite.EqualError(err, types.ErrUnknownRollappID.Error()) -} - -// create sequencer before genesisInfo is set -func (suite *SequencerTestSuite) TestCreateSequencerBeforeGenesisInfo() { - suite.SetupTest() - goCtx := sdk.WrapSDKContext(suite.Ctx) - rollappId, pk := suite.CreateDefaultRollapp() - - // mess up the genesisInfo - rollapp := suite.App.RollappKeeper.MustGetRollapp(suite.Ctx, rollappId) - rollapp.GenesisInfo.Bech32Prefix = "" - suite.App.RollappKeeper.SetRollapp(suite.Ctx, rollapp) - - addr := sdk.AccAddress(pk.Address()) - err := bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, addr, sdk.NewCoins(bond)) - suite.Require().NoError(err) - - pkAny, err := codectypes.NewAnyWithValue(pk) - suite.Require().Nil(err) - sequencerMsg := types.MsgCreateSequencer{ - Creator: addr.String(), - DymintPubKey: pkAny, - Bond: bond, - RollappId: rollappId, - Metadata: types.SequencerMetadata{ - Rpcs: []string{"https://rpc.wpd.evm.rollapp.noisnemyd.xyz:443"}, - }, - } - - _, err = suite.msgServer.CreateSequencer(goCtx, &sequencerMsg) - suite.Require().Error(err) - - // set the genesisInfo - rollapp.GenesisInfo.Bech32Prefix = "rol" - suite.App.RollappKeeper.SetRollapp(suite.Ctx, rollapp) - - _, err = suite.msgServer.CreateSequencer(goCtx, &sequencerMsg) - suite.Require().NoError(err) -} - -// create sequencer before prelaunch -func (suite *SequencerTestSuite) TestCreateSequencerBeforePrelaunch() { - suite.SetupTest() - rollappId, pk := suite.CreateDefaultRollapp() - - // set prelaunch time to the rollapp - preLaunchTime := time.Now() - rollapp := suite.App.RollappKeeper.MustGetRollapp(suite.Ctx, rollappId) - rollapp.PreLaunchTime = &preLaunchTime - suite.App.RollappKeeper.SetRollapp(suite.Ctx, rollapp) - - addr := sdk.AccAddress(pk.Address()) - err := bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, addr, sdk.NewCoins(bond)) - suite.Require().NoError(err) - - pkAny, err := codectypes.NewAnyWithValue(pk) - suite.Require().Nil(err) - sequencerMsg := types.MsgCreateSequencer{ - Creator: addr.String(), - DymintPubKey: pkAny, - Bond: bond, - RollappId: rollappId, - Metadata: types.SequencerMetadata{ - Rpcs: []string{"https://rpc.wpd.evm.rollapp.noisnemyd.xyz:443"}, - }, - } - - _, err = suite.msgServer.CreateSequencer(sdk.WrapSDKContext(suite.Ctx), &sequencerMsg) - suite.Require().Error(err) - - suite.Ctx = suite.Ctx.WithBlockTime(preLaunchTime.Add(time.Second)) - _, err = suite.msgServer.CreateSequencer(sdk.WrapSDKContext(suite.Ctx), &sequencerMsg) - suite.Require().NoError(err) -} - -// --------------------------------------- -// verifyAll receives a list of expected results and a map of sequencerAddress->sequencer -// the function verifies that the map contains all the sequencers that are in the list and only them -func (suite *SequencerTestSuite) verifyAll(sequencersExpect []*types.Sequencer, sequencersRes map[string]*types.Sequencer) { - // check number of items are equal - suite.Require().EqualValues(len(sequencersExpect), len(sequencersRes)) - for i := 0; i < len(sequencersExpect); i++ { - sequencerExpect := sequencersExpect[i] - sequencerRes := sequencersRes[sequencerExpect.GetAddress()] - suite.equalSequencer(sequencerExpect, sequencerRes) - } -} - -// getAll quires for all existing sequencers and returns a map of sequencerId->sequencer -func getAll(suite *SequencerTestSuite) (map[string]*types.Sequencer, int) { - goCtx := sdk.WrapSDKContext(suite.Ctx) - totalChecked := 0 - totalRes := 0 - nextKey := []byte{} - sequencersRes := make(map[string]*types.Sequencer) - for { - queryAllResponse, err := suite.queryClient.Sequencers(goCtx, - &types.QuerySequencersRequest{ - Pagination: &query.PageRequest{ - Key: nextKey, - Offset: 0, - Limit: 0, - CountTotal: true, - Reverse: false, - }, - }) - suite.Require().Nil(err) - - if totalRes == 0 { - totalRes = int(queryAllResponse.GetPagination().GetTotal()) - } - - for i := 0; i < len(queryAllResponse.Sequencers); i++ { - sequencerRes := queryAllResponse.Sequencers[i] - sequencersRes[sequencerRes.GetAddress()] = &sequencerRes - } - totalChecked += len(queryAllResponse.Sequencers) - nextKey = queryAllResponse.GetPagination().GetNextKey() - - if nextKey == nil { - break - } - } - - return sequencersRes, totalRes -} - -// equalSequencer receives two sequencers and compares them. If they are not equal, fails the test -func (suite *SequencerTestSuite) equalSequencer(s1 *types.Sequencer, s2 *types.Sequencer) { - suite.T().Helper() - eq := compareSequencers(s1, s2) - suite.Require().True(eq, "expected: %v\nfound: %v", *s1, *s2) -} - -func compareSequencers(s1, s2 *types.Sequencer) bool { - if s1.Address != s2.Address { - return false - } - - s1Pubkey := s1.DymintPubKey - s2Pubkey := s2.DymintPubKey - if !s1Pubkey.Equal(s2Pubkey) { - return false - } - if s1.RollappId != s2.RollappId { - return false - } - - if s1.Jailed != s2.Jailed { - return false - } - if s1.Status != s2.Status { - return false - } - - if !s1.Tokens.IsEqual(s2.Tokens) { - return false - } - - if s1.UnbondRequestHeight != s2.UnbondRequestHeight { - return false - } - if !s1.UnbondTime.Equal(s2.UnbondTime) { - return false - } - if !s1.NoticePeriodTime.Equal(s2.NoticePeriodTime) { - return false - } - if !reflect.DeepEqual(s1.Metadata, s2.Metadata) { - return false - } - if s1.RewardAddr != s2.RewardAddr { - return false - } - if !slices.Equal(s1.WhitelistedRelayers, s2.WhitelistedRelayers) { - return false - } - return true -} diff --git a/x/sequencer/keeper/msg_server_create_test.go b/x/sequencer/keeper/msg_server_create_test.go new file mode 100644 index 000000000..ba59eefb2 --- /dev/null +++ b/x/sequencer/keeper/msg_server_create_test.go @@ -0,0 +1,287 @@ +package keeper_test + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/query" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" + "github.com/dymensionxyz/sdk-utils/utils/uptr" + "github.com/dymensionxyz/sdk-utils/utils/urand" + "github.com/dymensionxyz/sdk-utils/utils/utest" +) + +// On success, we should get back an object with all the right info +func (s *SequencerTestSuite) TestCreateSequencerBasic() { + ra := s.createRollapp() + s.fundSequencer(alice, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, alice) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + s.Require().NoError(err) + seq, err := s.k().RealSequencer(s.Ctx, pkAddr(alice)) + s.Require().NoError(err) + s.Require().Equal(seq.Address, pkAddr(alice)) + s.Require().True(bond.Equal(seq.TokensCoin())) + s.Require().Equal(s.moduleBalance(), bond) + s.Require().True(s.k().IsProposer(s.Ctx, seq)) + s.Require().True(equalSequencers(uptr.To(expectedSequencer(&msg)), &seq)) +} + +func (s *SequencerTestSuite) TestCreateSequencerSeveral() { + ra := s.createRollapp() + + for _, pk := range pks { + s.fundSequencer(pk, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, pk) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + s.Require().NoError(err) + } + + getOneRes := make([]*types.Sequencer, 0) + + for _, pk := range pks { + res, err := s.queryClient.Sequencer( + sdk.WrapSDKContext(s.Ctx), + &types.QueryGetSequencerRequest{ + SequencerAddress: pkAddr(pk), + }, + ) + s.Require().NoError(err) + getOneRes = append(getOneRes, &res.Sequencer) + } + + allRes, cnt := getAllSequencersMap(s) + s.Require().Equal(cnt, len(allRes)) + s.compareAllSequencersResponse(getOneRes, allRes) +} + +// There are several reasons to reject creation +func (s *SequencerTestSuite) TestCreateSequencerRestrictions() { + ra := s.createRollapp() + + s.Run("not allowed - no rollapp", func() { + s.fundSequencer(alice, bond) + msg := createSequencerMsgOnePubkey(urand.RollappID(), alice) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + utest.IsErr(s.Require(), err, gerrc.ErrNotFound) + }) + s.Run("not allowed - already exist", func() { + pk := randomTMPubKey() + s.fundSequencer(pk, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, pk) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + s.Require().NoError(err) + _, err = s.msgServer.CreateSequencer(s.Ctx, &msg) + utest.IsErr(s.Require(), err, gerrc.ErrAlreadyExists) + }) + s.Run("not allowed - pub key in use", func() { + pk := randomTMPubKey() + s.fundSequencer(pk, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, pk) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + s.Require().NoError(err) + s.fundSequencer(alice, bond) + msg = createSequencerMsg(ra.RollappId, alice, pk) + msg.Bond = bond + _, err = s.msgServer.CreateSequencer(s.Ctx, &msg) + utest.IsErr(s.Require(), err, gerrc.ErrAlreadyExists) + }) + + s.Run("not allowed - insufficient bond", func() { + s.fundSequencer(alice, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, alice) + msg.Bond = bond + msg.Bond.Amount = msg.Bond.Amount.Sub(sdk.OneInt()) + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + utest.IsErr(s.Require(), err, gerrc.ErrOutOfRange) + }) + s.Run("not allowed - wrong denom", func() { + s.fundSequencer(alice, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, alice) + msg.Bond = bond + msg.Bond.Denom = "foo" + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + utest.IsErr(s.Require(), err, gerrc.ErrInvalidArgument) + }) + s.Run("not allowed - vm", func() { + ra := s.createRollapp() + ra.VmType = rollapptypes.Rollapp_EVM + s.raK().SetRollapp(s.Ctx, ra) + s.fundSequencer(alice, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, alice) + msg.Bond = bond + msg.Metadata.EvmRpcs = msg.Metadata.EvmRpcs[:0] + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + utest.IsErr(s.Require(), err, gerrc.ErrInvalidArgument) + }) + s.Run("not allowed - not launched and not initial", func() { + ra := s.createRollappWithInitialSeqConstraint("") + s.Require().False(ra.Launched) + + s.fundSequencer(alice, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, alice) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) + }) + + s.Run("not allowed - pre launch", func() { + ra := s.createRollappWithInitialSeqConstraint("*") + s.Require().False(ra.Launched) + ra.PreLaunchTime = uptr.To(s.Ctx.BlockTime().Add(time.Hour)) + s.raK().SetRollapp(s.Ctx, ra) + + seq := david + s.fundSequencer(seq, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, seq) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) + + _, err = s.msgServer.CreateSequencer(s.Ctx.WithBlockTime(*ra.PreLaunchTime), &msg) + s.Require().NoError(err) + }) + + s.Run("allowed - launched", func() { + seq := alice + ra := s.createRollappWithInitialSeqConstraint("") + ra.Launched = true + s.raK().SetRollapp(s.Ctx, ra) + + s.fundSequencer(seq, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, seq) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + s.Require().NoError(err) + }) + s.Run("allowed - pre launch and is initial", func() { + seq := bob + ra := s.createRollappWithInitialSeqConstraint(pkAddr(bob)) + s.Require().False(ra.Launched) + + s.fundSequencer(seq, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, seq) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + s.Require().NoError(err) + }) + s.Run("not allowed - genesis info broken", func() { + seq := charlie + ra := s.createRollapp() + ra.GenesisInfo.Bech32Prefix = "" + s.raK().SetRollapp(s.Ctx, ra) + + s.fundSequencer(seq, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, seq) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) + + ra.GenesisInfo.Bech32Prefix = "eth" + s.raK().SetRollapp(s.Ctx, ra) + + _, err = s.msgServer.CreateSequencer(s.Ctx, &msg) + s.Require().NoError(err) + }) +} + +// TestCreateSequencerRestrictions2 +// TODO: subtests in here were breaking when in the main test, but not sure why +func (s *SequencerTestSuite) TestCreateSequencerRestrictions2() { + ra := s.createRollapp() + s.Run("not allowed - awaitingLastProposerBlock", func() { + // create one proposer and finish their notice + pk := randomTMPubKey() + s.fundSequencer(pk, bond) + msg := createSequencerMsgOnePubkey(ra.RollappId, pk) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(s.Ctx, &msg) + s.Require().NoError(err) + seq := s.k().GetSequencer(s.Ctx, pkAddr(pk)) + s.k().StartNoticePeriod(s.Ctx, &seq) + s.k().SetSequencer(s.Ctx, seq) + + // try to create another one + s.Ctx = s.Ctx.WithBlockTime(seq.NoticePeriodTime) + s.fundSequencer(alice, bond) + msg = createSequencerMsgOnePubkey(ra.RollappId, alice) + msg.Bond = bond + _, err = s.msgServer.CreateSequencer(s.Ctx, &msg) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) + }) +} + +func expectedSequencer(m *types.MsgCreateSequencer) types.Sequencer { + return types.Sequencer{ + Address: m.Creator, + DymintPubKey: m.DymintPubKey, + RollappId: m.RollappId, + Metadata: m.Metadata, + Status: types.Bonded, + OptedIn: true, + Tokens: sdk.NewCoins(m.Bond), + NoticePeriodTime: time.Time{}, + RewardAddr: m.Creator, + } +} + +// returns sequencer, total> +func getAllSequencersMap(suite *SequencerTestSuite) (map[string]*types.Sequencer, int) { + goCtx := sdk.WrapSDKContext(suite.Ctx) + totalChecked := 0 + totalRes := 0 + nextKey := []byte{} + sequencersRes := make(map[string]*types.Sequencer) + for { + queryAllResponse, err := suite.queryClient.Sequencers(goCtx, + &types.QuerySequencersRequest{ + Pagination: &query.PageRequest{ + Key: nextKey, + Offset: 0, + Limit: 0, + CountTotal: true, + Reverse: false, + }, + }) + suite.Require().Nil(err) + + if totalRes == 0 { + totalRes = int(queryAllResponse.GetPagination().GetTotal()) + } + + for i := 0; i < len(queryAllResponse.Sequencers); i++ { + sequencerRes := queryAllResponse.Sequencers[i] + sequencersRes[sequencerRes.GetAddress()] = &sequencerRes + } + totalChecked += len(queryAllResponse.Sequencers) + nextKey = queryAllResponse.GetPagination().GetNextKey() + + if nextKey == nil { + break + } + } + + return sequencersRes, totalRes +} + +// verifyAll receives a list of expected results and a map of sequencerAddress->sequencer +// the function verifies that the map contains all the sequencers that are in the list and only them +func (s *SequencerTestSuite) compareAllSequencersResponse( + expected []*types.Sequencer, + got map[string]*types.Sequencer, +) { + // check number of items are equal + s.Require().EqualValues(len(expected), len(got)) + for i := 0; i < len(expected); i++ { + exp := expected[i] + res := got[exp.GetAddress()] + s.equalSequencers(exp, res) + } +} diff --git a/x/sequencer/keeper/msg_server_decrease_bond.go b/x/sequencer/keeper/msg_server_decrease_bond.go deleted file mode 100644 index aa6f4981e..000000000 --- a/x/sequencer/keeper/msg_server_decrease_bond.go +++ /dev/null @@ -1,52 +0,0 @@ -package keeper - -import ( - "context" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -// DecreaseBond implements types.MsgServer. -func (k msgServer) DecreaseBond(goCtx context.Context, msg *types.MsgDecreaseBond) (*types.MsgDecreaseBondResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - sequencer, found := k.GetSequencer(ctx, msg.GetCreator()) - if !found { - return nil, types.ErrUnknownSequencer - } - if !sequencer.IsBonded() { - return nil, types.ErrInvalidSequencerStatus - } - - effectiveBond := sequencer.Tokens - if bds := k.GetBondReductionsBySequencer(ctx, msg.Creator); len(bds) > 0 { - for _, bd := range bds { - effectiveBond = effectiveBond.Sub(bd.DecreaseBondAmount) - } - } - - // Check if the sequencer has enough bond to decrease - if !effectiveBond.IsZero() && effectiveBond.IsAllLTE(sdk.NewCoins(msg.DecreaseAmount)) { - return nil, types.ErrInsufficientBond - } - - // Check if the bond reduction will make the sequencer's bond less than the minimum bond value - minBondValue := k.GetParams(ctx).MinBond - if !minBondValue.IsNil() && !minBondValue.IsZero() { - decreasedBondValue := effectiveBond.Sub(msg.DecreaseAmount) - if decreasedBondValue.IsAllLT(sdk.NewCoins(minBondValue)) { - return nil, types.ErrInsufficientBond - } - } - completionTime := ctx.BlockHeader().Time.Add(k.UnbondingTime(ctx)) - k.SetDecreasingBondQueue(ctx, types.BondReduction{ - SequencerAddress: msg.Creator, - DecreaseBondAmount: msg.DecreaseAmount, - DecreaseBondTime: completionTime, - }) - - return &types.MsgDecreaseBondResponse{ - CompletionTime: completionTime, - }, nil -} diff --git a/x/sequencer/keeper/msg_server_decrease_bond_test.go b/x/sequencer/keeper/msg_server_decrease_bond_test.go deleted file mode 100644 index 3a42cdb4a..000000000 --- a/x/sequencer/keeper/msg_server_decrease_bond_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package keeper_test - -import ( - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -func (suite *SequencerTestSuite) TestDecreaseBond() { - suite.SetupTest() - bondDenom := types.DefaultParams().MinBond.Denom - rollappId, pk := suite.CreateDefaultRollapp() - // setup a default sequencer with has minBond + 20token - defaultSequencerAddress := suite.CreateSequencerWithBond(suite.Ctx, rollappId, bond.AddAmount(sdk.NewInt(20)), pk) - // setup an unbonded sequencer - unbondedPk := ed25519.GenPrivKey().PubKey() - unbondedSequencerAddress := suite.CreateSequencer(suite.Ctx, rollappId, unbondedPk) - unbondedSequencer, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, unbondedSequencerAddress) - unbondedSequencer.Status = types.Unbonded - suite.App.SequencerKeeper.UpdateSequencer(suite.Ctx, &unbondedSequencer, unbondedSequencer.Status) - // setup a jailed sequencer - jailedPk := ed25519.GenPrivKey().PubKey() - jailedSequencerAddress := suite.CreateSequencer(suite.Ctx, rollappId, jailedPk) - jailedSequencer, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, jailedSequencerAddress) - jailedSequencer.Jailed = true - suite.App.SequencerKeeper.UpdateSequencer(suite.Ctx, &jailedSequencer, jailedSequencer.Status) - - testCase := []struct { - name string - msg types.MsgDecreaseBond - expectedErr error - }{ - { - name: "invalid sequencer", - msg: types.MsgDecreaseBond{ - Creator: "invalid_address", - DecreaseAmount: sdk.NewInt64Coin(bondDenom, 10), - }, - expectedErr: types.ErrUnknownSequencer, - }, - { - name: "sequencer is not bonded", - msg: types.MsgDecreaseBond{ - Creator: unbondedSequencerAddress, - DecreaseAmount: sdk.NewInt64Coin(bondDenom, 10), - }, - expectedErr: types.ErrInvalidSequencerStatus, - }, - { - name: "decreased bond value to less than minimum bond value", - msg: types.MsgDecreaseBond{ - Creator: defaultSequencerAddress, - DecreaseAmount: sdk.NewInt64Coin(bondDenom, 100), - }, - expectedErr: types.ErrInsufficientBond, - }, - { - name: "trying to decrease more bond than they have tokens bonded", - msg: types.MsgDecreaseBond{ - Creator: defaultSequencerAddress, - DecreaseAmount: bond.AddAmount(sdk.NewInt(30)), - }, - expectedErr: types.ErrInsufficientBond, - }, - { - name: "valid decrease bond", - msg: types.MsgDecreaseBond{ - Creator: defaultSequencerAddress, - DecreaseAmount: sdk.NewInt64Coin(bondDenom, 10), - }, - }, - } - - for _, tc := range testCase { - suite.Run(tc.name, func() { - resp, err := suite.msgServer.DecreaseBond(suite.Ctx, &tc.msg) - if tc.expectedErr != nil { - suite.Require().ErrorIs(err, tc.expectedErr) - } else { - suite.Require().NoError(err) - suite.Require().NotNil(resp) - expectedCompletionTime := suite.Ctx.BlockHeader().Time.Add(suite.App.SequencerKeeper.UnbondingTime(suite.Ctx)) - suite.Require().Equal(expectedCompletionTime, resp.CompletionTime) - // check if the unbonding is set correctly - bondReductionIDs := suite.App.SequencerKeeper.GetMatureDecreasingBondIDs(suite.Ctx, expectedCompletionTime) - suite.Require().Len(bondReductionIDs, 1) - bondReduction, found := suite.App.SequencerKeeper.GetBondReduction(suite.Ctx, bondReductionIDs[0]) - suite.Require().True(found) - suite.Require().Equal(tc.msg.Creator, bondReduction.SequencerAddress) - suite.Require().Equal(tc.msg.DecreaseAmount, bondReduction.DecreaseBondAmount) - } - }) - } -} - -func (suite *SequencerTestSuite) TestDecreaseBond_BondDecreaseInProgress() { - suite.SetupTest() - bondDenom := types.DefaultParams().MinBond.Denom - rollappId, pk := suite.CreateDefaultRollapp() - // setup a default sequencer with has minBond + 20token - defaultSequencerAddress := suite.CreateSequencerWithBond(suite.Ctx, rollappId, bond.AddAmount(sdk.NewInt(20)), pk) - // decrease the bond of the sequencer - _, err := suite.msgServer.DecreaseBond(suite.Ctx, &types.MsgDecreaseBond{ - Creator: defaultSequencerAddress, - DecreaseAmount: sdk.NewInt64Coin(bondDenom, 10), - }) - suite.Require().NoError(err) - // try to decrease the bond again - should be fine as still not below minbond - suite.Ctx = suite.Ctx.WithBlockHeight(suite.Ctx.BlockHeight() + 1).WithBlockTime(suite.Ctx.BlockTime().Add(10)) - _, err = suite.msgServer.DecreaseBond(suite.Ctx, &types.MsgDecreaseBond{ - Creator: defaultSequencerAddress, - DecreaseAmount: sdk.NewInt64Coin(bondDenom, 10), - }) - suite.Require().NoError(err) - // try to decrease the bond again - should err as below minbond - suite.Ctx = suite.Ctx.WithBlockHeight(suite.Ctx.BlockHeight() + 1).WithBlockTime(suite.Ctx.BlockTime().Add(10)) - _, err = suite.msgServer.DecreaseBond(suite.Ctx, &types.MsgDecreaseBond{ - Creator: defaultSequencerAddress, - DecreaseAmount: sdk.NewInt64Coin(bondDenom, 10), - }) - suite.Require().ErrorIs(err, types.ErrInsufficientBond) -} diff --git a/x/sequencer/keeper/msg_server_increase_bond.go b/x/sequencer/keeper/msg_server_increase_bond.go deleted file mode 100644 index 5b5c7b234..000000000 --- a/x/sequencer/keeper/msg_server_increase_bond.go +++ /dev/null @@ -1,54 +0,0 @@ -package keeper - -import ( - "context" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/sdk-utils/utils/uevent" - - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -// IncreaseBond implements types.MsgServer. -func (k msgServer) IncreaseBond(goCtx context.Context, msg *types.MsgIncreaseBond) (*types.MsgIncreaseBondResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - sequencer, found := k.GetSequencer(ctx, msg.GetCreator()) - if !found { - return nil, types.ErrUnknownSequencer - } - if !sequencer.IsBonded() { - return nil, types.ErrInvalidSequencerStatus - } - - // transfer the bond from the sequencer to the module account - seqAcc := sdk.MustAccAddressFromBech32(msg.Creator) - err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, seqAcc, types.ModuleName, sdk.NewCoins(msg.AddAmount)) - if err != nil { - return nil, err - } - - // validate the addition amt is of same denom of existing bond - if found, _ := sequencer.Tokens.Find(msg.AddAmount.Denom); !found { - return nil, types.ErrInvalidCoinDenom - } - - // update the sequencers bond amount in state - sequencer.Tokens = sequencer.Tokens.Add(msg.AddAmount) - k.UpdateSequencer(ctx, &sequencer, sequencer.Status) - - // emit a typed event which includes the added amount and the active bond amount - err = uevent.EmitTypedEvent(ctx, - &types.EventIncreasedBond{ - Sequencer: msg.Creator, - Bond: sequencer.Tokens, - AddedAmount: msg.AddAmount, - }, - ) - if err != nil { - return nil, fmt.Errorf("emit event: %w", err) - } - - return &types.MsgIncreaseBondResponse{}, nil -} diff --git a/x/sequencer/keeper/msg_server_increase_bond_test.go b/x/sequencer/keeper/msg_server_increase_bond_test.go deleted file mode 100644 index 78e3aff10..000000000 --- a/x/sequencer/keeper/msg_server_increase_bond_test.go +++ /dev/null @@ -1,90 +0,0 @@ -package keeper_test - -import ( - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - bankutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" - - "github.com/dymensionxyz/dymension/v3/testutil/sample" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -func (suite *SequencerTestSuite) TestIncreaseBond() { - rollappId, pk := suite.CreateDefaultRollapp() - // setup a default sequencer - defaultSequencerAddress := suite.CreateSequencer(suite.Ctx, rollappId, pk) - // setup an unbonded sequencer - pk1 := ed25519.GenPrivKey().PubKey() - unbondedSequencerAddress := suite.CreateSequencer(suite.Ctx, rollappId, pk1) - unbondedSequencer, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, unbondedSequencerAddress) - unbondedSequencer.Status = types.Unbonded - suite.App.SequencerKeeper.UpdateSequencer(suite.Ctx, &unbondedSequencer, unbondedSequencer.Status) - // setup a jailed sequencer - pk2 := ed25519.GenPrivKey().PubKey() - jailedSequencerAddress := suite.CreateSequencer(suite.Ctx, rollappId, pk2) - jailedSequencer, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, jailedSequencerAddress) - jailedSequencer.Jailed = true - suite.App.SequencerKeeper.UpdateSequencer(suite.Ctx, &jailedSequencer, jailedSequencer.Status) - // fund all the sequencers which have been setup - bondAmount := sdk.NewInt64Coin(types.DefaultParams().MinBond.Denom, 100) - err := bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, sdk.MustAccAddressFromBech32(defaultSequencerAddress), sdk.NewCoins(bondAmount)) - suite.Require().NoError(err) - err = bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, sdk.MustAccAddressFromBech32(unbondedSequencerAddress), sdk.NewCoins(bondAmount)) - suite.Require().NoError(err) - err = bankutil.FundAccount(suite.App.BankKeeper, suite.Ctx, sdk.MustAccAddressFromBech32(jailedSequencerAddress), sdk.NewCoins(bondAmount)) - suite.Require().NoError(err) - - testCase := []struct { - name string - msg types.MsgIncreaseBond - expectedErr error - }{ - { - name: "valid", - msg: types.MsgIncreaseBond{ - Creator: defaultSequencerAddress, - AddAmount: bondAmount, - }, - expectedErr: nil, - }, - { - name: "invalid sequencer", - msg: types.MsgIncreaseBond{ - Creator: sample.AccAddress(), // a random address which is not a registered sequencer - AddAmount: bondAmount, - }, - expectedErr: types.ErrUnknownSequencer, - }, - { - name: "invalid sequencer status", - msg: types.MsgIncreaseBond{ - Creator: unbondedSequencerAddress, - AddAmount: bondAmount, - }, - expectedErr: types.ErrInvalidSequencerStatus, - }, - { - name: "sequencer doesn't have enough balance", - msg: types.MsgIncreaseBond{ - Creator: defaultSequencerAddress, - AddAmount: sdk.NewInt64Coin(types.DefaultParams().MinBond.Denom, 99999999), // very high amount which sequencer doesn't have - }, - expectedErr: sdkerrors.ErrInsufficientFunds, - }, - } - - for _, tc := range testCase { - suite.Run(tc.name, func() { - _, err := suite.msgServer.IncreaseBond(suite.Ctx, &tc.msg) - if tc.expectedErr != nil { - suite.Require().ErrorIs(err, tc.expectedErr) - } else { - suite.Require().NoError(err) - expectedBond := types.DefaultParams().MinBond.Add(bondAmount) - seq, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, defaultSequencerAddress) - suite.Require().Equal(expectedBond, seq.Tokens[0]) - } - }) - } -} diff --git a/x/sequencer/keeper/msg_server_kick_proposer.go b/x/sequencer/keeper/msg_server_kick_proposer.go new file mode 100644 index 000000000..af7fe3aa9 --- /dev/null +++ b/x/sequencer/keeper/msg_server_kick_proposer.go @@ -0,0 +1,25 @@ +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) + + 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, kicker); err != nil { + return nil, err + } + + return &types.MsgKickProposerResponse{}, nil +} diff --git a/x/sequencer/keeper/msg_server_kick_proposer_test.go b/x/sequencer/keeper/msg_server_kick_proposer_test.go new file mode 100644 index 000000000..b753fdb00 --- /dev/null +++ b/x/sequencer/keeper/msg_server_kick_proposer_test.go @@ -0,0 +1,48 @@ +package keeper_test + +import ( + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" + "github.com/dymensionxyz/sdk-utils/utils/utest" +) + +func (s *SequencerTestSuite) TestKickProposerBasicFlow() { + ra := s.createRollapp() + seqAlice := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) + s.Require().True(s.k().IsProposer(s.Ctx, seqAlice)) + + // 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.ErrFailedPrecondition) + + // bob creates a sequencer + seqBob := s.createSequencerWithBond(s.Ctx, ra.RollappId, bob, bond) + // suppose he's unbonded + seqBob.Status = types.Unbonded + s.k().SetSequencer(s.Ctx, seqBob) + + // bob tries to kick alice but he's not bonded + _, err = s.msgServer.KickProposer(s.Ctx, m) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) + + // bob bonds, but alice is not below kick threshold + seqBob.Status = types.Bonded + s.k().SetSequencer(s.Ctx, seqBob) + _, err = s.msgServer.KickProposer(s.Ctx, m) + s.Require().Error(err) + s.Require().True(s.k().IsProposer(s.Ctx, seqAlice)) + s.Require().False(s.k().IsProposer(s.Ctx, seqBob)) + + // alice falls to threshold + seqAlice.SetTokensCoin(kick) + s.k().SetSequencer(s.Ctx, seqAlice) + _, err = s.msgServer.KickProposer(s.Ctx, m) + s.Require().NoError(err) + s.Require().False(s.k().IsProposer(s.Ctx, seqAlice)) + + // bob is now proposer + s.Require().True(s.k().IsProposer(s.Ctx, seqBob)) + seqAlice = s.k().GetSequencer(s.Ctx, seqAlice.Address) + s.Require().Equal(types.Unbonded, seqAlice.Status) +} diff --git a/x/sequencer/keeper/msg_server_unbond.go b/x/sequencer/keeper/msg_server_unbond.go deleted file mode 100644 index aa7e73eef..000000000 --- a/x/sequencer/keeper/msg_server_unbond.go +++ /dev/null @@ -1,54 +0,0 @@ -package keeper - -import ( - "context" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -// Unbond defines a method for removing coins from sequencer's bond -func (k msgServer) Unbond(goCtx context.Context, msg *types.MsgUnbond) (*types.MsgUnbondResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - seq, found := k.GetSequencer(ctx, msg.Creator) - if !found { - return nil, types.ErrUnknownSequencer - } - - if !seq.IsBonded() { - return nil, errorsmod.Wrapf( - types.ErrInvalidSequencerStatus, - "sequencer status is not bonded: got %s", - seq.Status.String(), - ) - } - - if seq.UnbondRequestHeight != 0 { - return nil, errorsmod.Wrapf( - types.ErrInvalidSequencerStatus, - "sequencer has already requested to unbond", - ) - } - seq.UnbondRequestHeight = ctx.BlockHeight() - - // check if the sequencer is required for a notice period before unbonding - if k.isNoticePeriodRequired(ctx, seq) { - completionTime := k.startNoticePeriodForSequencer(ctx, &seq) - return &types.MsgUnbondResponse{ - CompletionTime: &types.MsgUnbondResponse_NoticePeriodCompletionTime{ - NoticePeriodCompletionTime: &completionTime, - }, - }, nil - } - - // otherwise, start unbonding - completionTime := k.startUnbondingPeriodForSequencer(ctx, &seq) - return &types.MsgUnbondResponse{ - CompletionTime: &types.MsgUnbondResponse_UnbondingCompletionTime{ - UnbondingCompletionTime: &completionTime, - }, - }, nil -} diff --git a/x/sequencer/keeper/msg_server_unbond_test.go b/x/sequencer/keeper/msg_server_unbond_test.go deleted file mode 100644 index 2ee11caf3..000000000 --- a/x/sequencer/keeper/msg_server_unbond_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package keeper_test - -import ( - "time" - - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -func (suite *SequencerTestSuite) TestUnbondingNonProposer() { - rollappId, pk := suite.CreateDefaultRollapp() - proposerAddr := suite.CreateSequencer(suite.Ctx, rollappId, pk) - - bondedAddr := suite.CreateDefaultSequencer(suite.Ctx, rollappId) - suite.Require().NotEqual(proposerAddr, bondedAddr) - - proposer, ok := suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - suite.Equal(proposerAddr, proposer.Address) - - /* ------------------------- unbond non proposer sequencer ------------------------ */ - bondedSeq, found := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, bondedAddr) - suite.Require().True(found) - suite.Equal(types.Bonded, bondedSeq.Status) - - unbondMsg := types.MsgUnbond{Creator: bondedAddr} - _, err := suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - - // check sequencer operating status - bondedSeq, found = suite.App.SequencerKeeper.GetSequencer(suite.Ctx, bondedAddr) - suite.Require().True(found) - suite.Equal(types.Unbonding, bondedSeq.Status) - - suite.App.SequencerKeeper.UnbondAllMatureSequencers(suite.Ctx, bondedSeq.UnbondTime.Add(10*time.Second)) - bondedSeq, found = suite.App.SequencerKeeper.GetSequencer(suite.Ctx, bondedAddr) - suite.Require().True(found) - suite.Equal(types.Unbonded, bondedSeq.Status) - - // check proposer not changed - proposer, ok = suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - suite.Equal(proposerAddr, proposer.Address) - - // try to unbond again. already unbonded, we expect error - _, err = suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().Error(err) -} - -func (suite *SequencerTestSuite) TestUnbondingProposer() { - suite.Ctx = suite.Ctx.WithBlockHeight(10) - - rollappId, proposerAddr := suite.CreateDefaultRollappAndProposer() - _ = suite.CreateSequencer(suite.Ctx, rollappId, ed25519.GenPrivKey().PubKey()) - - /* ----------------------------- unbond proposer ---------------------------- */ - unbondMsg := types.MsgUnbond{Creator: proposerAddr} - _, err := suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - - // check proposer still bonded and notice period started - p, ok := suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - suite.Equal(proposerAddr, p.Address) - suite.Equal(suite.Ctx.BlockHeight(), p.UnbondRequestHeight) - - // unbonding again, we expect error as sequencer is in notice period - _, err = suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().Error(err) - - // next proposer should not be set yet - _, ok = suite.App.SequencerKeeper.GetNextProposer(suite.Ctx, rollappId) - suite.Require().False(ok) - - // check notice period queue - m := suite.App.SequencerKeeper.GetMatureNoticePeriodSequencers(suite.Ctx, p.NoticePeriodTime.Add(-1*time.Second)) - suite.Require().Len(m, 0) - m = suite.App.SequencerKeeper.GetMatureNoticePeriodSequencers(suite.Ctx, p.NoticePeriodTime.Add(1*time.Second)) - suite.Require().Len(m, 1) -} diff --git a/x/sequencer/keeper/msg_server_update.go b/x/sequencer/keeper/msg_server_update.go new file mode 100644 index 000000000..d01061d7a --- /dev/null +++ b/x/sequencer/keeper/msg_server_update.go @@ -0,0 +1,63 @@ +package keeper + +import ( + "context" + "fmt" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/sdk-utils/utils/uevent" + + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" +) + +func (k msgServer) UpdateSequencerInformation( + goCtx context.Context, + msg *types.MsgUpdateSequencerInformation, +) (*types.MsgUpdateSequencerInformationResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + seq, err := k.RealSequencer(ctx, msg.Creator) + if err != nil { + return nil, err + } + defer func() { + k.SetSequencer(ctx, seq) + }() + + rollapp := k.rollappKeeper.MustGetRollapp(ctx, seq.RollappId) + + if err := msg.VMSpecificValidate(rollapp.VmType); err != nil { + return nil, err + } + + seq.Metadata = msg.Metadata + + if err := uevent.EmitTypedEvent(ctx, &seq); err != nil { + return nil, fmt.Errorf("emit event: %w", err) + } + + return &types.MsgUpdateSequencerInformationResponse{}, nil +} + +// UpdateOptInStatus : if false, then the sequencer will not be chosen as proposer or successor. +// If already chosen as proposer or successor, the change has no effect. +func (k msgServer) UpdateOptInStatus(goCtx context.Context, + msg *types.MsgUpdateOptInStatus, +) (*types.MsgUpdateOptInStatus, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + seq, err := k.RealSequencer(ctx, msg.Creator) + if err != nil { + return nil, err + } + + if err := seq.SetOptedIn(ctx, msg.OptedIn); err != nil { + return nil, err + } + k.SetSequencer(ctx, seq) + + // maybe set as proposer if one is needed + if err := k.UpdateProposerIfNeeded(ctx, seq.RollappId); err != nil { + return nil, errorsmod.Wrap(err, "choose proposer") + } + return &types.MsgUpdateOptInStatus{}, nil +} diff --git a/x/sequencer/keeper/msg_server_update_reward_address.go b/x/sequencer/keeper/msg_server_update_reward_address.go index dc638ece4..c58950168 100644 --- a/x/sequencer/keeper/msg_server_update_reward_address.go +++ b/x/sequencer/keeper/msg_server_update_reward_address.go @@ -4,9 +4,7 @@ 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/dymensionxyz/dymension/v3/x/sequencer/types" @@ -15,17 +13,17 @@ import ( // UpdateRewardAddress defines a method for updating the sequencer's reward address. func (k msgServer) UpdateRewardAddress(goCtx context.Context, msg *types.MsgUpdateRewardAddress) (*types.MsgUpdateRewardAddressResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - - seq, ok := k.GetSequencer(ctx, msg.Creator) - if !ok { - return nil, errorsmod.Wrap(gerrc.ErrNotFound, "sequencer") + seq, err := k.RealSequencer(ctx, msg.Creator) + if err != nil { + return nil, err } + defer func() { + k.SetSequencer(ctx, seq) + }() seq.RewardAddr = msg.RewardAddr - k.SetSequencer(ctx, seq) - - err := uevent.EmitTypedEvent(ctx, &types.EventUpdateRewardAddress{ + err = uevent.EmitTypedEvent(ctx, &types.EventUpdateRewardAddress{ Creator: msg.Creator, RewardAddr: msg.RewardAddr, }) diff --git a/x/sequencer/keeper/msg_server_update_reward_address_test.go b/x/sequencer/keeper/msg_server_update_reward_address_test.go index 3bc2a4840..7107974c5 100644 --- a/x/sequencer/keeper/msg_server_update_reward_address_test.go +++ b/x/sequencer/keeper/msg_server_update_reward_address_test.go @@ -5,9 +5,9 @@ import ( "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) -func (suite *SequencerTestSuite) TestUpdateRewardAddress() { - rollappId, pk := suite.CreateDefaultRollapp() - defaultSequencerAddress := suite.CreateSequencer(suite.Ctx, rollappId, pk) +func (s *SequencerTestSuite) TestUpdateRewardAddress() { + ra := s.createRollapp() + seqAlice := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) rewardAddr := sample.AccAddress() testCase := []struct { @@ -18,7 +18,7 @@ func (suite *SequencerTestSuite) TestUpdateRewardAddress() { { name: "valid", msg: types.MsgUpdateRewardAddress{ - Creator: defaultSequencerAddress, + Creator: seqAlice.Address, RewardAddr: rewardAddr, }, expectedErr: nil, @@ -26,14 +26,14 @@ func (suite *SequencerTestSuite) TestUpdateRewardAddress() { } for _, tc := range testCase { - suite.Run(tc.name, func() { - _, err := suite.msgServer.UpdateRewardAddress(suite.Ctx, &tc.msg) + s.Run(tc.name, func() { + _, err := s.msgServer.UpdateRewardAddress(s.Ctx, &tc.msg) if tc.expectedErr != nil { - suite.Require().ErrorIs(err, tc.expectedErr) + s.Require().ErrorIs(err, tc.expectedErr) } else { - suite.Require().NoError(err) - seq, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, tc.msg.Creator) - suite.Require().Equal(tc.msg.RewardAddr, seq.RewardAddr) + s.Require().NoError(err) + seq, _ := s.App.SequencerKeeper.RealSequencer(s.Ctx, tc.msg.Creator) + s.Require().Equal(tc.msg.RewardAddr, seq.RewardAddr) } }) } diff --git a/x/sequencer/keeper/msg_server_update_sequencer.go b/x/sequencer/keeper/msg_server_update_sequencer.go deleted file mode 100644 index 4e5052ef3..000000000 --- a/x/sequencer/keeper/msg_server_update_sequencer.go +++ /dev/null @@ -1,40 +0,0 @@ -package keeper - -import ( - "context" - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/sdk-utils/utils/uevent" - - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -// UpdateSequencerInformation defines a method for updating a sequencer -func (k msgServer) UpdateSequencerInformation(goCtx context.Context, msg *types.MsgUpdateSequencerInformation) (*types.MsgUpdateSequencerInformationResponse, error) { - ctx := sdk.UnwrapSDKContext(goCtx) - - sequencer, found := k.GetSequencer(ctx, msg.Creator) - if !found { - return nil, types.ErrUnknownSequencer - } - - if sequencer.Jailed { - return nil, types.ErrSequencerJailed - } - - rollapp := k.rollappKeeper.MustGetRollapp(ctx, sequencer.RollappId) - if err := msg.VMSpecificValidate(rollapp.VmType); err != nil { - return nil, err - } - - sequencer.Metadata = msg.Metadata - - k.SetSequencer(ctx, sequencer) - - if err := uevent.EmitTypedEvent(ctx, &sequencer); err != nil { - return nil, fmt.Errorf("emit event: %w", err) - } - - return &types.MsgUpdateSequencerInformationResponse{}, nil -} diff --git a/x/sequencer/keeper/msg_server_update_sequencer_test.go b/x/sequencer/keeper/msg_server_update_test.go similarity index 73% rename from x/sequencer/keeper/msg_server_update_sequencer_test.go rename to x/sequencer/keeper/msg_server_update_test.go index 1aa4ae4f8..2aa52eb57 100644 --- a/x/sequencer/keeper/msg_server_update_sequencer_test.go +++ b/x/sequencer/keeper/msg_server_update_test.go @@ -1,8 +1,6 @@ package keeper_test import ( - "time" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,11 +10,11 @@ import ( "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) -func (suite *SequencerTestSuite) TestUpdateSequencer() { +func (s *SequencerTestSuite) TestUpdateSequencer() { pubkey := ed25519.GenPrivKey().PubKey() addr := sdk.AccAddress(pubkey.Address()) pkAny, err := codectypes.NewAnyWithValue(pubkey) - suite.Require().Nil(err) + s.Require().Nil(err) const rollappID = "rollapp_1234-1" @@ -85,24 +83,9 @@ func (suite *SequencerTestSuite) TestUpdateSequencer() { }, GasPrice: uptr.To(sdk.NewInt(100)), }, - Jailed: false, - Status: 0, - Tokens: nil, - UnbondTime: time.Time{}, - }, - }, { - name: "Update rollapp: fail - try to update a jailed sequencer", - update: &types.MsgUpdateSequencerInformation{ - Creator: addr.String(), - }, - malleate: func(sequencer *types.Sequencer) { - suite.App.SequencerKeeper.SetSequencer(suite.Ctx, types.Sequencer{ - Address: addr.String(), - RollappId: rollappID, - Jailed: true, - }) + Status: 0, + Tokens: nil, }, - expError: types.ErrSequencerJailed, }, { name: "Update rollapp: fail - try to update wrong VM type fields", update: &types.MsgUpdateSequencerInformation{ @@ -112,7 +95,7 @@ func (suite *SequencerTestSuite) TestUpdateSequencer() { }, }, malleate: func(*types.Sequencer) { - suite.App.RollappKeeper.SetRollapp(suite.Ctx, rollapptypes.Rollapp{ + s.raK().SetRollapp(s.Ctx, rollapptypes.Rollapp{ RollappId: rollappID, VmType: rollapptypes.Rollapp_WASM, }) @@ -122,8 +105,8 @@ func (suite *SequencerTestSuite) TestUpdateSequencer() { } for _, tc := range tests { - suite.Run(tc.name, func() { - goCtx := sdk.WrapSDKContext(suite.Ctx) + s.Run(tc.name, func() { + goCtx := sdk.WrapSDKContext(s.Ctx) rollapp := rollapptypes.Rollapp{ RollappId: rollappID, VmType: rollapptypes.Rollapp_EVM, @@ -131,35 +114,50 @@ func (suite *SequencerTestSuite) TestUpdateSequencer() { InitialSequencer: addr.String(), } - suite.App.RollappKeeper.SetRollapp(suite.Ctx, rollapp) + s.raK().SetRollapp(s.Ctx, rollapp) sequencer := types.Sequencer{ Address: addr.String(), DymintPubKey: pkAny, RollappId: rollappID, Metadata: types.SequencerMetadata{}, - Jailed: false, Status: 0, Tokens: nil, - UnbondTime: time.Time{}, } - suite.App.RollappKeeper.SetRollapp(suite.Ctx, rollapp) - suite.App.SequencerKeeper.SetSequencer(suite.Ctx, sequencer) + s.raK().SetRollapp(s.Ctx, rollapp) + s.k().SetSequencer(s.Ctx, sequencer) if tc.malleate != nil { tc.malleate(&sequencer) } - _, err = suite.msgServer.UpdateSequencerInformation(goCtx, tc.update) + _, err = s.msgServer.UpdateSequencerInformation(goCtx, tc.update) if tc.expError == nil { - suite.Require().NoError(err) - resp, err := suite.queryClient.Sequencer(goCtx, &types.QueryGetSequencerRequest{SequencerAddress: tc.update.Creator}) - suite.Require().NoError(err) - suite.equalSequencer(&tc.expSequencer, &resp.Sequencer) + s.Require().NoError(err) + resp, err := s.queryClient.Sequencer(goCtx, &types.QueryGetSequencerRequest{SequencerAddress: tc.update.Creator}) + s.Require().NoError(err) + s.equalSequencers(&tc.expSequencer, &resp.Sequencer) } else { - suite.ErrorIs(err, tc.expError) + s.ErrorIs(err, tc.expError) } }) } } + +func (s *SequencerTestSuite) TestChangeOptInStatusBasicFlow() { + ra := s.createRollapp() + seq := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) + + m := &types.MsgUpdateOptInStatus{Creator: seq.Address, OptedIn: false} + _, err := s.msgServer.UpdateOptInStatus(s.Ctx, m) + s.Require().NoError(err) + seq = s.k().GetSequencer(s.Ctx, seq.Address) + s.Require().False(seq.OptedIn) + + m = &types.MsgUpdateOptInStatus{Creator: seq.Address, OptedIn: true} + _, err = s.msgServer.UpdateOptInStatus(s.Ctx, m) + s.Require().NoError(err) + seq = s.k().GetSequencer(s.Ctx, seq.Address) + s.Require().True(seq.OptedIn) +} diff --git a/x/sequencer/keeper/msg_server_update_whitelisted_relayers.go b/x/sequencer/keeper/msg_server_update_whitelisted_relayers.go index 46febc818..5cb34c1a1 100644 --- a/x/sequencer/keeper/msg_server_update_whitelisted_relayers.go +++ b/x/sequencer/keeper/msg_server_update_whitelisted_relayers.go @@ -4,9 +4,7 @@ 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/dymensionxyz/dymension/v3/x/sequencer/types" @@ -15,17 +13,17 @@ import ( // UpdateWhitelistedRelayers defines a method for updating the sequencer's whitelisted relater list. func (k msgServer) UpdateWhitelistedRelayers(goCtx context.Context, msg *types.MsgUpdateWhitelistedRelayers) (*types.MsgUpdateWhitelistedRelayersResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - - seq, ok := k.GetSequencer(ctx, msg.Creator) - if !ok { - return nil, errorsmod.Wrap(gerrc.ErrNotFound, "sequencer") + seq, err := k.RealSequencer(ctx, msg.Creator) + if err != nil { + return nil, err } + defer func() { + k.SetSequencer(ctx, seq) + }() seq.SetWhitelistedRelayers(msg.Relayers) - k.SetSequencer(ctx, seq) - - err := uevent.EmitTypedEvent(ctx, &types.EventUpdateWhitelistedRelayers{ + err = uevent.EmitTypedEvent(ctx, &types.EventUpdateWhitelistedRelayers{ Creator: msg.Creator, Relayers: msg.Relayers, }) diff --git a/x/sequencer/keeper/msg_server_update_whitelisted_relayers_test.go b/x/sequencer/keeper/msg_server_update_whitelisted_relayers_test.go index f362bf3b9..4d9b99072 100644 --- a/x/sequencer/keeper/msg_server_update_whitelisted_relayers_test.go +++ b/x/sequencer/keeper/msg_server_update_whitelisted_relayers_test.go @@ -7,9 +7,9 @@ import ( "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) -func (suite *SequencerTestSuite) TestUpdateWhitelistedRelayers() { - rollappId, pk := suite.CreateDefaultRollapp() - defaultSequencerAddress := suite.CreateSequencer(suite.Ctx, rollappId, pk) +func (s *SequencerTestSuite) TestUpdateWhitelistedRelayers() { + ra := s.createRollapp() + seqAlice := s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) relayers := []string{sample.AccAddress(), sample.AccAddress()} testCase := []struct { @@ -20,7 +20,7 @@ func (suite *SequencerTestSuite) TestUpdateWhitelistedRelayers() { { name: "valid", msg: types.MsgUpdateWhitelistedRelayers{ - Creator: defaultSequencerAddress, + Creator: seqAlice.Address, Relayers: relayers, }, expectedErr: nil, @@ -28,15 +28,15 @@ func (suite *SequencerTestSuite) TestUpdateWhitelistedRelayers() { } for _, tc := range testCase { - suite.Run(tc.name, func() { - _, err := suite.msgServer.UpdateWhitelistedRelayers(suite.Ctx, &tc.msg) + s.Run(tc.name, func() { + _, err := s.msgServer.UpdateWhitelistedRelayers(s.Ctx, &tc.msg) if tc.expectedErr != nil { - suite.Require().ErrorIs(err, tc.expectedErr) + s.Require().ErrorIs(err, tc.expectedErr) } else { - suite.Require().NoError(err) - seq, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, tc.msg.Creator) + s.Require().NoError(err) + seq, _ := s.App.SequencerKeeper.RealSequencer(s.Ctx, tc.msg.Creator) slices.Sort(tc.msg.Relayers) - suite.Require().Equal(tc.msg.Relayers, seq.WhitelistedRelayers) + s.Require().Equal(tc.msg.Relayers, seq.WhitelistedRelayers) } }) } diff --git a/x/sequencer/keeper/params.go b/x/sequencer/keeper/params.go index 7d05c5e64..44690567f 100644 --- a/x/sequencer/keeper/params.go +++ b/x/sequencer/keeper/params.go @@ -1,8 +1,6 @@ package keeper import ( - "time" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -10,24 +8,12 @@ import ( "github.com/dymensionxyz/gerr-cosmos/gerrc" ) -const ( - HubExpectedTimePerBlock = 6 * time.Second -) - // ValidateParams is a stateful validation for params. // it validates that unbonding time is greater then x/rollapp's dispute period // and that the correct denom is set. // The unbonding time is set by governance hence it's more of a sanity/human error check which // in theory should never fail as setting such unbonding time has wide protocol security implications beyond the dispute period. func (k Keeper) ValidateParams(ctx sdk.Context, params types.Params) error { - // validate unbonding time > dispute period - rollappParams := k.rollappKeeper.GetParams(ctx) - // Get the time duration of the dispute period - disputeDuration := time.Duration(rollappParams.DisputePeriodInBlocks) * HubExpectedTimePerBlock // dispute period duration - if params.UnbondingTime < disputeDuration { - return errorsmod.Wrapf(gerrc.ErrInvalidArgument, "unbonding time must be greater than dispute period") - } - // validate min bond denom denom, err := sdk.GetBaseDenom() if err != nil { @@ -36,6 +22,9 @@ func (k Keeper) ValidateParams(ctx sdk.Context, params types.Params) error { if params.MinBond.Denom != denom { return errorsmod.Wrapf(gerrc.ErrInvalidArgument, "min bond denom must be equal to base denom") } + if params.KickThreshold.Denom != denom { + return errorsmod.Wrapf(gerrc.ErrInvalidArgument, "kick threshold denom must be equal to base denom") + } return nil } @@ -56,19 +45,3 @@ func (k Keeper) GetParams(ctx sdk.Context) (params types.Params) { k.cdc.MustUnmarshal(bz, ¶ms) return params } - -func (k Keeper) MinBond(ctx sdk.Context) (res sdk.Coin) { - return k.GetParams(ctx).MinBond -} - -func (k Keeper) UnbondingTime(ctx sdk.Context) (res time.Duration) { - return k.GetParams(ctx).UnbondingTime -} - -func (k Keeper) NoticePeriod(ctx sdk.Context) (res time.Duration) { - return k.GetParams(ctx).NoticePeriod -} - -func (k Keeper) LivenessSlashMultiplier(ctx sdk.Context) (res sdk.Dec) { - return k.GetParams(ctx).LivenessSlashMultiplier -} diff --git a/x/sequencer/keeper/params_test.go b/x/sequencer/keeper/params_test.go index fb74ec702..89e126e5b 100644 --- a/x/sequencer/keeper/params_test.go +++ b/x/sequencer/keeper/params_test.go @@ -2,7 +2,6 @@ package keeper_test import ( "testing" - "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -23,10 +22,7 @@ func TestGetParams(t *testing.T) { // test ValidateParams func (s *SequencerTestSuite) TestValidateParams() { - s.SetupTest() k := s.App.SequencerKeeper - disputeInBlocks := s.App.RollappKeeper.GetParams(s.Ctx).DisputePeriodInBlocks - defaultDisputeDuration := time.Duration(disputeInBlocks*6) * time.Second tests := []struct { name string @@ -40,15 +36,6 @@ func (s *SequencerTestSuite) TestValidateParams() { }, false, }, - { - "stateful validation: unbonding time less than dispute period", - func() types.Params { - params := types.DefaultParams() - params.UnbondingTime = defaultDisputeDuration - time.Second - return params - }, - true, - }, { "stateful validation: min bond denom not equal to base denom", func() types.Params { diff --git a/x/sequencer/keeper/proposer.go b/x/sequencer/keeper/proposer.go new file mode 100644 index 000000000..a15e7d0f7 --- /dev/null +++ b/x/sequencer/keeper/proposer.go @@ -0,0 +1,130 @@ +package keeper + +import ( + "slices" + + 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/uevent" +) + +// OptOutAllSequencers : change every sequencer of the rollapp to be opted out. +// Can optionally pass a list of exclusions: those sequencers won't be modified. +func (k Keeper) optOutAllSequencers(ctx sdk.Context, rollapp string, excl ...string) error { + seqs := k.RollappSequencers(ctx, rollapp) + exclMap := make(map[string]struct{}, len(excl)) + for _, addr := range excl { + exclMap[addr] = struct{}{} + } + for _, seq := range seqs { + if _, ok := exclMap[seq.Address]; !ok { + if err := seq.SetOptedIn(ctx, false); err != nil { + return errorsmod.Wrap(err, "set opted in") + } + k.SetSequencer(ctx, seq) + } + } + return nil +} + +func (k Keeper) RollappPotentialProposers(ctx sdk.Context, rollappId string) []types.Sequencer { + seqs := k.RollappBondedSequencers(ctx, rollappId) + seqs = slices.DeleteFunc(seqs, func(seq types.Sequencer) bool { + return !seq.IsPotentialProposer() + }) + // FIXME: sentinel should be added only if no sequencers are bonded + return append(seqs, k.SentinelSequencer(ctx)) +} + +// UpdateProposerIfNeeded 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) UpdateProposerIfNeeded(ctx sdk.Context, rollapp string) error { + proposer := k.GetProposer(ctx, rollapp) + before := proposer + + // a valid proposer is already set so there's no need to do anything + if !proposer.Sentinel() { + 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 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) + 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 +} + +func (k Keeper) IsProposer(ctx sdk.Context, seq types.Sequencer) bool { + return seq.Address == k.GetProposer(ctx, seq.RollappId).Address +} + +func (k Keeper) IsSuccessor(ctx sdk.Context, seq types.Sequencer) bool { + return seq.Address == k.GetSuccessor(ctx, seq.RollappId).Address +} diff --git a/x/sequencer/keeper/proposer_test.go b/x/sequencer/keeper/proposer_test.go new file mode 100644 index 000000000..aba66a991 --- /dev/null +++ b/x/sequencer/keeper/proposer_test.go @@ -0,0 +1,83 @@ +package keeper_test + +import ( + "reflect" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + "github.com/dymensionxyz/sdk-utils/utils/ucoin" +) + +func Test_proposerChoiceAlgo(t *testing.T) { + type args struct { + seqs []types.Sequencer + } + tests := []struct { + name string + args args + want int + }{ + { + name: "only one", + args: args{ + seqs: []types.Sequencer{ + { + Address: "0", + Tokens: sdk.NewCoins(bond), + }, + }, + }, + want: 0, + }, + { + name: "two", + args: args{ + seqs: []types.Sequencer{ + { + Address: "0", + Tokens: sdk.NewCoins(ucoin.SimpleMul(bond, 1)), + }, + { + Address: "1", + Tokens: sdk.NewCoins(ucoin.SimpleMul(bond, 2)), + }, + }, + }, + want: 1, + }, + { + name: "stable", + args: args{ + seqs: []types.Sequencer{ + { + Address: "0", + Tokens: sdk.NewCoins(ucoin.SimpleMul(bond, 1)), + }, + { + Address: "1", + Tokens: sdk.NewCoins(ucoin.SimpleMul(bond, 3)), + }, + { + Address: "2", + Tokens: sdk.NewCoins(ucoin.SimpleMul(bond, 3)), + }, + { + Address: "3", + Tokens: sdk.NewCoins(ucoin.SimpleMul(bond, 2)), + }, + }, + }, + want: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + want := tt.args.seqs[tt.want] + if got, _ := keeper.ProposerChoiceAlgo(tt.args.seqs); !reflect.DeepEqual(got, want) { + t.Errorf("proposerChoiceAlgo() = %v, want %v", got, want) + } + }) + } +} diff --git a/x/sequencer/keeper/rotation.go b/x/sequencer/keeper/rotation.go index cc77045d4..a748e0052 100644 --- a/x/sequencer/keeper/rotation.go +++ b/x/sequencer/keeper/rotation.go @@ -1,7 +1,6 @@ package keeper import ( - "sort" "strings" "time" @@ -12,135 +11,87 @@ import ( "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) -func (k Keeper) startNoticePeriodForSequencer(ctx sdk.Context, seq *types.Sequencer) time.Time { - completionTime := ctx.BlockTime().Add(k.NoticePeriod(ctx)) - seq.NoticePeriodTime = completionTime +// StartNoticePeriod defines a period of time for the proposer where +// they cannot yet unbond, nor submit their last block. Adds to a queue for later +// processing. +func (k Keeper) StartNoticePeriod(ctx sdk.Context, prop *types.Sequencer) { + prop.NoticePeriodTime = ctx.BlockTime().Add(k.GetParams(ctx).NoticePeriod) - k.UpdateSequencer(ctx, seq) - k.AddSequencerToNoticePeriodQueue(ctx, seq) + k.AddToNoticeQueue(ctx, *prop) ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeNoticePeriodStarted, - sdk.NewAttribute(types.AttributeKeyRollappId, seq.RollappId), - sdk.NewAttribute(types.AttributeKeySequencer, seq.Address), - sdk.NewAttribute(types.AttributeKeyCompletionTime, completionTime.String()), + sdk.NewAttribute(types.AttributeKeyRollappId, prop.RollappId), + sdk.NewAttribute(types.AttributeKeySequencer, prop.Address), + sdk.NewAttribute(types.AttributeKeyCompletionTime, prop.NoticePeriodTime.String()), ), ) - - return completionTime -} - -// MatureSequencersWithNoticePeriod start rotation flow for all sequencers that have finished their notice period -// The next proposer is set to the next bonded sequencer -// The hub will expect a "last state update" from the sequencer to start unbonding -// In the middle of rotation, the next proposer required a notice period as well. -func (k Keeper) MatureSequencersWithNoticePeriod(ctx sdk.Context, currTime time.Time) { - seqs := k.GetMatureNoticePeriodSequencers(ctx, currTime) - for _, seq := range seqs { - if k.isProposer(ctx, seq.RollappId, seq.Address) { - k.startRotation(ctx, seq.RollappId) - k.removeNoticePeriodSequencer(ctx, seq) - } - // next proposer cannot mature it's notice period until the current proposer has finished rotation - // minor effect as notice_period >>> rotation time - } } -// IsRotating returns true if the rollapp is currently in the process of rotation. -// A process of rotation is defined by the existence of a next proposer. The next proposer can also be a "dummy" sequencer (i.e empty) in case no sequencer came. This is still considered rotation -// as the sequencer is rotating to an empty one (i.e gracefully leaving the rollapp). -// The next proposer can only be set after the notice period is over. The rotation period is over after the proposer sends his last batch. -func (k Keeper) IsRotating(ctx sdk.Context, rollappId string) bool { - return k.isNextProposerSet(ctx, rollappId) +// NoticeElapsedProposers gets all sequencers across all rollapps whose notice period +// has passed/elapsed. +func (k Keeper) NoticeElapsedProposers(ctx sdk.Context, endTime time.Time) ([]types.Sequencer, error) { + return k.NoticeQueue(ctx, &endTime) } -// isNoticePeriodRequired returns true if the sequencer requires a notice period before unbonding -// Both the proposer and the next proposer require a notice period -func (k Keeper) isNoticePeriodRequired(ctx sdk.Context, seq types.Sequencer) bool { - return k.isProposer(ctx, seq.RollappId, seq.Address) || k.isNextProposer(ctx, seq.RollappId, seq.Address) -} - -// ExpectedNextProposer returns the next proposer for a rollapp -// it selects the next proposer from the bonded sequencers by bond amount -// if there are no bonded sequencers, it returns an empty sequencer -func (k Keeper) ExpectedNextProposer(ctx sdk.Context, rollappId string) types.Sequencer { - // if nextProposer is set, were in the middle of rotation. The expected next proposer cannot change - seq, ok := k.GetNextProposer(ctx, rollappId) - if ok { - return seq +// ChooseSuccessorForFinishedNotices goes through all sequencers whose notice periods have elapsed. +// For each proposer, it chooses a successor proposer for their rollapp. +// Contract: must be called before OnProposerLastBlock for a given block time +func (k Keeper) ChooseSuccessorForFinishedNotices(ctx sdk.Context, now time.Time) error { + seqs, err := k.NoticeElapsedProposers(ctx, now) + if err != nil { + return errorsmod.Wrap(err, "get notice elapsed sequencers") } - - // take the next bonded sequencer to be the proposer. sorted by bond - seqs := k.GetSequencersByRollappByStatus(ctx, rollappId, types.Bonded) - sort.SliceStable(seqs, func(i, j int) bool { - return seqs[i].Tokens.IsAllGT(seqs[j].Tokens) - }) - - // return the first sequencer that is not the proposer - proposer, _ := k.GetProposer(ctx, rollappId) - for _, s := range seqs { - if s.Address != proposer.Address { - return s + for _, seq := range seqs { + k.removeFromNoticeQueue(ctx, seq) + if err := k.chooseSuccessor(ctx, seq.RollappId); err != nil { + return errorsmod.Wrap(err, "choose successor") } + successor := k.GetSuccessor(ctx, seq.RollappId) + ctx.EventManager().EmitEvent( + sdk.NewEvent( + types.EventTypeRotationStarted, + sdk.NewAttribute(types.AttributeKeyRollappId, seq.RollappId), + sdk.NewAttribute(types.AttributeKeyNextProposer, successor.Address), + sdk.NewAttribute(types.AttributeKeyRewardAddr, successor.RewardAddr), + sdk.NewAttribute(types.AttributeKeyWhitelistedRelayers, strings.Join(successor.WhitelistedRelayers, ",")), + ), + ) } - - return types.Sequencer{} + return nil } -// startRotation sets the nextSequencer for the rollapp. -// This function will not clear the current proposer -// This function called when the sequencer has finished its notice period -func (k Keeper) startRotation(ctx sdk.Context, rollappId string) { - // next proposer can be empty if there are no bonded sequencers available - nextProposer := k.ExpectedNextProposer(ctx, rollappId) - k.setNextProposer(ctx, rollappId, nextProposer.Address) - - k.Logger(ctx).Info("rotation started", "rollappId", rollappId, "nextProposer", nextProposer.Address) +func (k Keeper) RotationInProgress(ctx sdk.Context, rollapp string) bool { + prop := k.GetProposer(ctx, rollapp) + return prop.NoticeInProgress(ctx.BlockTime()) || k.AwaitingLastProposerBlock(ctx, rollapp) +} - // TODO: use corresponding typed event - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeRotationStarted, - sdk.NewAttribute(types.AttributeKeyRollappId, rollappId), - sdk.NewAttribute(types.AttributeKeyNextProposer, nextProposer.Address), - sdk.NewAttribute(types.AttributeKeyRewardAddr, nextProposer.RewardAddr), - sdk.NewAttribute(types.AttributeKeyWhitelistedRelayers, strings.Join(nextProposer.WhitelistedRelayers, ",")), - ), - ) +func (k Keeper) AwaitingLastProposerBlock(ctx sdk.Context, rollapp string) bool { + proposer := k.GetProposer(ctx, rollapp) + return proposer.NoticeElapsed(ctx.BlockTime()) } -// CompleteRotation completes the sequencer rotation flow. -// It's called when a last state update is received from the active, rotating sequencer. -// it will start unbonding the current proposer, and sets the nextProposer as the proposer. -func (k Keeper) CompleteRotation(ctx sdk.Context, rollappId string) error { - proposer, ok := k.GetProposer(ctx, rollappId) - if !ok { - return errorsmod.Wrapf(gerrc.ErrInternal, "proposer not set for rollapp %s", rollappId) - } - nextProposer, ok := k.GetNextProposer(ctx, rollappId) - if !ok { - return errorsmod.Wrapf(gerrc.ErrInternal, "next proposer not set for rollapp %s", rollappId) +// OnProposerLastBlock : it will assign the successor to be the proposer. +// Contract: must be called after ChooseSuccessorForFinishedNotices for a given block time +func (k Keeper) OnProposerLastBlock(ctx sdk.Context, proposer types.Sequencer) error { + allowLastBlock := proposer.NoticeElapsed(ctx.BlockTime()) + if !allowLastBlock { + return errorsmod.Wrap(gerrc.ErrFault, "sequencer has submitted last block without finishing notice period") } - // start unbonding the current proposer - k.startUnbondingPeriodForSequencer(ctx, &proposer) - - // change the proposer - k.removeNextProposer(ctx, rollappId) - k.SetProposer(ctx, rollappId, nextProposer.Address) - - if nextProposer.Address == NO_SEQUENCER_AVAILABLE { - k.Logger(ctx).Info("Rollapp left with no proposer.", "RollappID", rollappId) + k.SetProposer(ctx, proposer.RollappId, types.SentinelSeqAddr) + // FIXME: shouldn't go through sentinel, as it considered hard fork + if err := k.UpdateProposerIfNeeded(ctx, proposer.RollappId); err != nil { + return errorsmod.Wrap(err, "choose proposer") } - + after := k.GetProposer(ctx, proposer.RollappId) ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeProposerRotated, - sdk.NewAttribute(types.AttributeKeyRollappId, rollappId), - sdk.NewAttribute(types.AttributeKeySequencer, nextProposer.Address), + sdk.NewAttribute(types.AttributeKeyRollappId, proposer.RollappId), + sdk.NewAttribute(types.AttributeKeySequencer, after.Address), ), ) - return nil } diff --git a/x/sequencer/keeper/rotation_test.go b/x/sequencer/keeper/rotation_test.go index eafbec0a3..0468e864b 100644 --- a/x/sequencer/keeper/rotation_test.go +++ b/x/sequencer/keeper/rotation_test.go @@ -1,193 +1,120 @@ package keeper_test import ( - "time" - - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - 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" + "github.com/dymensionxyz/sdk-utils/utils/utest" ) -func (suite *SequencerTestSuite) TestExpectedNextProposer() { - type testCase struct { - name string - numSeqAddrs int - expectEmptyNextProposer bool - } - - testCases := []testCase{ - {"No additional sequencers", 0, true}, - {"few", 4, false}, - } - - for _, tc := range testCases { - suite.Run(tc.name, func() { - suite.SetupTest() - - rollappId, pk := suite.CreateDefaultRollapp() - _ = suite.CreateSequencerWithBond(suite.Ctx, rollappId, bond, pk) // proposer, with highest bond - - seqAddrs := make([]string, tc.numSeqAddrs) - currBond := sdk.NewCoin(bond.Denom, bond.Amount.Quo(sdk.NewInt(10))) - for i := 0; i < len(seqAddrs); i++ { - currBond = currBond.AddAmount(bond.Amount) - pubkey := ed25519.GenPrivKey().PubKey() - seqAddrs[i] = suite.CreateSequencerWithBond(suite.Ctx, rollappId, currBond, pubkey) - } - next := suite.App.SequencerKeeper.ExpectedNextProposer(suite.Ctx, rollappId) - if tc.expectEmptyNextProposer { - suite.Require().Empty(next.Address) - return - } - - expectedNextProposer := seqAddrs[len(seqAddrs)-1] - suite.Equal(expectedNextProposer, next.Address) - }) - } -} - -// TestStartRotation tests the StartRotation function which is called when a sequencer has finished its notice period -func (suite *SequencerTestSuite) TestStartRotation() { - rollappId, pk := suite.CreateDefaultRollapp() - addr1 := suite.CreateSequencer(suite.Ctx, rollappId, pk) - - _ = suite.CreateDefaultSequencer(suite.Ctx, rollappId) - _ = suite.CreateDefaultSequencer(suite.Ctx, rollappId) - - /* ----------------------------- unbond proposer ---------------------------- */ - unbondMsg := types.MsgUnbond{Creator: addr1} - _, err := suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - - // check proposer still bonded and notice period started - p, ok := suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - suite.Equal(addr1, p.Address) - suite.Equal(suite.Ctx.BlockHeight(), p.UnbondRequestHeight) - - m := suite.App.SequencerKeeper.GetMatureNoticePeriodSequencers(suite.Ctx, p.NoticePeriodTime.Add(-10*time.Second)) - suite.Require().Len(m, 0) - m = suite.App.SequencerKeeper.GetMatureNoticePeriodSequencers(suite.Ctx, p.NoticePeriodTime.Add(10*time.Second)) - suite.Require().Len(m, 1) - suite.App.SequencerKeeper.MatureSequencersWithNoticePeriod(suite.Ctx, p.NoticePeriodTime.Add(10*time.Second)) - - // validate nextProposer is set - n, ok := suite.App.SequencerKeeper.GetNextProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - suite.Require().NotEmpty(n.Address) - - // validate proposer not changed - p, _ = suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Equal(addr1, p.Address) -} - -func (suite *SequencerTestSuite) TestRotateProposer() { - rollappId, pk := suite.CreateDefaultRollapp() - addr1 := suite.CreateSequencer(suite.Ctx, rollappId, pk) - addr2 := suite.CreateSequencer(suite.Ctx, rollappId, ed25519.GenPrivKey().PubKey()) - - /* ----------------------------- unbond proposer ---------------------------- */ - unbondMsg := types.MsgUnbond{Creator: addr1} - res, err := suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - - // mature notice period - suite.App.SequencerKeeper.MatureSequencersWithNoticePeriod(suite.Ctx, res.GetNoticePeriodCompletionTime().Add(10*time.Second)) - _, ok := suite.App.SequencerKeeper.GetNextProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - - // simulate lastBlock received - err = suite.App.SequencerKeeper.CompleteRotation(suite.Ctx, rollappId) - suite.Require().NoError(err) - - // assert addr2 is now proposer - p, ok := suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - suite.Equal(addr2, p.Address) - // assert addr1 is unbonding - u, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr1) - suite.Equal(types.Unbonding, u.Status) - // assert nextProposer is nil - _, ok = suite.App.SequencerKeeper.GetNextProposer(suite.Ctx, rollappId) - suite.Require().False(ok) +// Normal flow where there are two sequencers A, B and everything is graceful +func (s *SequencerTestSuite) TestRotationHappyFlow() { + // init + ra := s.createRollapp() + s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, bond) + s.createSequencerWithBond(s.Ctx, ra.RollappId, bob, bond) + s.Require().True(s.k().IsProposer(s.Ctx, s.seq(alice))) + s.Require().False(s.k().IsSuccessor(s.Ctx, s.seq(bob))) + + // proposer tries to unbond + mUnbond := &types.MsgUnbond{Creator: pkAddr(alice)} + res, err := s.msgServer.Unbond(s.Ctx, mUnbond) + s.Require().NoError(err) + + // notice period has not yet elapsed + err = s.k().ChooseSuccessorForFinishedNotices(s.Ctx, s.Ctx.BlockTime()) + s.Require().NoError(err) + s.Require().False(s.k().IsSuccessor(s.Ctx, s.seq(bob))) + + // proposer cannot yet submit last + err = s.k().OnProposerLastBlock(s.Ctx, s.seq(alice)) + utest.IsErr(s.Require(), err, gerrc.ErrFault) + + // advance clock past notice + s.Require().True(res.GetNoticePeriodCompletionTime().After(s.Ctx.BlockTime())) + s.Ctx = s.Ctx.WithBlockTime(*res.GetNoticePeriodCompletionTime()) + + // notice period has now elapsed + err = s.k().ChooseSuccessorForFinishedNotices(s.Ctx, s.Ctx.BlockTime()) + s.Require().NoError(err) + s.Require().True(s.k().IsSuccessor(s.Ctx, s.seq(bob))) + + // proposer can submit last + err = s.k().OnProposerLastBlock(s.Ctx, s.seq(alice)) + s.Require().NoError(err) + s.Require().False(s.k().IsProposer(s.Ctx, s.seq(alice))) + s.Require().True(s.k().IsProposer(s.Ctx, s.seq(bob))) + s.Require().False(s.k().IsSuccessor(s.Ctx, s.seq(bob))) } -func (suite *SequencerTestSuite) TestRotateProposerNoNextProposer() { - rollappId, pk := suite.CreateDefaultRollapp() - addr1 := suite.CreateSequencer(suite.Ctx, rollappId, pk) - - /* ----------------------------- unbond proposer ---------------------------- */ - unbondMsg := types.MsgUnbond{Creator: addr1} - res, err := suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - - // mature notice period - suite.App.SequencerKeeper.MatureSequencersWithNoticePeriod(suite.Ctx, res.GetNoticePeriodCompletionTime().Add(10*time.Second)) - // simulate lastBlock received - err = suite.App.SequencerKeeper.CompleteRotation(suite.Ctx, rollappId) - suite.Require().NoError(err) - - _, ok := suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().False(ok) - - _, ok = suite.App.SequencerKeeper.GetNextProposer(suite.Ctx, rollappId) - suite.Require().False(ok) +// A wants to rotate but there is no B to take over. Proposer should be sentinel afterwards. +func (s *SequencerTestSuite) TestRotationNoSuccessor() { + // 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))) + + // proposer tries to unbond + mUnbond := &types.MsgUnbond{Creator: pkAddr(alice)} + res, err := s.msgServer.Unbond(s.Ctx, mUnbond) + s.Require().NoError(err) + + // advance clock past notice + s.Require().True(res.GetNoticePeriodCompletionTime().After(s.Ctx.BlockTime())) + s.Ctx = s.Ctx.WithBlockTime(*res.GetNoticePeriodCompletionTime()) + + // notice period has now elapsed + err = s.k().ChooseSuccessorForFinishedNotices(s.Ctx, s.Ctx.BlockTime()) + s.Require().NoError(err) + s.Require().True(s.k().IsSuccessor(s.Ctx, s.k().SentinelSequencer(s.Ctx))) + + // proposer can submit last + err = s.k().OnProposerLastBlock(s.Ctx, s.seq(alice)) + s.Require().NoError(err) + s.Require().False(s.k().IsProposer(s.Ctx, s.seq(alice))) + s.Require().True(s.k().IsProposer(s.Ctx, s.k().SentinelSequencer(s.Ctx))) + s.Require().True(s.k().IsSuccessor(s.Ctx, s.k().SentinelSequencer(s.Ctx))) } -// Both the proposer and nextProposer tries to unbond -func (suite *SequencerTestSuite) TestStartRotationTwice() { - suite.Ctx = suite.Ctx.WithBlockHeight(10) - - rollappId, pk := suite.CreateDefaultRollapp() - addr1 := suite.CreateSequencer(suite.Ctx, rollappId, pk) - addr2 := suite.CreateSequencer(suite.Ctx, rollappId, ed25519.GenPrivKey().PubKey()) - - // unbond proposer - unbondMsg := types.MsgUnbond{Creator: addr1} - _, err := suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - - p, ok := suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - suite.Equal(addr1, p.Address) - suite.Equal(suite.Ctx.BlockHeight(), p.UnbondRequestHeight) - - suite.App.SequencerKeeper.MatureSequencersWithNoticePeriod(suite.Ctx, p.NoticePeriodTime.Add(10*time.Second)) - suite.Require().True(suite.App.SequencerKeeper.IsRotating(suite.Ctx, rollappId)) - - n, ok := suite.App.SequencerKeeper.GetNextProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - suite.Equal(addr2, n.Address) - - // unbond nextProposer before rotation completes - suite.Ctx = suite.Ctx.WithBlockHeight(20) - unbondMsg = types.MsgUnbond{Creator: addr2} - _, err = suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - - // check nextProposer is still the nextProposer and notice period started - n, ok = suite.App.SequencerKeeper.GetNextProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - suite.Equal(addr2, n.Address) - suite.Require().True(n.IsNoticePeriodInProgress()) - - // rotation completes before notice period ends for addr2 (the nextProposer) - err = suite.App.SequencerKeeper.CompleteRotation(suite.Ctx, rollappId) // simulate lastBlock received - suite.Require().NoError(err) - - // validate addr2 is now proposer and still with notice period - p, _ = suite.App.SequencerKeeper.GetProposer(suite.Ctx, rollappId) - suite.Equal(addr2, p.Address) - suite.Require().True(p.IsNoticePeriodInProgress()) - - // validate nextProposer is unset after rotation completes - n, ok = suite.App.SequencerKeeper.GetNextProposer(suite.Ctx, rollappId) - suite.Require().False(ok) - - // mature notice period for addr2 - suite.App.SequencerKeeper.MatureSequencersWithNoticePeriod(suite.Ctx, p.NoticePeriodTime.Add(10*time.Second)) - // validate nextProposer is set - n, ok = suite.App.SequencerKeeper.GetNextProposer(suite.Ctx, rollappId) - suite.Require().True(ok) - suite.Require().Empty(n.Address) +// A wants to rotate. After B is marked successor he also wants to rotate, before A has finished. +func (s *SequencerTestSuite) TestRotationProposerAndSuccessorBothUnbond() { + // init + ra := s.createRollapp() + s.createSequencerWithBond(s.Ctx, ra.RollappId, alice, ucoin.SimpleMul(bond, 3)) + s.createSequencerWithBond(s.Ctx, ra.RollappId, bob, ucoin.SimpleMul(bond, 2)) // bob has prio over charlie + s.createSequencerWithBond(s.Ctx, ra.RollappId, charlie, ucoin.SimpleMul(bond, 1)) + s.Require().True(s.k().IsProposer(s.Ctx, s.seq(alice))) + s.Require().False(s.k().IsSuccessor(s.Ctx, s.seq(bob))) + + // proposer tries to unbond + mUnbond := &types.MsgUnbond{Creator: pkAddr(alice)} + res, err := s.msgServer.Unbond(s.Ctx, mUnbond) + s.Require().NoError(err) + + // advance clock past proposer notice + s.Require().True(res.GetNoticePeriodCompletionTime().After(s.Ctx.BlockTime())) + s.Ctx = s.Ctx.WithBlockTime(*res.GetNoticePeriodCompletionTime()) + + // notice period has now elapsed + err = s.k().ChooseSuccessorForFinishedNotices(s.Ctx, s.Ctx.BlockTime()) + s.Require().NoError(err) + s.Require().True(s.k().IsSuccessor(s.Ctx, s.seq(bob)), "successor", s.k().GetSuccessor(s.Ctx, ra.RollappId).Address) + + // successor tries to unbond, but it fails + mUnbond = &types.MsgUnbond{Creator: pkAddr(bob)} + _, err = s.msgServer.Unbond(s.Ctx, mUnbond) + utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) + + // proposer can submit last + err = s.k().OnProposerLastBlock(s.Ctx, s.seq(alice)) + s.Require().NoError(err) + s.Require().False(s.k().IsProposer(s.Ctx, s.seq(alice))) + s.Require().True(s.k().IsProposer(s.Ctx, s.seq(bob))) + s.Require().False(s.k().IsSuccessor(s.Ctx, s.seq(bob))) + + // successor tries to unbond this time it works + mUnbond = &types.MsgUnbond{Creator: pkAddr(bob)} + _, err = s.msgServer.Unbond(s.Ctx, mUnbond) + s.Require().NoError(err) } diff --git a/x/sequencer/keeper/sequencer.go b/x/sequencer/keeper/sequencer.go index e38f8465a..17e5096bd 100644 --- a/x/sequencer/keeper/sequencer.go +++ b/x/sequencer/keeper/sequencer.go @@ -1,272 +1,24 @@ package keeper import ( - "time" - - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) -// used to indicate that no sequencer is available for a proposer / next proposer role -const NO_SEQUENCER_AVAILABLE = "" - -// SetSequencer set a specific sequencer in the store from its index -func (k Keeper) SetSequencer(ctx sdk.Context, sequencer types.Sequencer) { - store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshal(&sequencer) - store.Set(types.SequencerKey( - sequencer.Address, - ), b) - - seqByRollappKey := types.SequencerByRollappByStatusKey(sequencer.RollappId, sequencer.Address, sequencer.Status) - store.Set(seqByRollappKey, b) -} - -// UpdateSequencer updates the state of a sequencer in the keeper. -// Parameters: -// - sequencer: The sequencer object to be updated. -// - oldStatus: An optional parameter representing the old status of the sequencer. -// Needs to be provided if the status of the sequencer has changed (e.g from Bonded to Unbonding). -func (k Keeper) UpdateSequencer(ctx sdk.Context, sequencer *types.Sequencer, oldStatus ...types.OperatingStatus) { - k.SetSequencer(ctx, *sequencer) - - // status changed, need to remove old status key - if len(oldStatus) > 0 && sequencer.Status != oldStatus[0] { - oldKey := types.SequencerByRollappByStatusKey(sequencer.RollappId, sequencer.Address, oldStatus[0]) - ctx.KVStore(k.storeKey).Delete(oldKey) - } -} - -// GetSequencer returns a sequencer from its index -func (k Keeper) GetSequencer(ctx sdk.Context, sequencerAddress string) (val types.Sequencer, found bool) { - store := ctx.KVStore(k.storeKey) - b := store.Get(types.SequencerKey( - sequencerAddress, - )) - if b == nil { - return val, false - } - - k.cdc.MustUnmarshal(b, &val) - return val, true -} - -// MustGetSequencer returns a sequencer from its index -// It will panic if the sequencer is not found -func (k Keeper) MustGetSequencer(ctx sdk.Context, sequencerAddress string) types.Sequencer { - seq, found := k.GetSequencer(ctx, sequencerAddress) - if !found { - panic("sequencer not found") - } - return seq -} - -// GetAllSequencers returns all sequencer -func (k Keeper) GetAllSequencers(ctx sdk.Context) (list []types.Sequencer) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.SequencersKeyPrefix) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() // nolint: errcheck - - for ; iterator.Valid(); iterator.Next() { - var val types.Sequencer - k.cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - - return -} - -// GetSequencersByRollapp returns a sequencersByRollapp from its index -func (k Keeper) GetSequencersByRollapp(ctx sdk.Context, rollappId string) (list []types.Sequencer) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.SequencersByRollappKey(rollappId)) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() // nolint: errcheck - - for ; iterator.Valid(); iterator.Next() { - var val types.Sequencer - k.cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - - return -} - -// GetSequencersByRollappByStatus returns a sequencersByRollapp from its index -func (k Keeper) GetSequencersByRollappByStatus(ctx sdk.Context, rollappId string, status types.OperatingStatus) (list []types.Sequencer) { - prefixKey := types.SequencersByRollappByStatusKey(rollappId, status) - store := prefix.NewStore(ctx.KVStore(k.storeKey), prefixKey) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - - defer iterator.Close() // nolint: errcheck - - for ; iterator.Valid(); iterator.Next() { - var val types.Sequencer - k.cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - - return -} - -/* -------------------------------------------------------------------------- */ -/* Unbonding queue */ -/* -------------------------------------------------------------------------- */ - -// GetMatureUnbondingSequencers returns all unbonding sequencers -func (k Keeper) GetMatureUnbondingSequencers(ctx sdk.Context, endTime time.Time) (list []types.Sequencer) { - store := ctx.KVStore(k.storeKey) - iterator := store.Iterator(types.UnbondingQueueKey, sdk.PrefixEndBytes(types.UnbondingQueueByTimeKey(endTime))) - - defer iterator.Close() // nolint: errcheck - - for ; iterator.Valid(); iterator.Next() { - var val types.Sequencer - k.cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - - return -} - -func (k Keeper) AddSequencerToUnbondingQueue(ctx sdk.Context, sequencer *types.Sequencer) { - store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshal(sequencer) - - unbondingQueueKey := types.UnbondingSequencerKey(sequencer.Address, sequencer.UnbondTime) - store.Set(unbondingQueueKey, b) -} - -// remove unbonding sequencer from the queue -func (k Keeper) removeUnbondingSequencer(ctx sdk.Context, sequencer types.Sequencer) { - store := ctx.KVStore(k.storeKey) - unbondingQueueKey := types.UnbondingSequencerKey(sequencer.Address, sequencer.UnbondTime) - store.Delete(unbondingQueueKey) -} - -/* -------------------------------------------------------------------------- */ -/* notice period */ -/* -------------------------------------------------------------------------- */ - -// GetMatureNoticePeriodSequencers returns all sequencers that have finished their notice period -func (k Keeper) GetMatureNoticePeriodSequencers(ctx sdk.Context, endTime time.Time) (list []types.Sequencer) { - store := ctx.KVStore(k.storeKey) - iterator := store.Iterator(types.NoticePeriodQueueKey, sdk.PrefixEndBytes(types.NoticePeriodQueueByTimeKey(endTime))) - - defer iterator.Close() // nolint: errcheck - - for ; iterator.Valid(); iterator.Next() { - var val types.Sequencer - k.cdc.MustUnmarshal(iterator.Value(), &val) - list = append(list, val) - } - - return -} - -// AddSequencerToNoticePeriodQueue set sequencer in notice period queue -func (k Keeper) AddSequencerToNoticePeriodQueue(ctx sdk.Context, sequencer *types.Sequencer) { - store := ctx.KVStore(k.storeKey) - b := k.cdc.MustMarshal(sequencer) - - noticePeriodKey := types.NoticePeriodSequencerKey(sequencer.Address, sequencer.NoticePeriodTime) - store.Set(noticePeriodKey, b) -} - -// remove sequencer from notice period queue -func (k Keeper) removeNoticePeriodSequencer(ctx sdk.Context, sequencer types.Sequencer) { - store := ctx.KVStore(k.storeKey) - noticePeriodKey := types.NoticePeriodSequencerKey(sequencer.Address, sequencer.NoticePeriodTime) - store.Delete(noticePeriodKey) -} - -/* ------------------------- proposer/next proposer ------------------------- */ - -// GetAllProposers returns all proposers for all rollapps -func (k Keeper) GetAllProposers(ctx sdk.Context) (list []types.Sequencer) { - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.ProposerByRollappKey("")) - iterator := sdk.KVStorePrefixIterator(store, []byte{}) - defer iterator.Close() // nolint: errcheck - - for ; iterator.Valid(); iterator.Next() { - address := string(iterator.Value()) - seq := k.MustGetSequencer(ctx, address) - list = append(list, seq) - } - - return +// SentinelSequencer is a convenient placeholder for the empty-sequencer case +// Note: does not populate rollappID by default +func (k Keeper) SentinelSequencer(ctx sdk.Context) types.Sequencer { + s := k.NewSequencer(ctx, "") + s.Status = types.Bonded + s.Address = types.SentinelSeqAddr + s.OptedIn = true + return *s } -func (k Keeper) SetProposer(ctx sdk.Context, rollappId, sequencerAddr string) { - store := ctx.KVStore(k.storeKey) - addressBytes := []byte(sequencerAddr) - - activeKey := types.ProposerByRollappKey(rollappId) - store.Set(activeKey, addressBytes) -} - -// GetProposer returns the proposer for a rollapp -func (k Keeper) GetProposer(ctx sdk.Context, rollappId string) (val types.Sequencer, found bool) { - store := ctx.KVStore(k.storeKey) - b := store.Get(types.ProposerByRollappKey(rollappId)) - if len(b) == 0 || string(b) == NO_SEQUENCER_AVAILABLE { - return val, false +func (k Keeper) NewSequencer(ctx sdk.Context, rollapp string) *types.Sequencer { + return &types.Sequencer{ + RollappId: rollapp, + // DO NOT USE NEW COINS! IT WILL REMOVE ZERO COIN + Tokens: sdk.Coins{sdk.NewCoin(k.bondDenom(ctx), sdk.NewInt(0))}, } - - return k.GetSequencer(ctx, string(b)) -} - -func (k Keeper) removeProposer(ctx sdk.Context, rollappId string) { - k.SetProposer(ctx, rollappId, NO_SEQUENCER_AVAILABLE) -} - -func (k Keeper) isProposer(ctx sdk.Context, rollappId, seqAddr string) bool { - proposer, ok := k.GetProposer(ctx, rollappId) - return ok && proposer.Address == seqAddr -} - -// SetNextProposer sets the next proposer for a rollapp -// called when the proposer has finished its notice period and rotation flow has started -func (k Keeper) setNextProposer(ctx sdk.Context, rollappId, seqAddr string) { - store := ctx.KVStore(k.storeKey) - addressBytes := []byte(seqAddr) - nextProposerKey := types.NextProposerByRollappKey(rollappId) - store.Set(nextProposerKey, addressBytes) -} - -// GetNextProposer returns the next proposer for a rollapp -// It will return found=false if the next proposer is not set -// It will return found=true if the next proposer is set, even if it's empty -func (k Keeper) GetNextProposer(ctx sdk.Context, rollappId string) (val types.Sequencer, found bool) { - store := ctx.KVStore(k.storeKey) - b := store.Get(types.NextProposerByRollappKey(rollappId)) - if b == nil { - return val, false - } - - address := string(b) - if address == NO_SEQUENCER_AVAILABLE { - return val, true - } - return k.GetSequencer(ctx, address) -} - -func (k Keeper) isNextProposerSet(ctx sdk.Context, rollappId string) bool { - store := ctx.KVStore(k.storeKey) - return store.Has(types.NextProposerByRollappKey(rollappId)) -} - -func (k Keeper) isNextProposer(ctx sdk.Context, rollappId, seqAddr string) bool { - nextProposer, ok := k.GetNextProposer(ctx, rollappId) - return ok && nextProposer.Address == seqAddr -} - -// removeNextProposer removes the next proposer for a rollapp -// called when the proposer has finished its rotation flow -func (k Keeper) removeNextProposer(ctx sdk.Context, rollappId string) { - store := ctx.KVStore(k.storeKey) - store.Delete(types.NextProposerByRollappKey(rollappId)) } diff --git a/x/sequencer/keeper/sequencer_suite_test.go b/x/sequencer/keeper/sequencer_suite_test.go deleted file mode 100644 index 5dec46111..000000000 --- a/x/sequencer/keeper/sequencer_suite_test.go +++ /dev/null @@ -1,108 +0,0 @@ -package keeper_test - -import ( - "testing" - - cometbftproto "github.com/cometbft/cometbft/proto/tendermint/types" - "github.com/cosmos/cosmos-sdk/baseapp" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" - sdk "github.com/cosmos/cosmos-sdk/types" - bankutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" - "github.com/dymensionxyz/sdk-utils/utils/urand" - "github.com/stretchr/testify/suite" - - "github.com/dymensionxyz/dymension/v3/app/apptesting" - "github.com/dymensionxyz/dymension/v3/testutil/sample" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -type SequencerTestSuite struct { - apptesting.KeeperTestHelper - msgServer types.MsgServer - queryClient types.QueryClient -} - -func TestSequencerKeeperTestSuite(t *testing.T) { - suite.Run(t, new(SequencerTestSuite)) -} - -func (suite *SequencerTestSuite) SetupTest() { - app := apptesting.Setup(suite.T(), false) - ctx := app.GetBaseApp().NewContext(false, cometbftproto.Header{}) - - queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry()) - types.RegisterQueryServer(queryHelper, app.SequencerKeeper) - queryClient := types.NewQueryClient(queryHelper) - - suite.App = app - suite.msgServer = keeper.NewMsgServerImpl(app.SequencerKeeper) - suite.Ctx = ctx - suite.queryClient = queryClient -} - -func (suite *SequencerTestSuite) CreateDefaultRollapp() (string, cryptotypes.PubKey) { - pubkey := ed25519.GenPrivKey().PubKey() - addr := sdk.AccAddress(pubkey.Address()) - return suite.CreateRollappWithInitialSequencer(addr.String()), pubkey -} - -func (suite *SequencerTestSuite) CreateRollappWithInitialSequencer(initSeq string) string { - rollapp := rollapptypes.Rollapp{ - RollappId: urand.RollappID(), - Owner: sample.AccAddress(), - GenesisInfo: rollapptypes.GenesisInfo{ - Bech32Prefix: "rol", - GenesisChecksum: "checksum", - NativeDenom: rollapptypes.DenomMetadata{Display: "DEN", Base: "aden", Exponent: 18}, - InitialSupply: sdk.NewInt(1000), - }, - InitialSequencer: initSeq, - } - suite.App.RollappKeeper.SetRollapp(suite.Ctx, rollapp) - return rollapp.GetRollappId() -} - -func (suite *SequencerTestSuite) CreateSequencer(ctx sdk.Context, rollappId string, pk cryptotypes.PubKey) string { - return suite.CreateSequencerWithBond(ctx, rollappId, bond, pk) -} - -func (suite *SequencerTestSuite) CreateSequencerWithBond(ctx sdk.Context, rollappId string, bond sdk.Coin, pk cryptotypes.PubKey) string { - pkAny, err := codectypes.NewAnyWithValue(pk) - suite.Require().Nil(err) - - addr := sdk.AccAddress(pk.Address()) - // fund account - err = bankutil.FundAccount(suite.App.BankKeeper, ctx, addr, sdk.NewCoins(bond)) - suite.Require().Nil(err) - - sequencerMsg1 := types.MsgCreateSequencer{ - Creator: addr.String(), - DymintPubKey: pkAny, - Bond: bond, - RollappId: rollappId, - Metadata: types.SequencerMetadata{ - Rpcs: []string{"https://rpc.wpd.evm.rollapp.noisnemyd.xyz:443"}, - EvmRpcs: []string{"https://rpc.evm.rollapp.noisnemyd.xyz:443"}, - }, - } - _, err = suite.msgServer.CreateSequencer(ctx, &sequencerMsg1) - suite.Require().NoError(err) - return addr.String() -} - -func (suite *SequencerTestSuite) assertJailed(seqAddr string) { - seq, found := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, seqAddr) - suite.Require().True(found) - suite.True(seq.Jailed) - suite.Equal(types.Unbonded, seq.Status) - suite.Equal(sdk.Coins(nil), seq.Tokens) - - sequencers := suite.App.SequencerKeeper.GetMatureUnbondingSequencers(suite.Ctx, suite.Ctx.BlockTime()) - for _, s := range sequencers { - suite.NotEqual(s.Address, seqAddr) - } -} diff --git a/x/sequencer/keeper/sequencer_test.go b/x/sequencer/keeper/sequencer_test.go deleted file mode 100644 index 6b0f80494..000000000 --- a/x/sequencer/keeper/sequencer_test.go +++ /dev/null @@ -1,70 +0,0 @@ -package keeper_test - -import ( - "strconv" - "testing" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/stretchr/testify/require" - - keepertest "github.com/dymensionxyz/dymension/v3/testutil/keeper" - "github.com/dymensionxyz/dymension/v3/testutil/nullify" - "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -// Prevent strconv unused error -var _ = strconv.IntSize - -func createNSequencer(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Sequencer { - items := make([]types.Sequencer, n) - for i := range items { - seq := types.Sequencer{ - Address: strconv.Itoa(i), - Status: types.Bonded, - } - items[i] = seq - - keeper.SetSequencer(ctx, items[i]) - } - return items -} - -func TestSequencerGet(t *testing.T) { - keeper, ctx := keepertest.SequencerKeeper(t) - items := createNSequencer(keeper, ctx, 10) - for _, item := range items { - item := item - rst, found := keeper.GetSequencer(ctx, - item.Address, - ) - require.True(t, found) - require.Equal(t, - nullify.Fill(&item), - nullify.Fill(&rst), - ) - } -} - -func TestSequencerGetAll(t *testing.T) { - k, ctx := keepertest.SequencerKeeper(t) - items := createNSequencer(k, ctx, 10) - require.ElementsMatch(t, - nullify.Fill(items), - nullify.Fill(k.GetAllSequencers(ctx)), - ) -} - -func TestSequencersByRollappGet(t *testing.T) { - k, ctx := keepertest.SequencerKeeper(t) - items := createNSequencer(k, ctx, 10) - rst := k.GetSequencersByRollapp(ctx, - items[0].RollappId, - ) - - require.Equal(t, len(rst), len(items)) - require.ElementsMatch(t, - nullify.Fill(items), - nullify.Fill(rst), - ) -} diff --git a/x/sequencer/keeper/slashing.go b/x/sequencer/keeper/slashing.go deleted file mode 100644 index 35028f511..000000000 --- a/x/sequencer/keeper/slashing.go +++ /dev/null @@ -1,109 +0,0 @@ -package keeper - -import ( - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" - "github.com/dymensionxyz/sdk-utils/utils/ucoin" -) - -func (k Keeper) JailSequencerOnFraud(ctx sdk.Context, seqAddr string) error { - seq, found := k.GetSequencer(ctx, seqAddr) - if !found { - return types.ErrUnknownSequencer - } - - if err := k.Jail(ctx, seq); err != nil { - return errorsmod.Wrap(err, "jail") - } - - return nil -} - -func (k Keeper) SlashLiveness(ctx sdk.Context, rollappID string) error { - seq, err := k.LivenessLiableSequencer(ctx, rollappID) - if err != nil { - return err - } - mul := k.GetParams(ctx).LivenessSlashMultiplier - tokens := seq.Tokens - amt := ucoin.MulDec(mul, tokens...) - // TODO: make sure to be correct wrt. min bond, see https://github.com/dymensionxyz/dymension/issues/1019 - return k.Slash(ctx, &seq, amt) -} - -func (k Keeper) JailLiveness(ctx sdk.Context, rollappID string) error { - seq, err := k.LivenessLiableSequencer(ctx, rollappID) - if err != nil { - return errorsmod.Wrap(err, "liveness liable sequencer") - } - return k.Jail(ctx, seq) -} - -// LivenessLiableSequencer returns the sequencer who is responsible for ensuring liveness -func (k Keeper) LivenessLiableSequencer(ctx sdk.Context, rollappID string) (types.Sequencer, error) { - proposer, found := k.GetProposer(ctx, rollappID) - if !found { - return types.Sequencer{}, types.ErrNoProposer - } - return proposer, nil -} - -func (k Keeper) Slash(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coins) error { - if seq.Status == types.Unbonded { - return errorsmod.Wrap( - types.ErrInvalidSequencerStatus, - "can't slash unbonded sequencer", - ) - } - - err := k.reduceSequencerBond(ctx, seq, amt, true) - if err != nil { - return errorsmod.Wrap(err, "remove sequencer bond") - } - k.UpdateSequencer(ctx, seq) - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeSlashed, - sdk.NewAttribute(types.AttributeKeySequencer, seq.Address), - sdk.NewAttribute(types.AttributeKeyBond, amt.String()), - ), - ) - return nil -} - -// Jail sets the sequencer status to Jailed and unbonds the sequencer -func (k Keeper) Jail(ctx sdk.Context, seq types.Sequencer) error { - err := k.unbondSequencerAndJail(ctx, seq.Address) - if err != nil { - return errorsmod.Wrap(err, "unbond and jail") - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeJailed, - sdk.NewAttribute(types.AttributeKeySequencer, seq.Address), - sdk.NewAttribute(types.AttributeKeyBond, seq.Tokens.String()), - ), - ) - - return nil -} - -// Jail sets the sequencer status to Jailed and unbonds the sequencer -func (k Keeper) JailByAddr(ctx sdk.Context, seqAddr string) error { - err := k.unbondSequencerAndJail(ctx, seqAddr) - if err != nil { - return errorsmod.Wrap(err, "unbond and jail") - } - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeJailed, - sdk.NewAttribute(types.AttributeKeySequencer, seqAddr), - ), - ) - - return nil -} diff --git a/x/sequencer/keeper/slashing_fraud_test.go b/x/sequencer/keeper/slashing_fraud_test.go deleted file mode 100644 index deedf1bb2..000000000 --- a/x/sequencer/keeper/slashing_fraud_test.go +++ /dev/null @@ -1,99 +0,0 @@ -package keeper_test - -import ( - "time" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -func (suite *SequencerTestSuite) TestJailUnknownSequencer() { - suite.CreateDefaultRollapp() - keeper := suite.App.SequencerKeeper - - err := keeper.JailSequencerOnFraud(suite.Ctx, "unknown_sequencer") - suite.ErrorIs(err, types.ErrUnknownSequencer) -} - -func (suite *SequencerTestSuite) TestJailUnbondedSequencer() { - keeper := suite.App.SequencerKeeper - suite.Ctx = suite.Ctx.WithBlockHeight(20) - suite.Ctx = suite.Ctx.WithBlockTime(time.Now()) - - rollappId, _ := suite.CreateDefaultRollappAndProposer() - seqAddr := suite.CreateDefaultSequencer(suite.Ctx, rollappId) // bonded non proposer - - // unbond the non-proposer - unbondMsg := types.MsgUnbond{Creator: seqAddr} - res, err := suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - unbondTime := res.GetUnbondingCompletionTime() - keeper.UnbondAllMatureSequencers(suite.Ctx, unbondTime.Add(1*time.Second)) - seq, found := keeper.GetSequencer(suite.Ctx, seqAddr) - suite.Require().True(found) - suite.Equal(seq.Address, seqAddr) - suite.Equal(seq.Status, types.Unbonded) - - // jail the unbonded sequencer - err = keeper.JailSequencerOnFraud(suite.Ctx, seqAddr) - suite.ErrorIs(err, types.ErrInvalidSequencerStatus) -} - -func (suite *SequencerTestSuite) TestJailUnbondingSequencer() { - keeper := suite.App.SequencerKeeper - suite.Ctx = suite.Ctx.WithBlockHeight(20) - suite.Ctx = suite.Ctx.WithBlockTime(time.Now()) - - rollappId, _ := suite.CreateDefaultRollappAndProposer() - seqAddr := suite.CreateDefaultSequencer(suite.Ctx, rollappId) // bonded non proposer - - // unbond the non-proposer - unbondMsg := types.MsgUnbond{Creator: seqAddr} - _, err := suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - seq, ok := keeper.GetSequencer(suite.Ctx, seqAddr) - suite.Require().True(ok) - suite.Equal(seq.Status, types.Unbonding) - - // jail the unbonding sequencer - err = keeper.JailSequencerOnFraud(suite.Ctx, seqAddr) - suite.NoError(err) - suite.assertJailed(seqAddr) -} - -func (suite *SequencerTestSuite) TestJailProposerSequencer() { - keeper := suite.App.SequencerKeeper - suite.Ctx = suite.Ctx.WithBlockHeight(20) - suite.Ctx = suite.Ctx.WithBlockTime(time.Now()) - - rollappId, proposer := suite.CreateDefaultRollappAndProposer() - err := keeper.JailSequencerOnFraud(suite.Ctx, proposer) - suite.NoError(err) - suite.assertJailed(proposer) - - _, found := keeper.GetProposer(suite.Ctx, rollappId) - suite.Require().False(found) -} - -func (suite *SequencerTestSuite) TestJailBondReducingSequencer() { - keeper := suite.App.SequencerKeeper - suite.Ctx = suite.Ctx.WithBlockHeight(20) - suite.Ctx = suite.Ctx.WithBlockTime(time.Now()) - - rollappId, pk := suite.CreateDefaultRollapp() - seqAddr := suite.CreateSequencerWithBond(suite.Ctx, rollappId, bond.AddAmount(sdk.NewInt(20)), pk) - - reduceBondMsg := types.MsgDecreaseBond{Creator: seqAddr, DecreaseAmount: sdk.NewInt64Coin(bond.Denom, 10)} - resp, err := suite.msgServer.DecreaseBond(suite.Ctx, &reduceBondMsg) - suite.Require().NoError(err) - bondReductions := keeper.GetMatureDecreasingBondIDs(suite.Ctx, resp.GetCompletionTime()) - suite.Require().Len(bondReductions, 1) - - err = keeper.JailSequencerOnFraud(suite.Ctx, seqAddr) - suite.NoError(err) - - bondReductions = keeper.GetMatureDecreasingBondIDs(suite.Ctx, resp.GetCompletionTime()) - suite.Require().Len(bondReductions, 0) - suite.assertJailed(seqAddr) -} diff --git a/x/sequencer/keeper/slashing_test.go b/x/sequencer/keeper/slashing_test.go deleted file mode 100644 index 4b9edbb47..000000000 --- a/x/sequencer/keeper/slashing_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package keeper_test - -func (s *SequencerTestSuite) TestSlashBasic() { - s.Run("slash at zero does not error", func() { - // There shouldn't be an error if the sequencer has no tokens - k := s.App.SequencerKeeper - rollappId, pk := s.CreateDefaultRollapp() - seqAddr := s.CreateSequencer(s.Ctx, rollappId, pk) - seq, found := k.GetSequencer(s.Ctx, seqAddr) - s.Require().True(found) - err := k.Slash(s.Ctx, &seq, seq.Tokens) - s.Require().NoError(err) - err = k.Slash(s.Ctx, &seq, seq.Tokens) - s.Require().NoError(err) - }) -} diff --git a/x/sequencer/keeper/unbond.go b/x/sequencer/keeper/unbond.go deleted file mode 100644 index 5d64fe34c..000000000 --- a/x/sequencer/keeper/unbond.go +++ /dev/null @@ -1,187 +0,0 @@ -package keeper - -import ( - "fmt" - "time" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/osmosis-labs/osmosis/v15/osmoutils" - - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -// startUnbondingPeriodForSequencer sets the sequencer to unbonding status -// can be called after notice period or directly if notice period is not required -// caller is responsible for updating the proposer for the rollapp if needed -func (k Keeper) startUnbondingPeriodForSequencer(ctx sdk.Context, seq *types.Sequencer) time.Time { - completionTime := ctx.BlockTime().Add(k.UnbondingTime(ctx)) - seq.UnbondTime = completionTime - - seq.Status = types.Unbonding - k.UpdateSequencer(ctx, seq, types.Bonded) - k.AddSequencerToUnbondingQueue(ctx, seq) - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeUnbonding, - sdk.NewAttribute(types.AttributeKeySequencer, seq.Address), - sdk.NewAttribute(types.AttributeKeyBond, seq.Tokens.String()), - sdk.NewAttribute(types.AttributeKeyCompletionTime, completionTime.String()), - ), - ) - - return completionTime -} - -// UnbondAllMatureSequencers unbonds all the mature unbonding sequencers that -// have finished their unbonding period. -func (k Keeper) UnbondAllMatureSequencers(ctx sdk.Context, currTime time.Time) { - sequencers := k.GetMatureUnbondingSequencers(ctx, currTime) - for _, seq := range sequencers { - wrapFn := func(ctx sdk.Context) error { - return k.unbondSequencer(ctx, seq.Address) - } - err := osmoutils.ApplyFuncIfNoError(ctx, wrapFn) - if err != nil { - k.Logger(ctx).Error("unbond sequencer", "error", err, "sequencer", seq.Address) - continue - } - } -} - -// InstantUnbondAllSequencers unbonds all sequencers for a rollapp -// This is called when there is a fraud -func (k Keeper) InstantUnbondAllSequencers(ctx sdk.Context, rollappID string) error { - // unbond all bonded/unbonding sequencers - bonded := k.GetSequencersByRollappByStatus(ctx, rollappID, types.Bonded) - unbonding := k.GetSequencersByRollappByStatus(ctx, rollappID, types.Unbonding) - for _, sequencer := range append(bonded, unbonding...) { - err := k.unbondSequencer(ctx, sequencer.Address) - if err != nil { - k.Logger(ctx).Error("unbond sequencer", "error", err, "sequencer", sequencer.Address) - } - } - - return nil -} - -// reduceSequencerBond reduces the bond of a sequencer -// if burn is true, the tokens are burned, otherwise they are refunded -// returns an error if the sequencer does not have enough bond -// method updates the sequencer object. doesn't update the store -func (k Keeper) reduceSequencerBond(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coins, burn bool) error { - if amt.IsZero() { - return nil - } - if !seq.Tokens.IsAllGTE(amt) { - return fmt.Errorf("sequencer does not have enough bond: got %s, reducing by %s", seq.Tokens.String(), amt.String()) - } - if burn { - err := k.bankKeeper.BurnCoins(ctx, types.ModuleName, amt) - if err != nil { - return err - } - } else { - // refund - seqAcc := sdk.MustAccAddressFromBech32(seq.Address) - err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, seqAcc, amt) - if err != nil { - return err - } - } - - seq.Tokens = seq.Tokens.Sub(amt...) - return nil -} - -func (k Keeper) unbondSequencerAndJail(ctx sdk.Context, seqAddr string) error { - return k.unbond(ctx, seqAddr, true) -} - -func (k Keeper) unbondSequencer(ctx sdk.Context, seqAddr string) error { - return k.unbond(ctx, seqAddr, false) -} - -// unbond unbonds a sequencer -// if jail is true, the sequencer is jailed as well (cannot be bonded again) -// bonded tokens are refunded by default, unless jail is true -func (k Keeper) unbond(ctx sdk.Context, seqAddr string, jail bool) error { - seq, found := k.GetSequencer(ctx, seqAddr) - if !found { - return types.ErrUnknownSequencer - } - - if seq.Status == types.Unbonded { - return errorsmod.Wrapf( - types.ErrInvalidSequencerStatus, - "sequencer status is already unbonded", - ) - } - // keep the old status for updating the sequencer - oldStatus := seq.Status - - // handle bond: tokens refunded by default, unless jail is true - err := k.reduceSequencerBond(ctx, &seq, seq.Tokens, jail) - if err != nil { - return errorsmod.Wrap(err, "remove sequencer bond") - } - - /* ------------------------------ store cleanup ----------------------------- */ - // remove from queue if unbonding - if oldStatus == types.Unbonding { - k.removeUnbondingSequencer(ctx, seq) - } else { - // remove from notice period queue if needed - if seq.IsNoticePeriodInProgress() { - k.removeNoticePeriodSequencer(ctx, seq) - } - - // if we unbond the proposer, remove it - // the caller should rotate the proposer - if k.isProposer(ctx, seq.RollappId, seqAddr) { - k.removeProposer(ctx, seq.RollappId) - } - - // if we unbond the next proposer, we're in the middle of rotation - // the caller should clean the rotation state - if k.isNextProposer(ctx, seq.RollappId, seqAddr) { - k.removeNextProposer(ctx, seq.RollappId) - } - } - // in case the sequencer is currently reducing its bond, then we need to remove it from the decreasing bond queue - // all the tokens are returned, so we don't need to reduce the bond anymore - if bondReductionIDs := k.getBondReductionIDsBySequencer(ctx, seq.Address); len(bondReductionIDs) > 0 { - for _, bondReductionID := range bondReductionIDs { - bondReduction, found := k.GetBondReduction(ctx, bondReductionID) - if found { - k.removeBondReduction(ctx, bondReductionID, bondReduction) - } - } - } - - if jail { - seq.Jailed = true - } - // set the unbonding height and time, if not already set. - // to avoid leaving unbonded sequencer in the store with no unbond height or time - if seq.UnbondRequestHeight == 0 { - seq.UnbondRequestHeight = ctx.BlockHeight() - } - if seq.UnbondTime.IsZero() { - seq.UnbondTime = ctx.BlockTime() - } - - // update the sequencer in store - seq.Status = types.Unbonded - k.UpdateSequencer(ctx, &seq, oldStatus) - - ctx.EventManager().EmitEvent( - sdk.NewEvent( - types.EventTypeUnbonded, - sdk.NewAttribute(types.AttributeKeySequencer, seqAddr), - ), - ) - - return nil -} diff --git a/x/sequencer/keeper/unbond_test.go b/x/sequencer/keeper/unbond_test.go deleted file mode 100644 index 29c729160..000000000 --- a/x/sequencer/keeper/unbond_test.go +++ /dev/null @@ -1,124 +0,0 @@ -package keeper_test - -import ( - "time" - - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -func (suite *SequencerTestSuite) TestUnbondingMultiple() { - suite.Ctx = suite.Ctx.WithBlockHeight(10) - suite.Ctx = suite.Ctx.WithBlockTime(time.Now()) - - keeper := suite.App.SequencerKeeper - - rollappId, pk1 := suite.CreateDefaultRollapp() - rollappId2, pk2 := suite.CreateDefaultRollapp() - - numOfSequencers := 4 - numOfSequencers2 := 3 - unbodingSeq := 2 - - seqAddr1 := make([]string, numOfSequencers) - seqAddr2 := make([]string, numOfSequencers2) - - // create 5 sequencers for rollapp1 - seqAddr1[0] = suite.CreateSequencer(suite.Ctx, rollappId, pk1) - for i := 1; i < numOfSequencers; i++ { - seqAddr1[i] = suite.CreateSequencer(suite.Ctx, rollappId, ed25519.GenPrivKey().PubKey()) - } - - // create 3 sequencers for rollapp2 - seqAddr2[0] = suite.CreateSequencer(suite.Ctx, rollappId2, pk2) - for i := 1; i < numOfSequencers2; i++ { - seqAddr2[i] = suite.CreateSequencer(suite.Ctx, rollappId2, ed25519.GenPrivKey().PubKey()) - } - - // start unbonding for 2 sequencers in each rollapp - suite.Ctx = suite.Ctx.WithBlockHeight(20) - now := time.Now() - unbondTime := now.Add(keeper.GetParams(suite.Ctx).UnbondingTime) - suite.Ctx = suite.Ctx.WithBlockTime(now) - for i := 1; i < unbodingSeq+1; i++ { - unbondMsg := types.MsgUnbond{Creator: seqAddr1[i]} - _, err := suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - - unbondMsg = types.MsgUnbond{Creator: seqAddr2[i]} - _, err = suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - } - - // before unbonding time reached - sequencers := keeper.GetMatureUnbondingSequencers(suite.Ctx, now) - suite.Require().Len(sequencers, 0) - - sequencers = keeper.GetMatureUnbondingSequencers(suite.Ctx, unbondTime.Add(-1*time.Second)) - suite.Require().Len(sequencers, 0) - - // past unbonding time - sequencers = keeper.GetMatureUnbondingSequencers(suite.Ctx, unbondTime.Add(1*time.Second)) - suite.Require().Len(sequencers, 4) -} - -func (suite *SequencerTestSuite) TestTokensRefundOnUnbond() { - denom := bond.Denom - blockheight := 20 - var err error - - rollappId, pk := suite.CreateDefaultRollapp() - _ = suite.CreateSequencer(suite.Ctx, rollappId, pk) - - pk1 := ed25519.GenPrivKey().PubKey() - addr1 := suite.CreateSequencer(suite.Ctx, rollappId, pk1) - sequencer1, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr1) - suite.Require().True(sequencer1.Status == types.Bonded) - suite.Require().False(sequencer1.Tokens.IsZero()) - - pk2 := ed25519.GenPrivKey().PubKey() - addr2 := suite.CreateSequencer(suite.Ctx, rollappId, pk2) - sequencer2, _ := suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr2) - suite.Require().True(sequencer2.Status == types.Bonded) - suite.Require().False(sequencer2.Tokens.IsZero()) - - suite.Ctx = suite.Ctx.WithBlockHeight(int64(blockheight)) - suite.Ctx = suite.Ctx.WithBlockTime(time.Now()) - - // start the 1st unbond - unbondMsg := types.MsgUnbond{Creator: addr1} - _, err = suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - sequencer1, _ = suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr1) - suite.Require().True(sequencer1.Status == types.Unbonding) - suite.Require().Equal(sequencer1.UnbondRequestHeight, int64(blockheight)) - suite.Require().False(sequencer1.Tokens.IsZero()) - - // start the 2nd unbond later - suite.Ctx = suite.Ctx.WithBlockHeight(suite.Ctx.BlockHeight() + 1) - suite.Ctx = suite.Ctx.WithBlockTime(suite.Ctx.BlockTime().Add(5 * time.Minute)) - unbondMsg = types.MsgUnbond{Creator: addr2} - _, err = suite.msgServer.Unbond(suite.Ctx, &unbondMsg) - suite.Require().NoError(err) - sequencer2, _ = suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr2) - suite.Require().True(sequencer2.Status == types.Unbonding) - suite.Require().False(sequencer2.Tokens.IsZero()) - - /* -------------------------- check the unbond phase ------------------------- */ - balanceBefore := suite.App.BankKeeper.GetBalance(suite.Ctx, sdk.MustAccAddressFromBech32(addr1), denom) - suite.App.SequencerKeeper.UnbondAllMatureSequencers(suite.Ctx, sequencer1.UnbondTime.Add(1*time.Second)) - balanceAfter := suite.App.BankKeeper.GetBalance(suite.Ctx, sdk.MustAccAddressFromBech32(addr1), denom) - - // Check stake refunded - sequencer1, _ = suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr1) - suite.Equal(types.Unbonded, sequencer1.Status) - suite.True(sequencer1.Tokens.IsZero()) - suite.True(balanceBefore.Add(bond).IsEqual(balanceAfter), "expected %s, got %s", balanceBefore.Add(bond), balanceAfter) - - // check the 2nd unbond still not happened - sequencer2, _ = suite.App.SequencerKeeper.GetSequencer(suite.Ctx, addr2) - suite.Equal(types.Unbonding, sequencer2.Status) - suite.False(sequencer2.Tokens.IsZero()) -} diff --git a/x/sequencer/keeper/util_test.go b/x/sequencer/keeper/util_test.go new file mode 100644 index 000000000..382cd47ee --- /dev/null +++ b/x/sequencer/keeper/util_test.go @@ -0,0 +1,241 @@ +package keeper_test + +import ( + "reflect" + "slices" + "strconv" + "testing" + + cometbftproto "github.com/cometbft/cometbft/proto/tendermint/types" + "github.com/cosmos/cosmos-sdk/baseapp" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + bankutil "github.com/cosmos/cosmos-sdk/x/bank/testutil" + "github.com/dymensionxyz/dymension/v3/app/apptesting" + rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + "github.com/dymensionxyz/sdk-utils/utils/urand" + "github.com/stretchr/testify/suite" + + "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" + + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/dymensionxyz/dymension/v3/testutil/sample" +) + +var ( + + // TODO: use separate cosmos/dymint pubkeys in tests https://github.com/dymensionxyz/dymension/issues/1360 + + bond = types.DefaultParams().MinBond + kick = types.DefaultParams().KickThreshold + pks = []cryptotypes.PubKey{ + randomTMPubKey(), + randomTMPubKey(), + randomTMPubKey(), + randomTMPubKey(), + randomTMPubKey(), + randomTMPubKey(), + randomTMPubKey(), + randomTMPubKey(), + randomTMPubKey(), + } + alice = pks[0] + bob = pks[1] + charlie = pks[2] + david = pks[3] + eve = pks[4] + faythe = pks[5] + _ = eve + _ = faythe +) + +func randomTMPubKey() cryptotypes.PubKey { + return ed25519.GenPrivKey().PubKey() +} + +func pkAcc(pk cryptotypes.PubKey) sdk.AccAddress { + return sdk.AccAddress(pk.Address()) +} + +func pkAddr(pk cryptotypes.PubKey) string { + return pkAcc(pk).String() +} + +// Prevent strconv unused error +var _ = strconv.IntSize + +type SequencerTestSuite struct { + apptesting.KeeperTestHelper + msgServer types.MsgServer + queryClient types.QueryClient +} + +func (s *SequencerTestSuite) k() *keeper.Keeper { + return s.App.SequencerKeeper +} + +func (s *SequencerTestSuite) raK() *rollappkeeper.Keeper { + return s.App.RollappKeeper +} + +func TestSequencerKeeperTestSuite(t *testing.T) { + suite.Run(t, new(SequencerTestSuite)) +} + +func (s *SequencerTestSuite) SetupTest() { + app := apptesting.Setup(s.T(), false) + ctx := app.GetBaseApp().NewContext(false, cometbftproto.Header{}) + + queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry()) + types.RegisterQueryServer(queryHelper, app.SequencerKeeper) + queryClient := types.NewQueryClient(queryHelper) + + s.App = app + s.msgServer = keeper.NewMsgServerImpl(app.SequencerKeeper) + s.Ctx = ctx + s.queryClient = queryClient + + // Overwrite to exclude any unblockers set by default in apptesting, to ensure + // we are only testing our logic. + s.k().SetUnbondBlockers() +} + +func (s *SequencerTestSuite) seq(pk cryptotypes.PubKey) types.Sequencer { + return s.k().GetSequencer(s.Ctx, pkAddr(pk)) +} + +func (s *SequencerTestSuite) moduleBalance() sdk.Coin { + acc := s.App.AccountKeeper.GetModuleAccount(s.Ctx, types.ModuleName) + cs := s.App.BankKeeper.GetAllBalances(s.Ctx, acc.GetAddress()) + if cs.Len() == 0 { + // coins will be zerod + ret := bond + ret.Amount = sdk.ZeroInt() + return ret + } + return cs[0] +} + +func (s *SequencerTestSuite) createRollapp() rollapptypes.Rollapp { + return s.createRollappWithInitialSeqConstraint("*") +} + +// init seq is an addr or empty or * +func (s *SequencerTestSuite) createRollappWithInitialSeqConstraint(initSeq string) rollapptypes.Rollapp { + rollapp := rollapptypes.Rollapp{ + RollappId: urand.RollappID(), + Owner: sample.AccAddress(), + GenesisInfo: rollapptypes.GenesisInfo{ + Bech32Prefix: "rol", + GenesisChecksum: "checksum", + NativeDenom: rollapptypes.DenomMetadata{Display: "DEN", Base: "aden", Exponent: 18}, + InitialSupply: sdk.NewInt(1000), + }, + InitialSequencer: initSeq, + } + s.raK().SetRollapp(s.Ctx, rollapp) + return rollapp +} + +// Note: this method doesn't really mimic real usage +func createSequencerMsgOnePubkey(rollapp string, pk cryptotypes.PubKey) types.MsgCreateSequencer { + return createSequencerMsg(rollapp, pk, pk) +} + +// mimics real usage because two different keys will be used +func createSequencerMsg(rollapp string, pkCosmos, pkDymint cryptotypes.PubKey) types.MsgCreateSequencer { + pkAny, err := codectypes.NewAnyWithValue(pkDymint) + if err != nil { + panic(err) + } + + return types.MsgCreateSequencer{ + Creator: pkAddr(pkCosmos), + DymintPubKey: pkAny, + // Bond not included + RollappId: rollapp, + Metadata: types.SequencerMetadata{ + Rpcs: []string{"https://rpc.wpd.evm.rollapp.noisnemyd.xyz:443"}, + EvmRpcs: []string{"https://rpc.evm.rollapp.noisnemyd.xyz:443"}, + }, + } +} + +func (s *SequencerTestSuite) fundSequencer(pk cryptotypes.PubKey, amt sdk.Coin) { + err := bankutil.FundAccount(s.App.BankKeeper, s.Ctx, pkAcc(pk), sdk.NewCoins(amt)) + s.Require().NoError(err) +} + +func (s *SequencerTestSuite) createSequencerWithBond(ctx sdk.Context, rollapp string, pk cryptotypes.PubKey, bond sdk.Coin) types.Sequencer { + s.fundSequencer(pk, bond) + msg := createSequencerMsgOnePubkey(rollapp, pk) + msg.Bond = bond + _, err := s.msgServer.CreateSequencer(ctx, &msg) + s.Require().NoError(err) + return s.k().GetSequencer(ctx, pkAddr(pk)) +} + +func (s *SequencerTestSuite) equalSequencers(s1 *types.Sequencer, s2 *types.Sequencer) { + eq := equalSequencers(s1, s2) + s.Require().True(eq, "expected: %+v\nfound: %+v", *s1, *s2) +} + +func equalSequencers(s1, s2 *types.Sequencer) bool { + if s1.Address != s2.Address { + return false + } + + s1Pubkey := s1.DymintPubKey + s2Pubkey := s2.DymintPubKey + if !s1Pubkey.Equal(s2Pubkey) { + return false + } + if s1.RollappId != s2.RollappId { + return false + } + if !reflect.DeepEqual(s1.Metadata, s2.Metadata) { + return false + } + + if s1.Status != s2.Status { + return false + } + + if s1.OptedIn != s2.OptedIn { + return false + } + + if !s1.Tokens.IsEqual(s2.Tokens) { + return false + } + + if !s1.NoticePeriodTime.Equal(s2.NoticePeriodTime) { + return false + } + + if s1.RewardAddr != s2.RewardAddr { + return false + } + if !slices.Equal(s1.WhitelistedRelayers, s2.WhitelistedRelayers) { + return false + } + + return true +} + +func createNSequencers(keeper *keeper.Keeper, ctx sdk.Context, n int) []types.Sequencer { + items := make([]types.Sequencer, n) + for i := range items { + seq := types.Sequencer{ + Address: strconv.Itoa(i), + Status: types.Bonded, + } + items[i] = seq + + keeper.SetSequencer(ctx, items[i]) + } + return items +} diff --git a/x/sequencer/migrations.go b/x/sequencer/migrations.go index d95febb13..4d88febb4 100644 --- a/x/sequencer/migrations.go +++ b/x/sequencer/migrations.go @@ -22,12 +22,12 @@ type ( // Migrator is a struct for handling in-place store migrations. type Migrator struct { - keeper seqkeeper.Keeper + keeper *seqkeeper.Keeper legacySubspace Subspace } // NewMigrator returns a new Migrator. -func NewMigrator(keeper seqkeeper.Keeper, ss Subspace) Migrator { +func NewMigrator(keeper *seqkeeper.Keeper, ss Subspace) Migrator { return Migrator{keeper: keeper, legacySubspace: ss} } diff --git a/x/sequencer/migrations_test.go b/x/sequencer/migrations_test.go index 6704bd4e4..53afb31d9 100644 --- a/x/sequencer/migrations_test.go +++ b/x/sequencer/migrations_test.go @@ -16,9 +16,7 @@ func TestMigrate2to3(t *testing.T) { ctx := app.BaseApp.NewContext(false, cometbftproto.Header{Height: 1, ChainID: "dymension_100-1", Time: time.Now().UTC()}) // create legacy subspace - testValue := 555555 * time.Second // random value for testing params := types.DefaultParams() - params.UnbondingTime = testValue seqSubspace, ok := app.AppKeepers.ParamsKeeper.GetSubspace(types.ModuleName) if !ok { @@ -43,7 +41,4 @@ func TestMigrate2to3(t *testing.T) { // Check if the value was migrated correctly params = app.SequencerKeeper.GetParams(ctx) - if params.UnbondingTime != testValue { - t.Errorf("UnbondingTime not migrated correctly: got %v, expected %v", params.UnbondingTime, testValue) - } } diff --git a/x/sequencer/module.go b/x/sequencer/module.go index 40e35b8dc..171755e03 100644 --- a/x/sequencer/module.go +++ b/x/sequencer/module.go @@ -98,7 +98,7 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { type AppModule struct { AppModuleBasic - keeper keeper.Keeper + keeper *keeper.Keeper accountKeeper types.AccountKeeper bankKeeper types.BankKeeper @@ -108,7 +108,7 @@ type AppModule struct { func NewAppModule( cdc codec.Codec, - keeper keeper.Keeper, + keeper *keeper.Keeper, accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, ss Subspace, @@ -141,7 +141,7 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { // RegisterInvariants registers the module's invariants. func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) { - keeper.RegisterInvariants(ir, am.keeper) + keeper.RegisterInvariants(ir, *am.keeper) } // InitGenesis performs the capability module's genesis initialization It returns @@ -166,19 +166,16 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw func (AppModule) ConsensusVersion() uint64 { return 3 } // BeginBlock executes all ABCI BeginBlock logic respective to the capability module. -func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} +func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { + // Must be in begin block to make sure successor is set before allowing last block from proposer + err := am.keeper.ChooseSuccessorForFinishedNotices(ctx, ctx.BlockTime()) + if err != nil { + ctx.Logger().Error("ChooseNewProposerForFinishedNoticePeriods", "err", err) + } +} // EndBlock executes all ABCI EndBlock logic respective to the capability module. It // returns no validator updates. func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { - // start unbonding period for sequencers after notice period - am.keeper.MatureSequencersWithNoticePeriod(ctx, ctx.BlockTime()) - - // Unbond all mature sequencers - am.keeper.UnbondAllMatureSequencers(ctx, ctx.BlockTime()) - - // Handle bond reduction - am.keeper.HandleBondReduction(ctx, ctx.BlockTime()) - return []abci.ValidatorUpdate{} } diff --git a/x/sequencer/types/codec.go b/x/sequencer/types/codec.go index 5aa71aff5..af522c4ea 100644 --- a/x/sequencer/types/codec.go +++ b/x/sequencer/types/codec.go @@ -14,6 +14,8 @@ func RegisterCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgDecreaseBond{}, "sequencer/DecreaseBond", nil) cdc.RegisterConcrete(&MsgUpdateRewardAddress{}, "sequencer/UpdateRewardAddress", nil) cdc.RegisterConcrete(&MsgUpdateWhitelistedRelayers{}, "sequencer/UpdateWhitelistedRelayers", nil) + cdc.RegisterConcrete(&MsgKickProposer{}, "sequencer/KickProposer", nil) + cdc.RegisterConcrete(&MsgUpdateOptInStatus{}, "sequencer/UpdateOtpInStatus", nil) } func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { @@ -22,6 +24,8 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { &MsgDecreaseBond{}, &MsgUnbond{}, &MsgIncreaseBond{}, + &MsgKickProposer{}, + &MsgUpdateOptInStatus{}, &MsgUpdateRewardAddress{}, &MsgUpdateWhitelistedRelayers{}, ) @@ -30,6 +34,7 @@ func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { } var ( - Amino = codec.NewLegacyAmino() - ModuleCdc = codec.NewProtoCodec(cdctypes.NewInterfaceRegistry()) + Amino = codec.NewLegacyAmino() + InterfaceReg = cdctypes.NewInterfaceRegistry() + ModuleCdc = codec.NewProtoCodec(InterfaceReg) ) diff --git a/x/sequencer/types/errors.go b/x/sequencer/types/errors.go index fc900f3e1..672a6f8da 100644 --- a/x/sequencer/types/errors.go +++ b/x/sequencer/types/errors.go @@ -7,30 +7,22 @@ import ( "github.com/dymensionxyz/gerr-cosmos/gerrc" ) -// x/sequencer module sentinel errors var ( - ErrSequencerExists = errorsmod.Register(ModuleName, 1000, "sequencer already exist for this address; must use new sequencer address") - ErrUnknownRollappID = errorsmod.Register(ModuleName, 1002, "rollapp does not exist") - ErrUnknownSequencer = errorsmod.Register(ModuleName, 1005, "sequencer was not registered") - ErrSequencerRollappMismatch = errorsmod.Register(ModuleName, 1006, "sequencer was not registered for this rollapp") - ErrNotActiveSequencer = errorsmod.Register(ModuleName, 1007, "sequencer is not active") - ErrInvalidSequencerStatus = errorsmod.Register(ModuleName, 1008, "invalid sequencer status") - ErrInvalidCoinDenom = errorsmod.Register(ModuleName, 1010, "invalid coin denomination") - ErrInsufficientBond = errorsmod.Register(ModuleName, 1011, "insufficient bond") - ErrRollappFrozen = errorsmod.Register(ModuleName, 1012, "rollapp is frozen") - ErrInvalidAddress = errorsmod.Register(ModuleName, 1013, "invalid address") - ErrInvalidPubKey = errorsmod.Register(ModuleName, 1014, "invalid pubkey") - ErrInvalidCoins = errorsmod.Register(ModuleName, 1015, "invalid coins") - ErrInvalidType = errorsmod.Register(ModuleName, 1016, "invalid type") - ErrUnknownRequest = errorsmod.Register(ModuleName, 1017, "unknown request") - ErrInvalidRequest = errorsmod.Register(ModuleName, 1018, "invalid request") - ErrSequencerJailed = errorsmod.Register(ModuleName, 1019, "sequencer is jailed") - ErrRotationInProgress = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "sequencer rotation in progress") - ErrBeforePreLaunchTime = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "before pre-launch time") - ErrNoProposer = errorsmod.Wrap(gerrc.ErrNotFound, "proposer") - ErrNotInitialSequencer = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "not the initial sequencer") - ErrInvalidURL = errorsmod.Wrap(gerrc.ErrInvalidArgument, "invalid url") - ErrInvalidMetadata = errorsmod.Wrap(gerrc.ErrInvalidArgument, "invalid metadata") - ErrInvalidVMTypeUpdate = errorsmod.Wrap(gerrc.ErrInvalidArgument, "invalid vm type update") - ErrUnknownBondReduction = errorsmod.Wrap(gerrc.ErrNotFound, "unknown bond reduction") + ErrInvalidURL = errorsmod.Wrap(gerrc.ErrInvalidArgument, "url") + ErrInvalidMetadata = errorsmod.Wrap(gerrc.ErrInvalidArgument, "metadata") + ErrInvalidVMTypeUpdate = errorsmod.Wrap(gerrc.ErrInvalidArgument, "vm type update") + ErrBeforePreLaunchTime = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "before pre-launch time") + ErrNotProposer = gerrc.ErrInvalidArgument.Wrap("sequencer is not proposer") + ErrSequencerAlreadyExists = gerrc.ErrAlreadyExists.Wrap("sequencer") + ErrSequencerNotFound = gerrc.ErrNotFound.Wrap("sequencer") + ErrUnbondNotAllowed = gerrc.ErrFailedPrecondition.Wrap("unbond not allowed") + ErrUnbondProposerOrSuccessor = errorsmod.Wrap(ErrUnbondNotAllowed, "proposer or successor") + ErrInvalidCoins = gerrc.ErrInvalidArgument.Wrap("coin or coins") + ErrInvalidDenom = errorsmod.Wrap(ErrInvalidCoins, "denom") + ErrInvalidCoinAmount = errorsmod.Wrap(ErrInvalidCoins, "amount") + ErrInsufficientBond = gerrc.ErrOutOfRange.Wrap("bond") + ErrRegisterSequencerWhileAwaitingLastProposerBlock = gerrc.ErrFailedPrecondition.Wrap("register sequencer while awaiting last proposer block") + ErrNotInitialSequencer = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "not the initial sequencer") + ErrInvalidAddr = gerrc.ErrInvalidArgument.Wrap("address") + ErrInvalidPubKey = gerrc.ErrInvalidArgument.Wrap("pubkey") ) diff --git a/x/sequencer/types/events.go b/x/sequencer/types/events.go index 18f5d5472..5b1854ac4 100644 --- a/x/sequencer/types/events.go +++ b/x/sequencer/types/events.go @@ -32,18 +32,11 @@ const ( // - AttributeKeyCompletionTime EventTypeNoticePeriodStarted = "notice_period_started" - // EventTypeUnbonding is emitted when a sequencer is unbonding - EventTypeUnbonding = "unbonding" - // EventTypeUnbonded is emitted when a sequencer is unbonded EventTypeUnbonded = "unbonded" // EventTypeSlashed is emitted when a sequencer is slashed EventTypeSlashed = "slashed" - // EventTypeJailed is emitted when a sequencer is jailed - EventTypeJailed = "jailed" - // EventTypeBondIncreased is emitted when a sequencer's bond is increased - EventTypeBondIncreased = "bond_increased" AttributeKeyRollappId = "rollapp_id" AttributeKeySequencer = "sequencer" @@ -53,4 +46,6 @@ const ( AttributeKeyRewardAddr = "reward_addr" AttributeKeyWhitelistedRelayers = "whitelisted_relayers" AttributeKeyCompletionTime = "completion_time" + AttributeKeyAmt = "amt" + AttributeKeyRemainingAmt = "remaining_amt" ) diff --git a/x/sequencer/types/events.pb.go b/x/sequencer/types/events.pb.go index 571ee128b..355fefdbc 100644 --- a/x/sequencer/types/events.pb.go +++ b/x/sequencer/types/events.pb.go @@ -28,7 +28,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // EventIncreasedBond is an event emitted when a sequencer's bond is increased. type EventIncreasedBond struct { - // sequencer is the bech32-encoded address of the sequencer which increased its bond + // sequencer is the bech32-encoded address of the sequencer Sequencer string `protobuf:"bytes,1,opt,name=sequencer,proto3" json:"sequencer,omitempty"` // added_amount is the amount of coins added to the sequencer's bond AddedAmount types.Coin `protobuf:"bytes,2,opt,name=added_amount,json=addedAmount,proto3" json:"added_amount"` @@ -198,10 +198,209 @@ func (m *EventUpdateWhitelistedRelayers) GetRelayers() []string { return nil } +// On a sequencer kicking the incumbent proposer +type EventKickedProposer struct { + Rollapp string `protobuf:"bytes,3,opt,name=rollapp,proto3" json:"rollapp,omitempty"` + // Kicker is the bech32-encoded address of the sequencer who triggered the kick + Kicker string `protobuf:"bytes,1,opt,name=kicker,proto3" json:"kicker,omitempty"` + // Proposer is the bech32-encoded address of the proposer who was kicked + Proposer string `protobuf:"bytes,2,opt,name=proposer,proto3" json:"proposer,omitempty"` +} + +func (m *EventKickedProposer) Reset() { *m = EventKickedProposer{} } +func (m *EventKickedProposer) String() string { return proto.CompactTextString(m) } +func (*EventKickedProposer) ProtoMessage() {} +func (*EventKickedProposer) Descriptor() ([]byte, []int) { + return fileDescriptor_1f8a63d7e7167eb3, []int{3} +} +func (m *EventKickedProposer) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventKickedProposer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventKickedProposer.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 *EventKickedProposer) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventKickedProposer.Merge(m, src) +} +func (m *EventKickedProposer) XXX_Size() int { + return m.Size() +} +func (m *EventKickedProposer) XXX_DiscardUnknown() { + xxx_messageInfo_EventKickedProposer.DiscardUnknown(m) +} + +var xxx_messageInfo_EventKickedProposer proto.InternalMessageInfo + +func (m *EventKickedProposer) GetRollapp() string { + if m != nil { + return m.Rollapp + } + return "" +} + +func (m *EventKickedProposer) GetKicker() string { + if m != nil { + return m.Kicker + } + return "" +} + +func (m *EventKickedProposer) GetProposer() string { + if m != nil { + return m.Proposer + } + return "" +} + +// Whenever the proposer changes to a new proposer +type EventProposerChange struct { + Rollapp string `protobuf:"bytes,3,opt,name=rollapp,proto3" json:"rollapp,omitempty"` + // Before is the bech32-encoded address of the old proposer + Before string `protobuf:"bytes,1,opt,name=before,proto3" json:"before,omitempty"` + // After is the bech32-encoded address of the new proposer + After string `protobuf:"bytes,2,opt,name=after,proto3" json:"after,omitempty"` +} + +func (m *EventProposerChange) Reset() { *m = EventProposerChange{} } +func (m *EventProposerChange) String() string { return proto.CompactTextString(m) } +func (*EventProposerChange) ProtoMessage() {} +func (*EventProposerChange) Descriptor() ([]byte, []int) { + return fileDescriptor_1f8a63d7e7167eb3, []int{4} +} +func (m *EventProposerChange) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventProposerChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventProposerChange.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 *EventProposerChange) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventProposerChange.Merge(m, src) +} +func (m *EventProposerChange) XXX_Size() int { + return m.Size() +} +func (m *EventProposerChange) XXX_DiscardUnknown() { + xxx_messageInfo_EventProposerChange.DiscardUnknown(m) +} + +var xxx_messageInfo_EventProposerChange proto.InternalMessageInfo + +func (m *EventProposerChange) GetRollapp() string { + if m != nil { + return m.Rollapp + } + return "" +} + +func (m *EventProposerChange) GetBefore() string { + if m != nil { + return m.Before + } + return "" +} + +func (m *EventProposerChange) GetAfter() string { + if m != nil { + return m.After + } + return "" +} + +// When a sequencer opt-in status changes +type EventOptInStatusChange struct { + Rollapp string `protobuf:"bytes,3,opt,name=rollapp,proto3" json:"rollapp,omitempty"` + // Sequencer is the bech32-encoded address of the old proposer + Sequencer string `protobuf:"bytes,1,opt,name=sequencer,proto3" json:"sequencer,omitempty"` + Before bool `protobuf:"varint,2,opt,name=before,proto3" json:"before,omitempty"` + After bool `protobuf:"varint,4,opt,name=after,proto3" json:"after,omitempty"` +} + +func (m *EventOptInStatusChange) Reset() { *m = EventOptInStatusChange{} } +func (m *EventOptInStatusChange) String() string { return proto.CompactTextString(m) } +func (*EventOptInStatusChange) ProtoMessage() {} +func (*EventOptInStatusChange) Descriptor() ([]byte, []int) { + return fileDescriptor_1f8a63d7e7167eb3, []int{5} +} +func (m *EventOptInStatusChange) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *EventOptInStatusChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_EventOptInStatusChange.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 *EventOptInStatusChange) XXX_Merge(src proto.Message) { + xxx_messageInfo_EventOptInStatusChange.Merge(m, src) +} +func (m *EventOptInStatusChange) XXX_Size() int { + return m.Size() +} +func (m *EventOptInStatusChange) XXX_DiscardUnknown() { + xxx_messageInfo_EventOptInStatusChange.DiscardUnknown(m) +} + +var xxx_messageInfo_EventOptInStatusChange proto.InternalMessageInfo + +func (m *EventOptInStatusChange) GetRollapp() string { + if m != nil { + return m.Rollapp + } + return "" +} + +func (m *EventOptInStatusChange) GetSequencer() string { + if m != nil { + return m.Sequencer + } + return "" +} + +func (m *EventOptInStatusChange) GetBefore() bool { + if m != nil { + return m.Before + } + return false +} + +func (m *EventOptInStatusChange) GetAfter() bool { + if m != nil { + return m.After + } + return false +} + func init() { proto.RegisterType((*EventIncreasedBond)(nil), "dymensionxyz.dymension.sequencer.EventIncreasedBond") proto.RegisterType((*EventUpdateRewardAddress)(nil), "dymensionxyz.dymension.sequencer.EventUpdateRewardAddress") proto.RegisterType((*EventUpdateWhitelistedRelayers)(nil), "dymensionxyz.dymension.sequencer.EventUpdateWhitelistedRelayers") + proto.RegisterType((*EventKickedProposer)(nil), "dymensionxyz.dymension.sequencer.EventKickedProposer") + proto.RegisterType((*EventProposerChange)(nil), "dymensionxyz.dymension.sequencer.EventProposerChange") + proto.RegisterType((*EventOptInStatusChange)(nil), "dymensionxyz.dymension.sequencer.EventOptInStatusChange") } func init() { @@ -209,33 +408,41 @@ func init() { } var fileDescriptor_1f8a63d7e7167eb3 = []byte{ - // 409 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0xb1, 0x8e, 0xd3, 0x30, - 0x18, 0xc7, 0x93, 0xeb, 0x09, 0x88, 0xcb, 0x14, 0xdd, 0x90, 0xeb, 0xe0, 0x46, 0x9d, 0xb2, 0x34, - 0xe6, 0x38, 0xe9, 0xf6, 0x0b, 0x62, 0x60, 0x43, 0x46, 0x07, 0x12, 0x4b, 0xe4, 0xc4, 0x9f, 0x72, - 0x11, 0x17, 0xbb, 0xd8, 0x6e, 0xb9, 0xf0, 0x14, 0x3c, 0x07, 0x33, 0x0f, 0xd1, 0xb1, 0x62, 0x62, - 0x02, 0xd4, 0x3e, 0x01, 0x6f, 0x80, 0xe2, 0x98, 0x90, 0xe5, 0x3a, 0x25, 0x7f, 0xe7, 0xff, 0xfb, - 0xfc, 0xfd, 0xbf, 0x7c, 0x68, 0xc9, 0xdb, 0x06, 0x84, 0xae, 0xa5, 0xb8, 0x6f, 0x3f, 0x93, 0x41, - 0x10, 0x0d, 0x1f, 0xd7, 0x20, 0x4a, 0x50, 0x04, 0x36, 0x20, 0x8c, 0x4e, 0x57, 0x4a, 0x1a, 0x19, - 0xc6, 0x63, 0x7b, 0x3a, 0x88, 0x74, 0xb0, 0xcf, 0xce, 0x4b, 0xa9, 0x1b, 0xa9, 0x73, 0xeb, 0x27, - 0xbd, 0xe8, 0xe1, 0xd9, 0x59, 0x25, 0x2b, 0xd9, 0x9f, 0x77, 0x6f, 0xee, 0x14, 0xf7, 0x1e, 0x52, - 0x30, 0x0d, 0x64, 0x73, 0x51, 0x80, 0x61, 0x17, 0xa4, 0x94, 0xb5, 0xe8, 0xbf, 0x2f, 0xfe, 0xf8, - 0x28, 0x7c, 0xd9, 0xf5, 0xf0, 0x4a, 0x94, 0x0a, 0x98, 0x06, 0x9e, 0x49, 0xc1, 0xc3, 0x2b, 0x14, - 0x0c, 0x97, 0x46, 0x7e, 0xec, 0x27, 0x41, 0x16, 0x7d, 0xff, 0xb6, 0x3c, 0x73, 0x37, 0x5e, 0x73, - 0xae, 0x40, 0xeb, 0x37, 0x46, 0xd5, 0xa2, 0xa2, 0xff, 0xad, 0x61, 0x86, 0x9e, 0x32, 0xce, 0x81, - 0xe7, 0xac, 0x91, 0x6b, 0x61, 0xa2, 0x93, 0xd8, 0x4f, 0xa6, 0xcf, 0xcf, 0x53, 0xc7, 0x75, 0x5d, - 0xa4, 0xae, 0x8b, 0xf4, 0x85, 0xac, 0x45, 0x76, 0xba, 0xfd, 0x39, 0xf7, 0xe8, 0xd4, 0x42, 0xd7, - 0x96, 0x09, 0x73, 0x74, 0x5a, 0x48, 0xc1, 0xa3, 0x49, 0x3c, 0x39, 0xce, 0x3e, 0xeb, 0xd8, 0xaf, - 0xbf, 0xe6, 0x49, 0x55, 0x9b, 0xdb, 0x75, 0x91, 0x96, 0xb2, 0x71, 0x23, 0x71, 0x8f, 0xa5, 0xe6, - 0x1f, 0x88, 0x69, 0x57, 0xa0, 0x2d, 0xa0, 0xa9, 0x2d, 0xbc, 0xb8, 0x41, 0x91, 0x8d, 0x7c, 0xb3, - 0xe2, 0xcc, 0x00, 0x85, 0x4f, 0x4c, 0x71, 0x97, 0x28, 0x8c, 0xd0, 0xe3, 0x6e, 0x0e, 0x46, 0xba, - 0xd8, 0xf4, 0x9f, 0x0c, 0xe7, 0x68, 0xaa, 0xac, 0x35, 0x67, 0x9c, 0x2b, 0x9b, 0x2c, 0xa0, 0x48, - 0x0d, 0xf4, 0xe2, 0x2d, 0xc2, 0xa3, 0xb2, 0xef, 0x6e, 0x6b, 0x03, 0x77, 0xb5, 0x36, 0xc0, 0x29, - 0xdc, 0xb1, 0x16, 0xd4, 0xb1, 0xe2, 0x33, 0xf4, 0x44, 0x39, 0x57, 0x74, 0x12, 0x4f, 0x92, 0x80, - 0x0e, 0x3a, 0x7b, 0xbd, 0xdd, 0x63, 0x7f, 0xb7, 0xc7, 0xfe, 0xef, 0x3d, 0xf6, 0xbf, 0x1c, 0xb0, - 0xb7, 0x3b, 0x60, 0xef, 0xc7, 0x01, 0x7b, 0xef, 0xaf, 0x46, 0xc1, 0x1f, 0xd8, 0xb4, 0xcd, 0x25, - 0xb9, 0x1f, 0xad, 0x9b, 0x1d, 0x46, 0xf1, 0xc8, 0xfe, 0xfb, 0xcb, 0xbf, 0x01, 0x00, 0x00, 0xff, - 0xff, 0xe1, 0x33, 0x1f, 0x07, 0x9f, 0x02, 0x00, 0x00, + // 531 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xc1, 0x6e, 0xd3, 0x30, + 0x1c, 0xc6, 0x9b, 0xb5, 0x8c, 0xd6, 0xe5, 0x64, 0xaa, 0x29, 0xeb, 0x21, 0xad, 0x72, 0xea, 0xa5, + 0xc9, 0xc6, 0xd0, 0xee, 0xeb, 0xc4, 0x61, 0xe2, 0xc0, 0x94, 0x69, 0x20, 0x71, 0xa9, 0x9c, 0xf8, + 0xbf, 0x34, 0x6a, 0x6b, 0x07, 0xdb, 0x2d, 0x2b, 0x4f, 0x01, 0x27, 0x78, 0x06, 0xce, 0x3c, 0xc4, + 0x8e, 0x13, 0x27, 0x4e, 0x80, 0xda, 0x27, 0xe0, 0x0d, 0x50, 0x6c, 0x37, 0xf4, 0x42, 0x8b, 0x38, + 0xb5, 0x9f, 0xfb, 0x7d, 0x5f, 0x7e, 0x7f, 0xd7, 0x31, 0xea, 0xd3, 0xc5, 0x14, 0x98, 0xcc, 0x38, + 0xbb, 0x5d, 0xbc, 0x0b, 0x4b, 0x11, 0x4a, 0x78, 0x33, 0x03, 0x96, 0x80, 0x08, 0x61, 0x0e, 0x4c, + 0xc9, 0x20, 0x17, 0x5c, 0x71, 0xdc, 0xdd, 0xb4, 0x07, 0xa5, 0x08, 0x4a, 0x7b, 0xfb, 0x30, 0xe1, + 0x72, 0xca, 0xe5, 0x50, 0xfb, 0x43, 0x23, 0x4c, 0xb8, 0xdd, 0x4a, 0x79, 0xca, 0xcd, 0x7a, 0xf1, + 0xcd, 0xae, 0x7a, 0xc6, 0x13, 0xc6, 0x44, 0x42, 0x38, 0x3f, 0x8e, 0x41, 0x91, 0xe3, 0x30, 0xe1, + 0x19, 0x33, 0xbf, 0xfb, 0xbf, 0x1c, 0x84, 0x9f, 0x15, 0x0c, 0x17, 0x2c, 0x11, 0x40, 0x24, 0xd0, + 0x01, 0x67, 0x14, 0x9f, 0xa2, 0x46, 0xf9, 0x50, 0xd7, 0xe9, 0x3a, 0xbd, 0xc6, 0xc0, 0xfd, 0xfa, + 0xa5, 0xdf, 0xb2, 0x4f, 0x3c, 0xa3, 0x54, 0x80, 0x94, 0x57, 0x4a, 0x64, 0x2c, 0x8d, 0xfe, 0x58, + 0xf1, 0x00, 0x3d, 0x22, 0x94, 0x02, 0x1d, 0x92, 0x29, 0x9f, 0x31, 0xe5, 0xee, 0x75, 0x9d, 0x5e, + 0xf3, 0xc9, 0x61, 0x60, 0x73, 0x05, 0x45, 0x60, 0x29, 0x82, 0x73, 0x9e, 0xb1, 0x41, 0xed, 0xee, + 0x7b, 0xa7, 0x12, 0x35, 0x75, 0xe8, 0x4c, 0x67, 0xf0, 0x10, 0xd5, 0x62, 0xce, 0xa8, 0x5b, 0xed, + 0x56, 0xb7, 0x67, 0x8f, 0x8a, 0xec, 0xe7, 0x1f, 0x9d, 0x5e, 0x9a, 0xa9, 0xd1, 0x2c, 0x0e, 0x12, + 0x3e, 0xb5, 0x5b, 0x62, 0x3f, 0xfa, 0x92, 0x8e, 0x43, 0xb5, 0xc8, 0x41, 0xea, 0x80, 0x8c, 0x74, + 0xb1, 0x7f, 0x8d, 0x5c, 0x3d, 0xf2, 0x75, 0x4e, 0x89, 0x82, 0x08, 0xde, 0x12, 0x41, 0xed, 0x44, + 0xd8, 0x45, 0x0f, 0x8b, 0x7d, 0x50, 0xdc, 0x8e, 0x1d, 0xad, 0x25, 0xee, 0xa0, 0xa6, 0xd0, 0xd6, + 0x21, 0xa1, 0x54, 0xe8, 0xc9, 0x1a, 0x11, 0x12, 0x65, 0xda, 0x7f, 0x89, 0xbc, 0x8d, 0xda, 0x57, + 0xa3, 0x4c, 0xc1, 0x24, 0x93, 0x0a, 0x68, 0x04, 0x13, 0xb2, 0x00, 0xb1, 0xad, 0xbc, 0x8d, 0xea, + 0xc2, 0xba, 0xdc, 0xbd, 0x6e, 0xb5, 0xd7, 0x88, 0x4a, 0xed, 0x7f, 0x74, 0xd0, 0x63, 0x5d, 0xfc, + 0x3c, 0x4b, 0xc6, 0x40, 0x2f, 0x05, 0xcf, 0xb9, 0x04, 0x51, 0xb4, 0x09, 0x3e, 0x99, 0x90, 0x3c, + 0x77, 0xab, 0xa6, 0xcd, 0x4a, 0x7c, 0x84, 0xf6, 0xc7, 0x85, 0x77, 0xf7, 0x5f, 0x67, 0x7d, 0xf8, + 0x29, 0xaa, 0xe7, 0xb6, 0xd7, 0x4c, 0xb6, 0x25, 0x53, 0x3a, 0xfd, 0x0f, 0x6b, 0xb2, 0x35, 0xd3, + 0xf9, 0x88, 0xb0, 0x14, 0xb6, 0x93, 0xc5, 0x70, 0xc3, 0x05, 0xec, 0x26, 0x33, 0x3e, 0x1c, 0xa0, + 0x07, 0xe4, 0x46, 0xfd, 0x03, 0x96, 0xb1, 0xf9, 0x9f, 0x1c, 0x74, 0xa0, 0x99, 0x5e, 0xe4, 0xea, + 0x82, 0x5d, 0x29, 0xa2, 0x66, 0x72, 0x27, 0xd6, 0xff, 0x1e, 0xf7, 0x83, 0x72, 0x9c, 0x82, 0xae, + 0x5e, 0x42, 0xb7, 0xd6, 0xd0, 0x35, 0xbd, 0x6c, 0xc4, 0xe0, 0xf2, 0x6e, 0xe9, 0x39, 0xf7, 0x4b, + 0xcf, 0xf9, 0xb9, 0xf4, 0x9c, 0xf7, 0x2b, 0xaf, 0x72, 0xbf, 0xf2, 0x2a, 0xdf, 0x56, 0x5e, 0xe5, + 0xf5, 0xe9, 0xc6, 0x09, 0xfe, 0xcb, 0x95, 0x31, 0x3f, 0x09, 0x6f, 0x37, 0xee, 0x0d, 0x7d, 0xaa, + 0xe3, 0x7d, 0xfd, 0x12, 0x9f, 0xfc, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xed, 0xe5, 0x96, 0x73, 0x68, + 0x04, 0x00, 0x00, } func (m *EventIncreasedBond) Marshal() (dAtA []byte, err error) { @@ -368,6 +575,151 @@ func (m *EventUpdateWhitelistedRelayers) MarshalToSizedBuffer(dAtA []byte) (int, return len(dAtA) - i, nil } +func (m *EventKickedProposer) 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 *EventKickedProposer) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventKickedProposer) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Rollapp) > 0 { + i -= len(m.Rollapp) + copy(dAtA[i:], m.Rollapp) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Rollapp))) + i-- + dAtA[i] = 0x1a + } + if len(m.Proposer) > 0 { + i -= len(m.Proposer) + copy(dAtA[i:], m.Proposer) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Proposer))) + i-- + dAtA[i] = 0x12 + } + if len(m.Kicker) > 0 { + i -= len(m.Kicker) + copy(dAtA[i:], m.Kicker) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Kicker))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventProposerChange) 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 *EventProposerChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventProposerChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Rollapp) > 0 { + i -= len(m.Rollapp) + copy(dAtA[i:], m.Rollapp) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Rollapp))) + i-- + dAtA[i] = 0x1a + } + if len(m.After) > 0 { + i -= len(m.After) + copy(dAtA[i:], m.After) + i = encodeVarintEvents(dAtA, i, uint64(len(m.After))) + i-- + dAtA[i] = 0x12 + } + if len(m.Before) > 0 { + i -= len(m.Before) + copy(dAtA[i:], m.Before) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Before))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *EventOptInStatusChange) 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 *EventOptInStatusChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *EventOptInStatusChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.After { + i-- + if m.After { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if len(m.Rollapp) > 0 { + i -= len(m.Rollapp) + copy(dAtA[i:], m.Rollapp) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Rollapp))) + i-- + dAtA[i] = 0x1a + } + if m.Before { + i-- + if m.Before { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } + if len(m.Sequencer) > 0 { + i -= len(m.Sequencer) + copy(dAtA[i:], m.Sequencer) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Sequencer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintEvents(dAtA []byte, offset int, v uint64) int { offset -= sovEvents(v) base := offset @@ -414,35 +766,477 @@ func (m *EventUpdateRewardAddress) Size() (n int) { if l > 0 { n += 1 + l + sovEvents(uint64(l)) } - return n -} + return n +} + +func (m *EventUpdateWhitelistedRelayers) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + if len(m.Relayers) > 0 { + for _, s := range m.Relayers { + l = len(s) + n += 1 + l + sovEvents(uint64(l)) + } + } + return n +} + +func (m *EventKickedProposer) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Kicker) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = len(m.Proposer) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = len(m.Rollapp) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + return n +} + +func (m *EventProposerChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Before) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = len(m.After) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + l = len(m.Rollapp) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + return n +} + +func (m *EventOptInStatusChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Sequencer) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + if m.Before { + n += 2 + } + l = len(m.Rollapp) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } + if m.After { + n += 2 + } + return n +} + +func sovEvents(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozEvents(x uint64) (n int) { + return sovEvents(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *EventIncreasedBond) 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 ErrIntOverflowEvents + } + 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: EventIncreasedBond: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventIncreasedBond: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Sequencer", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + 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 ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Sequencer = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AddedAmount", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.AddedAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Bond", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Bond = append(m.Bond, types.Coin{}) + if err := m.Bond[len(m.Bond)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *EventUpdateRewardAddress) 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 ErrIntOverflowEvents + } + 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: EventUpdateRewardAddress: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventUpdateRewardAddress: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + 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 ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field RewardAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + 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 ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.RewardAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } -func (m *EventUpdateWhitelistedRelayers) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.Creator) - if l > 0 { - n += 1 + l + sovEvents(uint64(l)) + if iNdEx > l { + return io.ErrUnexpectedEOF } - if len(m.Relayers) > 0 { - for _, s := range m.Relayers { - l = len(s) - n += 1 + l + sovEvents(uint64(l)) + return nil +} +func (m *EventUpdateWhitelistedRelayers) 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 ErrIntOverflowEvents + } + 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: EventUpdateWhitelistedRelayers: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: EventUpdateWhitelistedRelayers: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + 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 ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Relayers", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + 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 ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Relayers = append(m.Relayers, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipEvents(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthEvents + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy } } - return n -} -func sovEvents(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozEvents(x uint64) (n int) { - return sovEvents(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil } -func (m *EventIncreasedBond) Unmarshal(dAtA []byte) error { +func (m *EventKickedProposer) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -465,15 +1259,15 @@ func (m *EventIncreasedBond) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: EventIncreasedBond: wiretype end group for non-group") + return fmt.Errorf("proto: EventKickedProposer: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: EventIncreasedBond: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: EventKickedProposer: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Sequencer", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Kicker", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -501,13 +1295,13 @@ func (m *EventIncreasedBond) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Sequencer = string(dAtA[iNdEx:postIndex]) + m.Kicker = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field AddedAmount", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Proposer", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -517,30 +1311,29 @@ func (m *EventIncreasedBond) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.AddedAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Proposer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Bond", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Rollapp", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowEvents @@ -550,25 +1343,23 @@ func (m *EventIncreasedBond) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthEvents } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthEvents } if postIndex > l { return io.ErrUnexpectedEOF } - m.Bond = append(m.Bond, types.Coin{}) - if err := m.Bond[len(m.Bond)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } + m.Rollapp = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -591,7 +1382,7 @@ func (m *EventIncreasedBond) Unmarshal(dAtA []byte) error { } return nil } -func (m *EventUpdateRewardAddress) Unmarshal(dAtA []byte) error { +func (m *EventProposerChange) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -614,15 +1405,15 @@ func (m *EventUpdateRewardAddress) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: EventUpdateRewardAddress: wiretype end group for non-group") + return fmt.Errorf("proto: EventProposerChange: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: EventUpdateRewardAddress: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: EventProposerChange: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Before", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -650,11 +1441,11 @@ func (m *EventUpdateRewardAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Creator = string(dAtA[iNdEx:postIndex]) + m.Before = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field RewardAddr", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field After", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -682,7 +1473,39 @@ func (m *EventUpdateRewardAddress) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.RewardAddr = string(dAtA[iNdEx:postIndex]) + m.After = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Rollapp", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + 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 ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Rollapp = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex @@ -705,7 +1528,7 @@ func (m *EventUpdateRewardAddress) Unmarshal(dAtA []byte) error { } return nil } -func (m *EventUpdateWhitelistedRelayers) Unmarshal(dAtA []byte) error { +func (m *EventOptInStatusChange) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -728,15 +1551,15 @@ func (m *EventUpdateWhitelistedRelayers) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: EventUpdateWhitelistedRelayers: wiretype end group for non-group") + return fmt.Errorf("proto: EventOptInStatusChange: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: EventUpdateWhitelistedRelayers: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: EventOptInStatusChange: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Sequencer", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -764,11 +1587,31 @@ func (m *EventUpdateWhitelistedRelayers) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Creator = string(dAtA[iNdEx:postIndex]) + m.Sequencer = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Before", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Before = bool(v != 0) + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Relayers", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Rollapp", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -796,8 +1639,28 @@ func (m *EventUpdateWhitelistedRelayers) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Relayers = append(m.Relayers, string(dAtA[iNdEx:postIndex])) + m.Rollapp = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field After", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.After = bool(v != 0) default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) diff --git a/x/sequencer/types/expected_keepers.go b/x/sequencer/types/expected_keepers.go index fdeaed14a..cf7047f26 100644 --- a/x/sequencer/types/expected_keepers.go +++ b/x/sequencer/types/expected_keepers.go @@ -14,11 +14,6 @@ type RollappKeeper interface { GetAllRollapps(ctx sdk.Context) (list []rollapptypes.Rollapp) SetRollappAsLaunched(ctx sdk.Context, rollapp *rollapptypes.Rollapp) error GetParams(ctx sdk.Context) rollapptypes.Params - - // FIXME: remove after merge (will have hooks) - SetStateInfo(ctx sdk.Context, stateInfo rollapptypes.StateInfo) - GetLatestStateInfo(ctx sdk.Context, rollappId string) (val rollapptypes.StateInfo, found bool) - GetStateInfo(ctx sdk.Context, rollappId string, index uint64) (val rollapptypes.StateInfo, found bool) } // AccountKeeper defines the expected account keeper used for simulations (noalias) diff --git a/x/sequencer/types/genesis.go b/x/sequencer/types/genesis.go index 53637dcb6..ea94cdb08 100644 --- a/x/sequencer/types/genesis.go +++ b/x/sequencer/types/genesis.go @@ -8,6 +8,7 @@ func DefaultGenesis() *GenesisState { SequencerList: []Sequencer{}, GenesisProposers: []GenesisProposer{}, Params: DefaultParams(), + NoticeQueue: []string{}, } } @@ -28,18 +29,33 @@ func (gs GenesisState) Validate() error { sequencerIndexMap[seqKey] = struct{}{} } - // Check for duplicated index in proposer + if err := checkSecondIndex(gs.GenesisProposers, sequencerIndexMap); err != nil { + return err + } + if err := checkSecondIndex(gs.GenesisSuccessors, sequencerIndexMap); err != nil { + return err + } + + for _, s := range gs.NoticeQueue { + if _, ok := sequencerIndexMap[s]; !ok { + return fmt.Errorf("notice queue contains non-existent sequencer") + } + } + + return gs.Params.ValidateBasic() +} + +func checkSecondIndex(seqs []GenesisProposer, sequencerIndexMap map[string]struct{}) error { proposerIndexMap := make(map[string]struct{}) - for _, elem := range gs.GenesisProposers { + for _, elem := range seqs { rollappId := elem.RollappId if _, ok := proposerIndexMap[rollappId]; ok { - return fmt.Errorf("duplicated proposer for %s", rollappId) + return fmt.Errorf("duplicated for %s", rollappId) } if _, ok := sequencerIndexMap[string(SequencerKey(elem.Address))]; !ok { - return fmt.Errorf("proposer %s does not have a sequencer", rollappId) + return fmt.Errorf("%s does not have a sequencer", rollappId) } proposerIndexMap[rollappId] = struct{}{} } - - return gs.Params.ValidateBasic() + return nil } diff --git a/x/sequencer/types/genesis.pb.go b/x/sequencer/types/genesis.pb.go index 437ebb004..7361368d6 100644 --- a/x/sequencer/types/genesis.pb.go +++ b/x/sequencer/types/genesis.pb.go @@ -30,8 +30,10 @@ type GenesisState struct { SequencerList []Sequencer `protobuf:"bytes,2,rep,name=sequencerList,proto3" json:"sequencerList"` // genesisProposers is a list of the defined genesis proposers GenesisProposers []GenesisProposer `protobuf:"bytes,3,rep,name=genesisProposers,proto3" json:"genesisProposers"` - // bondReductions is a list of all bond reductions - BondReductions []BondReduction `protobuf:"bytes,4,rep,name=bondReductions,proto3" json:"bondReductions"` + // genesisSuccessor is a list of the defined genesis proposers + GenesisSuccessors []GenesisProposer `protobuf:"bytes,5,rep,name=genesisSuccessors,proto3" json:"genesisSuccessors"` + // list of sequencers in the notice queue + NoticeQueue []string `protobuf:"bytes,4,rep,name=noticeQueue,proto3" json:"noticeQueue,omitempty"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -88,9 +90,16 @@ func (m *GenesisState) GetGenesisProposers() []GenesisProposer { return nil } -func (m *GenesisState) GetBondReductions() []BondReduction { +func (m *GenesisState) GetGenesisSuccessors() []GenesisProposer { if m != nil { - return m.BondReductions + return m.GenesisSuccessors + } + return nil +} + +func (m *GenesisState) GetNoticeQueue() []string { + if m != nil { + return m.NoticeQueue } return nil } @@ -157,29 +166,30 @@ func init() { } var fileDescriptor_3115db717b16c2af = []byte{ - // 343 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x4b, 0xa9, 0xcc, 0x4d, - 0xcd, 0x2b, 0xce, 0xcc, 0xcf, 0xab, 0xa8, 0xac, 0xd2, 0x87, 0x73, 0xf4, 0x8b, 0x53, 0x0b, 0x4b, - 0x53, 0xf3, 0x92, 0x53, 0x8b, 0xf4, 0xd3, 0x53, 0xf3, 0x52, 0x8b, 0x33, 0x8b, 0xf5, 0x0a, 0x8a, - 0xf2, 0x4b, 0xf2, 0x85, 0x14, 0x90, 0xd5, 0x23, 0x34, 0xeb, 0xc1, 0xd5, 0x4b, 0x89, 0xa4, 0xe7, - 0xa7, 0xe7, 0x83, 0x15, 0xeb, 0x83, 0x58, 0x10, 0x7d, 0x52, 0xba, 0x04, 0xed, 0x29, 0x48, 0x2c, - 0x4a, 0xcc, 0x85, 0x5a, 0x23, 0x65, 0x40, 0x50, 0x39, 0x9c, 0x05, 0xd1, 0xa1, 0xf4, 0x99, 0x89, - 0x8b, 0xc7, 0x1d, 0xe2, 0xd4, 0xe0, 0x92, 0xc4, 0x92, 0x54, 0x21, 0x37, 0x2e, 0x36, 0x88, 0x91, - 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0xdc, 0x46, 0x1a, 0x7a, 0x84, 0x9c, 0xae, 0x17, 0x00, 0x56, 0xef, - 0xc4, 0x72, 0xe2, 0x9e, 0x3c, 0x43, 0x10, 0x54, 0xb7, 0x50, 0x38, 0x17, 0x2f, 0x5c, 0x85, 0x4f, - 0x66, 0x71, 0x89, 0x04, 0x93, 0x02, 0xb3, 0x06, 0xb7, 0x91, 0x36, 0x61, 0xe3, 0x82, 0x61, 0x2c, - 0xa8, 0x89, 0xa8, 0xe6, 0x08, 0x25, 0x73, 0x09, 0x40, 0xc3, 0x36, 0xa0, 0x28, 0xbf, 0x20, 0xbf, - 0x38, 0xb5, 0xa8, 0x58, 0x82, 0x19, 0x6c, 0xb6, 0x21, 0x61, 0xb3, 0xdd, 0x51, 0x75, 0x42, 0x6d, - 0xc0, 0x30, 0x50, 0x28, 0x96, 0x8b, 0x2f, 0x29, 0x3f, 0x2f, 0x25, 0x28, 0x35, 0xa5, 0x34, 0xb9, - 0x24, 0x33, 0x3f, 0xaf, 0x58, 0x82, 0x05, 0x6c, 0x85, 0x3e, 0x61, 0x2b, 0x9c, 0x90, 0xf5, 0x41, - 0x2d, 0x40, 0x33, 0x4c, 0xc9, 0x93, 0x8b, 0x1f, 0xcd, 0x25, 0x42, 0x12, 0x5c, 0xec, 0x89, 0x29, - 0x29, 0x45, 0xa9, 0xc5, 0x90, 0x80, 0xe7, 0x0c, 0x82, 0x71, 0x85, 0x64, 0xb8, 0x38, 0x8b, 0xf2, - 0x73, 0x72, 0x12, 0x0b, 0x0a, 0x3c, 0x53, 0x24, 0x98, 0xc0, 0x72, 0x08, 0x01, 0xa7, 0x80, 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, 0x4b, 0xcf, 0x2c, 0xc9, 0x28, 0x4d, - 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0xc7, 0x91, 0x2e, 0xca, 0x8c, 0xf5, 0x2b, 0x90, 0x12, 0x47, 0x49, - 0x65, 0x41, 0x6a, 0x71, 0x12, 0x1b, 0x38, 0x65, 0x18, 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0x0d, - 0xdb, 0x09, 0xa8, 0xe4, 0x02, 0x00, 0x00, + // 357 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x92, 0xc1, 0x4e, 0xfa, 0x40, + 0x10, 0xc6, 0x5b, 0xca, 0x9f, 0x7f, 0x58, 0x34, 0xea, 0xc6, 0xc3, 0x86, 0x98, 0xda, 0x70, 0x30, + 0x4d, 0x8c, 0xad, 0x42, 0xe2, 0x03, 0x70, 0x90, 0x90, 0x78, 0x40, 0x38, 0x98, 0x78, 0x2b, 0xed, + 0xa4, 0x36, 0x81, 0xee, 0xba, 0xbb, 0x35, 0xe0, 0x53, 0xf8, 0x0e, 0xbe, 0x0c, 0x47, 0x8e, 0x9e, + 0x8c, 0x81, 0x17, 0x31, 0xb6, 0x4b, 0x01, 0x89, 0xe9, 0xc1, 0xdb, 0xec, 0xcc, 0xf7, 0xfd, 0xbe, + 0x49, 0x3b, 0xc8, 0x09, 0xa6, 0x63, 0x88, 0x45, 0x44, 0xe3, 0xc9, 0xf4, 0xc5, 0xcd, 0x1f, 0xae, + 0x80, 0xa7, 0x04, 0x62, 0x1f, 0xb8, 0x1b, 0x42, 0x0c, 0x22, 0x12, 0x0e, 0xe3, 0x54, 0x52, 0x6c, + 0x6d, 0xea, 0xd7, 0x66, 0x27, 0xd7, 0xd7, 0x8f, 0x43, 0x1a, 0xd2, 0x54, 0xec, 0x7e, 0x57, 0x99, + 0xaf, 0x7e, 0x51, 0x98, 0xc3, 0x3c, 0xee, 0x8d, 0x55, 0x4c, 0xfd, 0xb2, 0x50, 0x9e, 0x57, 0x99, + 0xa3, 0xf1, 0x66, 0xa0, 0xbd, 0x4e, 0xb6, 0xea, 0x40, 0x7a, 0x12, 0xf0, 0x0d, 0xaa, 0x64, 0x48, + 0xa2, 0x5b, 0xba, 0x5d, 0x6b, 0xda, 0x4e, 0xd1, 0xea, 0x4e, 0x2f, 0xd5, 0xb7, 0xcb, 0xb3, 0x8f, + 0x53, 0xad, 0xaf, 0xdc, 0xf8, 0x1e, 0xed, 0xe7, 0x8a, 0xdb, 0x48, 0x48, 0x52, 0xb2, 0x0c, 0xbb, + 0xd6, 0x3c, 0x2f, 0xc6, 0x0d, 0x56, 0x95, 0x22, 0x6e, 0x73, 0xb0, 0x8f, 0x0e, 0xd5, 0xb7, 0xed, + 0x71, 0xca, 0xa8, 0x00, 0x2e, 0x88, 0x91, 0xb2, 0xaf, 0x8a, 0xd9, 0x9d, 0x6d, 0xa7, 0x4a, 0xd8, + 0x01, 0x62, 0x40, 0x47, 0xaa, 0x37, 0x48, 0x7c, 0x1f, 0x84, 0xa0, 0x5c, 0x90, 0x7f, 0x7f, 0x4b, + 0xd9, 0x25, 0xe2, 0x33, 0x54, 0x8b, 0xa9, 0x8c, 0x7c, 0xb8, 0x4b, 0x20, 0x01, 0x52, 0xb6, 0x0c, + 0xbb, 0xaa, 0xd4, 0x9b, 0x83, 0x46, 0x17, 0x1d, 0xfc, 0x60, 0x62, 0x82, 0xfe, 0x7b, 0x41, 0xc0, + 0x41, 0x64, 0x3f, 0xaa, 0xda, 0x5f, 0x3d, 0xf1, 0x09, 0xaa, 0x72, 0x3a, 0x1a, 0x79, 0x8c, 0x75, + 0x03, 0x52, 0x4a, 0x67, 0xeb, 0x46, 0xbb, 0x37, 0x5b, 0x98, 0xfa, 0x7c, 0x61, 0xea, 0x9f, 0x0b, + 0x53, 0x7f, 0x5d, 0x9a, 0xda, 0x7c, 0x69, 0x6a, 0xef, 0x4b, 0x53, 0x7b, 0xb8, 0x0e, 0x23, 0xf9, + 0x98, 0x0c, 0x1d, 0x9f, 0x8e, 0xdd, 0x5f, 0xee, 0xe8, 0xb9, 0xe5, 0x4e, 0x36, 0x8e, 0x49, 0x4e, + 0x19, 0x88, 0x61, 0x25, 0xbd, 0xa4, 0xd6, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0x82, 0x86, 0x46, + 0xcd, 0x14, 0x03, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -202,10 +212,10 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.BondReductions) > 0 { - for iNdEx := len(m.BondReductions) - 1; iNdEx >= 0; iNdEx-- { + if len(m.GenesisSuccessors) > 0 { + for iNdEx := len(m.GenesisSuccessors) - 1; iNdEx >= 0; iNdEx-- { { - size, err := m.BondReductions[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + size, err := m.GenesisSuccessors[iNdEx].MarshalToSizedBuffer(dAtA[:i]) if err != nil { return 0, err } @@ -213,6 +223,15 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintGenesis(dAtA, i, uint64(size)) } i-- + dAtA[i] = 0x2a + } + } + if len(m.NoticeQueue) > 0 { + for iNdEx := len(m.NoticeQueue) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.NoticeQueue[iNdEx]) + copy(dAtA[i:], m.NoticeQueue[iNdEx]) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.NoticeQueue[iNdEx]))) + i-- dAtA[i] = 0x22 } } @@ -325,8 +344,14 @@ func (m *GenesisState) Size() (n int) { n += 1 + l + sovGenesis(uint64(l)) } } - if len(m.BondReductions) > 0 { - for _, e := range m.BondReductions { + if len(m.NoticeQueue) > 0 { + for _, s := range m.NoticeQueue { + l = len(s) + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.GenesisSuccessors) > 0 { + for _, e := range m.GenesisSuccessors { l = e.Size() n += 1 + l + sovGenesis(uint64(l)) } @@ -489,7 +514,39 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field BondReductions", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field NoticeQueue", 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.NoticeQueue = append(m.NoticeQueue, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field GenesisSuccessors", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -516,8 +573,8 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.BondReductions = append(m.BondReductions, BondReduction{}) - if err := m.BondReductions[len(m.BondReductions)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + m.GenesisSuccessors = append(m.GenesisSuccessors, GenesisProposer{}) + if err := m.GenesisSuccessors[len(m.GenesisSuccessors)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/sequencer/types/hooks.go b/x/sequencer/types/hooks.go new file mode 100644 index 000000000..7a139eb10 --- /dev/null +++ b/x/sequencer/types/hooks.go @@ -0,0 +1,38 @@ +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) +} + +var _ Hooks = NoOpHooks{} + +type NoOpHooks struct{} + +func (n NoOpHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, before, after Sequencer) { +} + +func (n NoOpHooks) AfterKickProposer(ctx sdk.Context, kicked Sequencer) { +} + +var _ Hooks = MultiHooks{} + +type MultiHooks []Hooks + +func NewMultiHooks(hooks ...Hooks) MultiHooks { + return MultiHooks(hooks) +} + +func (m MultiHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, before, after Sequencer) { + for _, h := range m { + h.AfterChooseNewProposer(ctx, rollapp, before, after) + } +} + +func (m MultiHooks) AfterKickProposer(ctx sdk.Context, kicked Sequencer) { + for _, h := range m { + h.AfterKickProposer(ctx, kicked) + } +} diff --git a/x/sequencer/types/keys.go b/x/sequencer/types/keys.go index 8a2ba711f..5de67a919 100644 --- a/x/sequencer/types/keys.go +++ b/x/sequencer/types/keys.go @@ -5,8 +5,7 @@ import ( fmt "fmt" "time" - sdk "github.com/cosmos/cosmos-sdk/types" - + "cosmossdk.io/collections" "github.com/dymensionxyz/dymension/v3/utils" ) @@ -48,20 +47,17 @@ var ( NextProposerKeyPrefix = []byte{0x03} // prefix/rollappId // Prefixes for the different sequencer statuses - BondedSequencersKeyPrefix = []byte{0xa1} - UnbondedSequencersKeyPrefix = []byte{0xa2} - UnbondingSequencersKeyPrefix = []byte{0xa3} - UnbondingQueueKey = []byte{0x41} // prefix for the timestamps in unbonding queue + BondedSequencersKeyPrefix = []byte{0xa1} + UnbondedSequencersKeyPrefix = []byte{0xa2} + NoticePeriodQueueKey = []byte{0x42} // prefix for the timestamps in notice period queue - DecreasingBondQueueKey = []byte{0x43} // prefix for the timestamps in decreasing bond queue - DecreasingBondIndexKey = []byte{0x44} // prefix for the index count for bond reductions - DecreasingBondSequencerKey = []byte{0x45} // prefix for the decreasing bond queue by sequencer - DecreasingBondIDKey = []byte{0x46} // prefix for the decreasing bond count - used to generate ID + DymintProposerAddrToAccAddrKeyPrefix = collections.NewPrefix([]byte{0x43}) ) /* --------------------- specific sequencer address keys -------------------- */ + func SequencerKey(sequencerAddress string) []byte { sequencerAddrBytes := []byte(sequencerAddress) return []byte(fmt.Sprintf("%s%s%s", SequencersKeyPrefix, KeySeparator, sequencerAddrBytes)) @@ -73,6 +69,7 @@ func SequencerByRollappByStatusKey(rollappId, seqAddr string, status OperatingSt } /* ------------------------- multiple sequencers keys ------------------------ */ + func SequencersKey() []byte { return SequencersKeyPrefix } @@ -92,8 +89,6 @@ func SequencersByRollappByStatusKey(rollappId string, status OperatingStatus) [] prefix = BondedSequencersKeyPrefix case Unbonded: prefix = UnbondedSequencersKeyPrefix - case Unbonding: - prefix = UnbondingSequencersKeyPrefix } return []byte(fmt.Sprintf("%s%s%s", SequencersByRollappKey(rollappId), KeySeparator, prefix)) @@ -101,64 +96,23 @@ func SequencersByRollappByStatusKey(rollappId string, status OperatingStatus) [] /* -------------------------- queues keys -------------------------- */ -func UnbondingQueueByTimeKey(endTime time.Time) []byte { - return utils.EncodeTimeToKey(UnbondingQueueKey, endTime) -} - -func NoticePeriodQueueByTimeKey(endTime time.Time) []byte { +func NoticeQueueByTimeKey(endTime time.Time) []byte { return utils.EncodeTimeToKey(NoticePeriodQueueKey, endTime) } -func UnbondingSequencerKey(sequencerAddress string, endTime time.Time) []byte { - key := UnbondingQueueByTimeKey(endTime) +func NoticeQueueBySeqTimeKey(sequencerAddress string, endTime time.Time) []byte { + key := NoticeQueueByTimeKey(endTime) key = append(key, KeySeparator...) key = append(key, []byte(sequencerAddress)...) return key } -func NoticePeriodSequencerKey(sequencerAddress string, endTime time.Time) []byte { - key := NoticePeriodQueueByTimeKey(endTime) - key = append(key, KeySeparator...) - key = append(key, []byte(sequencerAddress)...) - return key -} - -/* -------------------------- decreasing bond queue keys -------------------------- */ -func DecreasingBondQueueByTimeKey(endTime time.Time) []byte { - return utils.EncodeTimeToKey(DecreasingBondQueueKey, endTime) -} - -func GetDecreasingBondQueueKey(sequencerAddress string, endTime time.Time) []byte { - key := DecreasingBondQueueByTimeKey(endTime) - key = append(key, KeySeparator...) - key = append(key, []byte(sequencerAddress)...) - return key -} - -func GetDecreasingBondIndexKey(bondReductionID uint64) []byte { - key := DecreasingBondIndexKey - key = append(key, KeySeparator...) - key = append(key, sdk.Uint64ToBigEndian(bondReductionID)...) - return key -} - -func GetDecreasingBondIDKey() []byte { - return DecreasingBondIDKey -} - -func GetDecreasingBondSequencerKey(sequencerAddress string) []byte { - key := DecreasingBondSequencerKey - key = append(key, KeySeparator...) - key = append(key, []byte(sequencerAddress)...) - key = append(key, KeySeparator...) - return key -} +/* --------------------- proposer and successor keys --------------------- */ -/* --------------------- active and next sequencer keys --------------------- */ func ProposerByRollappKey(rollappId string) []byte { return []byte(fmt.Sprintf("%s%s%s", ProposerKeyPrefix, KeySeparator, []byte(rollappId))) } -func NextProposerByRollappKey(rollappId string) []byte { +func SuccessorByRollappKey(rollappId string) []byte { return []byte(fmt.Sprintf("%s%s%s", NextProposerKeyPrefix, KeySeparator, []byte(rollappId))) } diff --git a/x/sequencer/types/metadata.go b/x/sequencer/types/metadata.go index 3b9decbab..7f0c63eb4 100644 --- a/x/sequencer/types/metadata.go +++ b/x/sequencer/types/metadata.go @@ -6,6 +6,7 @@ import ( errorsmod "cosmossdk.io/errors" "github.com/cockroachdb/errors" + "github.com/dymensionxyz/gerr-cosmos/gerrc" ) // constant for maximum string length of the SequencerMetadata fields @@ -64,7 +65,7 @@ func (cd ContactDetails) Validate() error { // ValidateURLs validates the URLs of a sequencer's metadata. func validateURLs(urls []string) error { if len(urls) == 0 { - return errorsmod.Wrap(ErrInvalidRequest, "urls cannot be empty") + return errorsmod.Wrap(gerrc.ErrInvalidArgument, "urls cannot be empty") } for _, u := range urls { @@ -78,7 +79,7 @@ func validateURLs(urls []string) error { func validateURL(urlStr string) error { if urlStr == "" { - return errorsmod.Wrap(ErrInvalidRequest, "url cannot be empty") + return errorsmod.Wrap(gerrc.ErrInvalidArgument, "url cannot be empty") } if len(urlStr) > maxURLLength { diff --git a/x/sequencer/types/msg_bond_change.go b/x/sequencer/types/msg_bond.go similarity index 68% rename from x/sequencer/types/msg_bond_change.go rename to x/sequencer/types/msg_bond.go index e02d05c63..62f8e7651 100644 --- a/x/sequencer/types/msg_bond_change.go +++ b/x/sequencer/types/msg_bond.go @@ -10,7 +10,6 @@ var ( _ sdk.Msg = &MsgDecreaseBond{} ) -/* ---------------------------- MsgIncreaseBond ---------------------------- */ func NewMsgIncreaseBond(creator string, addAmount sdk.Coin) *MsgIncreaseBond { return &MsgIncreaseBond{ Creator: creator, @@ -21,7 +20,7 @@ func NewMsgIncreaseBond(creator string, addAmount sdk.Coin) *MsgIncreaseBond { func (msg *MsgIncreaseBond) ValidateBasic() error { _, err := sdk.AccAddressFromBech32(msg.Creator) if err != nil { - return errorsmod.Wrapf(ErrInvalidAddress, "invalid creator address (%s)", err) + return errorsmod.Wrapf(ErrInvalidAddr, "invalid creator address (%s)", err) } if !(msg.AddAmount.IsValid() && msg.AddAmount.IsPositive()) { @@ -39,7 +38,6 @@ func (msg *MsgIncreaseBond) GetSigners() []sdk.AccAddress { return []sdk.AccAddress{creator} } -/* ---------------------------- MsgDecreaseBond ---------------------------- */ func NewMsgDecreaseBond(creator string, decreaseBond sdk.Coin) *MsgDecreaseBond { return &MsgDecreaseBond{ Creator: creator, @@ -50,7 +48,7 @@ func NewMsgDecreaseBond(creator string, decreaseBond sdk.Coin) *MsgDecreaseBond func (msg *MsgDecreaseBond) ValidateBasic() error { _, err := sdk.AccAddressFromBech32(msg.Creator) if err != nil { - return errorsmod.Wrapf(ErrInvalidAddress, "invalid creator address (%s)", err) + return errorsmod.Wrapf(ErrInvalidAddr, "invalid creator address (%s)", err) } if !(msg.DecreaseAmount.IsValid() && msg.DecreaseAmount.IsPositive()) { @@ -67,3 +65,28 @@ func (msg *MsgDecreaseBond) GetSigners() []sdk.AccAddress { } return []sdk.AccAddress{creator} } + +var _ sdk.Msg = &MsgUnbond{} + +func NewMsgUnbond(creator string) *MsgUnbond { + return &MsgUnbond{ + Creator: creator, + } +} + +func (msg *MsgUnbond) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + return errorsmod.Wrapf(ErrInvalidAddr, "invalid creator address (%s)", err) + } + + return nil +} + +func (msg *MsgUnbond) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(msg.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} diff --git a/x/sequencer/types/msg_create_sequencer.go b/x/sequencer/types/msg_create.go similarity index 94% rename from x/sequencer/types/msg_create_sequencer.go rename to x/sequencer/types/msg_create.go index 0f9f91dd5..2151dcc12 100644 --- a/x/sequencer/types/msg_create_sequencer.go +++ b/x/sequencer/types/msg_create.go @@ -40,7 +40,7 @@ func NewMsgCreateSequencer( whitelistedRelayers []string, ) (*MsgCreateSequencer, error) { if metadata == nil { - return nil, ErrInvalidRequest + return nil, gerrc.ErrInvalidArgument } var pkAny *codectypes.Any if pubkey != nil { @@ -85,7 +85,7 @@ func (msg *MsgCreateSequencer) GetSignBytes() []byte { func (msg *MsgCreateSequencer) ValidateBasic() error { _, err := sdk.AccAddressFromBech32(msg.Creator) if err != nil { - return errorsmod.Wrapf(ErrInvalidAddress, "invalid creator address (%s)", err) + return errorsmod.Wrapf(ErrInvalidAddr, "invalid creator address (%s)", err) } // public key also checked by the application logic @@ -101,7 +101,7 @@ func (msg *MsgCreateSequencer) ValidateBasic() error { // cast to cryptotypes.PubKey type pk, ok := msg.DymintPubKey.GetCachedValue().(cryptotypes.PubKey) if !ok { - return errorsmod.Wrapf(ErrInvalidType, "expecting cryptotypes.PubKey, got %T", pk) + return errorsmod.WithType(ErrInvalidPubKey, pk) } _, err = edwards.ParsePubKey(edwards.Edwards(), pk.Bytes()) diff --git a/x/sequencer/types/msg_create_sequencer_test.go b/x/sequencer/types/msg_create_test.go similarity index 99% rename from x/sequencer/types/msg_create_sequencer_test.go rename to x/sequencer/types/msg_create_test.go index 7dae7e39e..f1ca159c0 100644 --- a/x/sequencer/types/msg_create_sequencer_test.go +++ b/x/sequencer/types/msg_create_test.go @@ -47,7 +47,7 @@ func TestMsgCreateSequencer_ValidateBasic(t *testing.T) { DymintPubKey: pkAny, Bond: bond, }, - err: ErrInvalidAddress, + err: ErrInvalidAddr, }, { name: "valid address", msg: MsgCreateSequencer{ @@ -239,7 +239,7 @@ func TestNewMsgIncreaseBond_ValidateBasic(t *testing.T) { Creator: "invalid_address", AddAmount: sdk.NewInt64Coin("stake", 100), }, - err: ErrInvalidAddress, + err: ErrInvalidAddr, }, { name: "invalid bond amount", @@ -281,7 +281,7 @@ func TestNewMsgDecreaseBond_ValidateBasic(t *testing.T) { Creator: "invalid_address", DecreaseAmount: sdk.NewInt64Coin("stake", 100), }, - err: ErrInvalidAddress, + err: ErrInvalidAddr, }, { name: "invalid bond amount", diff --git a/x/sequencer/types/msg_kick_proposer.go b/x/sequencer/types/msg_kick_proposer.go new file mode 100644 index 000000000..e2e1fd097 --- /dev/null +++ b/x/sequencer/types/msg_kick_proposer.go @@ -0,0 +1,33 @@ +package types + +import ( + "errors" + + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" +) + +var _ sdk.Msg = &MsgKickProposer{} + +func NewMsgKickProposer(creator string) *MsgKickProposer { + return &MsgKickProposer{ + Creator: creator, + } +} + +func (m *MsgKickProposer) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Creator) + if err != nil { + return errorsmod.Wrap(errors.Join(gerrc.ErrInvalidArgument, err), "get creator addr from bech32") + } + return nil +} + +func (m *MsgKickProposer) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(m.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} diff --git a/x/sequencer/types/msg_unbond.go b/x/sequencer/types/msg_unbond.go deleted file mode 100644 index 183293350..000000000 --- a/x/sequencer/types/msg_unbond.go +++ /dev/null @@ -1,31 +0,0 @@ -package types - -import ( - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -var _ sdk.Msg = &MsgUnbond{} - -func NewMsgUnbond(creator string) *MsgUnbond { - return &MsgUnbond{ - Creator: creator, - } -} - -func (msg *MsgUnbond) ValidateBasic() error { - _, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - return errorsmod.Wrapf(ErrInvalidAddress, "invalid creator address (%s)", err) - } - - return nil -} - -func (msg *MsgUnbond) GetSigners() []sdk.AccAddress { - creator, err := sdk.AccAddressFromBech32(msg.Creator) - if err != nil { - panic(err) - } - return []sdk.AccAddress{creator} -} diff --git a/x/sequencer/types/msg_update_sequencer.go b/x/sequencer/types/msg_update.go similarity index 70% rename from x/sequencer/types/msg_update_sequencer.go rename to x/sequencer/types/msg_update.go index 7e5c2b0f1..50e4ea968 100644 --- a/x/sequencer/types/msg_update_sequencer.go +++ b/x/sequencer/types/msg_update.go @@ -1,21 +1,25 @@ package types import ( + "errors" + errorsmod "cosmossdk.io/errors" codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) var ( _ sdk.Msg = &MsgUpdateSequencerInformation{} + _ sdk.Msg = &MsgUpdateOptInStatus{} _ codectypes.UnpackInterfacesMessage = (*MsgUpdateSequencerInformation)(nil) ) func NewMsgUpdateSequencerInformation(creator string, metadata *SequencerMetadata) (*MsgUpdateSequencerInformation, error) { if metadata == nil { - return nil, ErrInvalidRequest + return nil, gerrc.ErrInvalidArgument } return &MsgUpdateSequencerInformation{ Creator: creator, @@ -63,3 +67,26 @@ func (msg *MsgUpdateSequencerInformation) VMSpecificValidate(vmType types.Rollap } func (msg *MsgUpdateSequencerInformation) UnpackInterfaces(codectypes.AnyUnpacker) error { return nil } + +func (m *MsgUpdateOptInStatus) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(m.Creator) + if err != nil { + return errorsmod.Wrap(errors.Join(gerrc.ErrInvalidArgument, err), "get creator addr from bech32") + } + return nil +} + +func (m *MsgUpdateOptInStatus) GetSigners() []sdk.AccAddress { + creator, err := sdk.AccAddressFromBech32(m.Creator) + if err != nil { + panic(err) + } + return []sdk.AccAddress{creator} +} + +func NewMsgUpdateOptInStatus(creator string, optIn bool) *MsgUpdateOptInStatus { + return &MsgUpdateOptInStatus{ + Creator: creator, + OptedIn: optIn, + } +} diff --git a/x/sequencer/types/msg_update_reward_address.go b/x/sequencer/types/msg_update_reward_address.go index ded316791..2464ebe47 100644 --- a/x/sequencer/types/msg_update_reward_address.go +++ b/x/sequencer/types/msg_update_reward_address.go @@ -11,7 +11,7 @@ import ( var _ sdk.Msg = (*MsgUpdateRewardAddress)(nil) func (m *MsgUpdateRewardAddress) ValidateBasic() error { - _, err := sdk.ValAddressFromBech32(m.Creator) + _, err := sdk.AccAddressFromBech32(m.Creator) if err != nil { return errorsmod.Wrap(errors.Join(gerrc.ErrInvalidArgument, err), "get creator addr from bech32") } @@ -23,6 +23,6 @@ func (m *MsgUpdateRewardAddress) ValidateBasic() error { } func (m *MsgUpdateRewardAddress) GetSigners() []sdk.AccAddress { - addr, _ := sdk.ValAddressFromBech32(m.Creator) - return []sdk.AccAddress{sdk.AccAddress(addr)} + addr, _ := sdk.AccAddressFromBech32(m.Creator) + return []sdk.AccAddress{addr} } diff --git a/x/sequencer/types/msg_update_reward_address_test.go b/x/sequencer/types/msg_update_reward_address_test.go index c78888b1e..7976bdefe 100644 --- a/x/sequencer/types/msg_update_reward_address_test.go +++ b/x/sequencer/types/msg_update_reward_address_test.go @@ -3,7 +3,6 @@ package types_test import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/gerr-cosmos/gerrc" "github.com/stretchr/testify/require" @@ -12,7 +11,7 @@ import ( ) func TestMsgUpdateRewardAddress(t *testing.T) { - valAddr := sdk.ValAddress(sample.Acc()) + valAddr := sample.Acc() rewardAddr := sample.AccAddress() tests := []struct { diff --git a/x/sequencer/types/msg_update_sequencer_test.go b/x/sequencer/types/msg_update_test.go similarity index 100% rename from x/sequencer/types/msg_update_sequencer_test.go rename to x/sequencer/types/msg_update_test.go diff --git a/x/sequencer/types/msg_update_whitelisted_relayers.go b/x/sequencer/types/msg_update_whitelisted_relayers.go index d21740b76..a98cacde8 100644 --- a/x/sequencer/types/msg_update_whitelisted_relayers.go +++ b/x/sequencer/types/msg_update_whitelisted_relayers.go @@ -15,7 +15,7 @@ const maxWhitelistedRelayers = 10 var _ sdk.Msg = new(MsgUpdateWhitelistedRelayers) func (m *MsgUpdateWhitelistedRelayers) ValidateBasic() error { - _, err := sdk.ValAddressFromBech32(m.Creator) + _, err := sdk.AccAddressFromBech32(m.Creator) if err != nil { return errorsmod.Wrap(errors.Join(gerrc.ErrInvalidArgument, err), "get creator addr from bech32") } @@ -60,6 +60,6 @@ func Bech32ToAddr[T sdk.AccAddress | sdk.ValAddress](addr string) (T, error) { } func (m *MsgUpdateWhitelistedRelayers) GetSigners() []sdk.AccAddress { - addr, _ := sdk.ValAddressFromBech32(m.Creator) - return []sdk.AccAddress{sdk.AccAddress(addr)} + addr, _ := sdk.AccAddressFromBech32(m.Creator) + return []sdk.AccAddress{addr} } diff --git a/x/sequencer/types/msg_update_whitelisted_relayers_test.go b/x/sequencer/types/msg_update_whitelisted_relayers_test.go index f786f3748..136d46161 100644 --- a/x/sequencer/types/msg_update_whitelisted_relayers_test.go +++ b/x/sequencer/types/msg_update_whitelisted_relayers_test.go @@ -3,7 +3,6 @@ package types_test import ( "testing" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/gerr-cosmos/gerrc" "github.com/stretchr/testify/require" @@ -12,7 +11,7 @@ import ( ) func TestMsgUpdateWhitelistedRelayers(t *testing.T) { - valAddr := sdk.ValAddress(sample.Acc()) + valAddr := sample.Acc() addr := sample.AccAddress() relayers := []string{ sample.AccAddress(), diff --git a/x/sequencer/types/operating_status.pb.go b/x/sequencer/types/operating_status.pb.go index 85d61bd01..31f0d2df7 100644 --- a/x/sequencer/types/operating_status.pb.go +++ b/x/sequencer/types/operating_status.pb.go @@ -28,8 +28,6 @@ const ( // OPERATING_STATUS_UNBONDED defines a sequencer that is not active and won't // be scheduled Unbonded OperatingStatus = 0 - // UNBONDING defines a sequencer that is currently unbonding. - Unbonding OperatingStatus = 1 // OPERATING_STATUS_BONDED defines a sequencer that is bonded and can be // scheduled Bonded OperatingStatus = 2 @@ -37,14 +35,12 @@ const ( var OperatingStatus_name = map[int32]string{ 0: "OPERATING_STATUS_UNBONDED", - 1: "OPERATING_STATUS_UNBONDING", 2: "OPERATING_STATUS_BONDED", } var OperatingStatus_value = map[string]int32{ - "OPERATING_STATUS_UNBONDED": 0, - "OPERATING_STATUS_UNBONDING": 1, - "OPERATING_STATUS_BONDED": 2, + "OPERATING_STATUS_UNBONDED": 0, + "OPERATING_STATUS_BONDED": 2, } func (x OperatingStatus) String() string { @@ -64,22 +60,21 @@ func init() { } var fileDescriptor_4d19c29067c09de2 = []byte{ - // 260 bytes of a gzipped FileDescriptorProto + // 242 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x32, 0x4f, 0xa9, 0xcc, 0x4d, 0xcd, 0x2b, 0xce, 0xcc, 0xcf, 0xab, 0xa8, 0xac, 0xd2, 0x87, 0x73, 0xf4, 0x8b, 0x53, 0x0b, 0x4b, 0x53, 0xf3, 0x92, 0x53, 0x8b, 0xf4, 0xf3, 0x0b, 0x52, 0x8b, 0x12, 0x4b, 0x32, 0xf3, 0xd2, 0xe3, 0x8b, 0x4b, 0x12, 0x4b, 0x4a, 0x8b, 0xf5, 0x0a, 0x8a, 0xf2, 0x4b, 0xf2, 0x85, 0x14, 0x90, 0x35, 0xea, 0xc1, 0x39, 0x7a, 0x70, 0x8d, 0x52, 0x22, 0xe9, 0xf9, 0xe9, 0xf9, 0x60, 0xc5, 0xfa, 0x20, - 0x16, 0x44, 0x9f, 0xd6, 0x1c, 0x46, 0x2e, 0x7e, 0x7f, 0x98, 0x91, 0xc1, 0x60, 0x13, 0x85, 0xb4, - 0xb9, 0x24, 0xfd, 0x03, 0x5c, 0x83, 0x1c, 0x43, 0x3c, 0xfd, 0xdc, 0xe3, 0x83, 0x43, 0x1c, 0x43, - 0x42, 0x83, 0xe3, 0x43, 0xfd, 0x9c, 0xfc, 0xfd, 0x5c, 0x5c, 0x5d, 0x04, 0x18, 0xa4, 0x78, 0xba, - 0xe6, 0x2a, 0x70, 0x84, 0xe6, 0x25, 0xe5, 0xe7, 0xa5, 0xa4, 0xa6, 0x08, 0xe9, 0x72, 0x49, 0xe1, - 0x50, 0xec, 0xe9, 0xe7, 0x2e, 0xc0, 0x28, 0xc5, 0xdb, 0x35, 0x57, 0x81, 0x13, 0xa2, 0x3a, 0x33, - 0x2f, 0x5d, 0x48, 0x9d, 0x4b, 0x1c, 0x43, 0x39, 0xd4, 0x64, 0x26, 0x29, 0xae, 0xae, 0xb9, 0x0a, - 0x6c, 0x4e, 0x60, 0x73, 0xa5, 0x58, 0x3a, 0x16, 0xcb, 0x31, 0x38, 0x05, 0x9c, 0x78, 0x24, 0xc7, - 0x78, 0xe1, 0x91, 0x1c, 0xe3, 0x83, 0x47, 0x72, 0x8c, 0x13, 0x1e, 0xcb, 0x31, 0x5c, 0x78, 0x2c, - 0xc7, 0x70, 0xe3, 0xb1, 0x1c, 0x43, 0x94, 0x59, 0x7a, 0x66, 0x49, 0x46, 0x69, 0x92, 0x5e, 0x72, - 0x7e, 0xae, 0x3e, 0x8e, 0x40, 0x2b, 0x33, 0xd6, 0xaf, 0x40, 0x0a, 0xb9, 0x92, 0xca, 0x82, 0xd4, - 0xe2, 0x24, 0x36, 0xb0, 0xbf, 0x8d, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xc4, 0x80, 0x47, 0x58, - 0x6a, 0x01, 0x00, 0x00, + 0x16, 0x44, 0x9f, 0x56, 0x31, 0x17, 0xbf, 0x3f, 0xcc, 0xc4, 0x60, 0xb0, 0x81, 0x42, 0xda, 0x5c, + 0x92, 0xfe, 0x01, 0xae, 0x41, 0x8e, 0x21, 0x9e, 0x7e, 0xee, 0xf1, 0xc1, 0x21, 0x8e, 0x21, 0xa1, + 0xc1, 0xf1, 0xa1, 0x7e, 0x4e, 0xfe, 0x7e, 0x2e, 0xae, 0x2e, 0x02, 0x0c, 0x52, 0x3c, 0x5d, 0x73, + 0x15, 0x38, 0x42, 0xf3, 0x92, 0xf2, 0xf3, 0x52, 0x52, 0x53, 0x84, 0xd4, 0xb9, 0xc4, 0x31, 0x14, + 0x43, 0x95, 0x32, 0x49, 0x71, 0x75, 0xcd, 0x55, 0x60, 0x73, 0x02, 0x2b, 0x94, 0x62, 0xe9, 0x58, + 0x2c, 0xc7, 0xa0, 0xc4, 0xc2, 0xc1, 0x28, 0xc0, 0xe8, 0x14, 0x70, 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, 0x66, 0xe9, 0x99, 0x25, 0x19, 0xa5, 0x49, 0x7a, 0xc9, 0xf9, 0xb9, + 0xfa, 0x38, 0x82, 0xa2, 0xcc, 0x58, 0xbf, 0x02, 0x29, 0x3c, 0x4a, 0x2a, 0x0b, 0x52, 0x8b, 0x93, + 0xd8, 0xc0, 0xbe, 0x31, 0x06, 0x04, 0x00, 0x00, 0xff, 0xff, 0xf3, 0x80, 0xeb, 0x32, 0x40, 0x01, + 0x00, 0x00, } diff --git a/x/sequencer/types/params.go b/x/sequencer/types/params.go index 8b49a24a7..3e498e43a 100644 --- a/x/sequencer/types/params.go +++ b/x/sequencer/types/params.go @@ -12,21 +12,24 @@ import ( var ( // DefaultMinBond is the minimum bond required to be a validator DefaultMinBond uint64 = 1000000 - // DefaultUnbondingTime is the time duration for unbonding - DefaultUnbondingTime time.Duration = time.Hour * 24 * 7 * 2 // 2 weeks + // DefaultKickThreshold is the minimum bond required to be a validator + DefaultKickThreshold uint64 = 10 // DefaultNoticePeriod is the time duration for notice period - DefaultNoticePeriod time.Duration = time.Hour * 24 * 7 // 1 week + DefaultNoticePeriod = time.Hour * 24 * 7 // 1 week // DefaultLivenessSlashMultiplier gives the amount of tokens to slash if the sequencer is liable for a liveness failure - DefaultLivenessSlashMultiplier sdk.Dec = sdk.MustNewDecFromStr("0.01907") // leaves 50% of original funds remaining after 48 slashes + DefaultLivenessSlashMultiplier = sdk.MustNewDecFromStr("0.01") + // DefaultLivenessSlashMinAbsolute will be slashed if the multiplier amount is too small + DefaultLivenessSlashMinAbsolute uint64 = 1 ) // NewParams creates a new Params instance -func NewParams(minBond sdk.Coin, unbondingPeriod, noticePeriod time.Duration, livenessSlashMul sdk.Dec) Params { +func NewParams(minBond sdk.Coin, noticePeriod time.Duration, livenessSlashMul sdk.Dec, livenessSlashAbs sdk.Coin, kickThreshold sdk.Coin) Params { return Params{ - MinBond: minBond, - UnbondingTime: unbondingPeriod, - NoticePeriod: noticePeriod, - LivenessSlashMultiplier: livenessSlashMul, + MinBond: minBond, + NoticePeriod: noticePeriod, + LivenessSlashMinMultiplier: livenessSlashMul, + LivenessSlashMinAbsolute: livenessSlashAbs, + KickThreshold: kickThreshold, } } @@ -37,8 +40,11 @@ func DefaultParams() Params { panic(err) } minBond := sdk.NewCoin(denom, sdk.NewIntFromUint64(DefaultMinBond)) + kick := sdk.NewCoin(denom, sdk.NewIntFromUint64(DefaultKickThreshold)) + slashAbs := sdk.NewCoin(denom, sdk.NewIntFromUint64(DefaultLivenessSlashMinAbsolute)) return NewParams( - minBond, DefaultUnbondingTime, DefaultNoticePeriod, DefaultLivenessSlashMultiplier, + minBond, DefaultNoticePeriod, DefaultLivenessSlashMultiplier, slashAbs, + kick, ) } @@ -81,15 +87,19 @@ func (p Params) ValidateBasic() error { return err } - if err := validateTime(p.UnbondingTime); err != nil { + if err := validateTime(p.NoticePeriod); err != nil { return err } - if err := validateTime(p.NoticePeriod); err != nil { + if err := validateLivenessSlashMultiplier(p.LivenessSlashMinMultiplier); err != nil { + return err + } + + if err := uparam.ValidateCoin(p.LivenessSlashMinAbsolute); err != nil { return err } - if err := validateLivenessSlashMultiplier(p.LivenessSlashMultiplier); err != nil { + if err := uparam.ValidateCoin(p.KickThreshold); err != nil { return err } diff --git a/x/sequencer/types/params.pb.go b/x/sequencer/types/params.pb.go index ddafe03f5..555852bd8 100644 --- a/x/sequencer/types/params.pb.go +++ b/x/sequencer/types/params.pb.go @@ -31,15 +31,18 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Params defines the parameters for the module. type Params struct { + // minimum amt that must be put up for stake to be sequencer MinBond types.Coin `protobuf:"bytes,1,opt,name=min_bond,json=minBond,proto3" json:"min_bond,omitempty"` - // unbonding_time is the time duration of unbonding. - UnbondingTime time.Duration `protobuf:"bytes,2,opt,name=unbonding_time,json=unbondingTime,proto3,stdduration" json:"unbonding_time"` + // amt where the active sequencer can be kicked if he has less or equal bond + KickThreshold types.Coin `protobuf:"bytes,5,opt,name=kick_threshold,json=kickThreshold,proto3" json:"kick_threshold,omitempty"` // notice_period is the time duration of notice period. // notice period is the duration between the unbond request and the actual // unbonding starting. the proposer is still bonded during this period. NoticePeriod time.Duration `protobuf:"bytes,3,opt,name=notice_period,json=noticePeriod,proto3,stdduration" json:"notice_period"` - // LivenessSlashMultiplier multiplies with the tokens of the slashed sequencer to compute the burn amount. - LivenessSlashMultiplier github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=liveness_slash_multiplier,json=livenessSlashMultiplier,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"liveness_slash_multiplier" yaml:"liveness_slash_multiplier"` + // liveness_slash_min_multiplier multiplies with the tokens of the slashed sequencer to compute the burn amount. + LivenessSlashMinMultiplier github_com_cosmos_cosmos_sdk_types.Dec `protobuf:"bytes,4,opt,name=liveness_slash_min_multiplier,json=livenessSlashMinMultiplier,proto3,customtype=github.com/cosmos/cosmos-sdk/types.Dec" json:"liveness_slash_min_multiplier" yaml:"liveness_slash_multiplier"` + // liveness_slash_min_absolute is the absolute minimum to slash for liveness + LivenessSlashMinAbsolute types.Coin `protobuf:"bytes,6,opt,name=liveness_slash_min_absolute,json=livenessSlashMinAbsolute,proto3" json:"liveness_slash_min_absolute,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -81,11 +84,11 @@ func (m *Params) GetMinBond() types.Coin { return types.Coin{} } -func (m *Params) GetUnbondingTime() time.Duration { +func (m *Params) GetKickThreshold() types.Coin { if m != nil { - return m.UnbondingTime + return m.KickThreshold } - return 0 + return types.Coin{} } func (m *Params) GetNoticePeriod() time.Duration { @@ -95,6 +98,13 @@ func (m *Params) GetNoticePeriod() time.Duration { return 0 } +func (m *Params) GetLivenessSlashMinAbsolute() types.Coin { + if m != nil { + return m.LivenessSlashMinAbsolute + } + return types.Coin{} +} + func init() { proto.RegisterType((*Params)(nil), "dymensionxyz.dymension.sequencer.Params") } @@ -104,34 +114,38 @@ func init() { } var fileDescriptor_599b0eefba99ee26 = []byte{ - // 422 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0x3f, 0x8b, 0xd4, 0x40, - 0x18, 0xc6, 0x33, 0x9e, 0x9c, 0x6b, 0xf4, 0x2c, 0x82, 0xe0, 0xde, 0x16, 0x49, 0xd8, 0x42, 0xae, - 0xf0, 0x66, 0x38, 0x0f, 0x2c, 0xae, 0x8c, 0x57, 0x88, 0x20, 0x84, 0x68, 0x65, 0x13, 0xf2, 0xe7, - 0x35, 0x37, 0x98, 0x99, 0x37, 0x66, 0x26, 0xcb, 0xc5, 0xaf, 0x20, 0x88, 0xe5, 0x95, 0xf7, 0x71, - 0xae, 0xbc, 0x52, 0x2c, 0xa2, 0xec, 0x36, 0x62, 0xe9, 0x27, 0x90, 0xfc, 0x65, 0x9b, 0x05, 0xab, - 0xe4, 0x9d, 0xe7, 0x79, 0x7e, 0x3c, 0xbc, 0xbc, 0xe6, 0x71, 0x5a, 0x0b, 0x90, 0x8a, 0xa3, 0xbc, - 0xac, 0x3f, 0xb3, 0x69, 0x60, 0x0a, 0x3e, 0x55, 0x20, 0x13, 0x28, 0x59, 0x11, 0x95, 0x91, 0x50, - 0xb4, 0x28, 0x51, 0xa3, 0xe5, 0x6e, 0xdb, 0xe9, 0x34, 0xd0, 0xc9, 0xbe, 0x78, 0x9c, 0x61, 0x86, - 0x9d, 0x99, 0xb5, 0x7f, 0x7d, 0x6e, 0x61, 0x27, 0xa8, 0x04, 0x2a, 0x16, 0x47, 0x0a, 0xd8, 0xea, - 0x24, 0x06, 0x1d, 0x9d, 0xb0, 0x04, 0xb9, 0x1c, 0xf5, 0x0c, 0x31, 0xcb, 0x81, 0x75, 0x53, 0x5c, - 0x7d, 0x60, 0x69, 0x55, 0x46, 0xba, 0x25, 0x77, 0x2f, 0xcb, 0x2f, 0x7b, 0xe6, 0xbe, 0xdf, 0x15, - 0xb1, 0x7c, 0x73, 0x26, 0xb8, 0x0c, 0x63, 0x94, 0xe9, 0x9c, 0xb8, 0xe4, 0xe8, 0xc1, 0xf3, 0x43, - 0xda, 0xd3, 0x69, 0x4b, 0xa7, 0x03, 0x9d, 0xbe, 0x44, 0x2e, 0xbd, 0xc5, 0x4d, 0xe3, 0x18, 0x7f, - 0x1a, 0xc7, 0x1a, 0x23, 0xcf, 0x50, 0x70, 0x0d, 0xa2, 0xd0, 0x75, 0x70, 0x4f, 0x70, 0xe9, 0xa1, - 0x4c, 0xad, 0xd7, 0xe6, 0xa3, 0x4a, 0xb6, 0x22, 0x97, 0x59, 0xa8, 0xb9, 0x80, 0xf9, 0x9d, 0x81, - 0xdb, 0xb7, 0xa2, 0x63, 0x2b, 0x7a, 0x3e, 0xb4, 0xf2, 0x66, 0x2d, 0xf7, 0xea, 0xa7, 0x43, 0x82, - 0x83, 0x29, 0xfa, 0x8e, 0x0b, 0xb0, 0x5e, 0x99, 0x07, 0x12, 0x35, 0x4f, 0x20, 0x2c, 0xa0, 0xe4, - 0x98, 0xce, 0xf7, 0xfe, 0x1f, 0xf5, 0xb0, 0x4f, 0xfa, 0x5d, 0xd0, 0xfa, 0x4a, 0xcc, 0xc3, 0x9c, - 0xaf, 0x40, 0x82, 0x52, 0xa1, 0xca, 0x23, 0x75, 0x11, 0x8a, 0x2a, 0xd7, 0xbc, 0xc8, 0x39, 0x94, - 0xf3, 0xbb, 0x2e, 0x39, 0xba, 0xef, 0x05, 0x6d, 0xf6, 0x47, 0xe3, 0x3c, 0xcd, 0xb8, 0xbe, 0xa8, - 0x62, 0x9a, 0xa0, 0x60, 0xc3, 0xa6, 0xfb, 0xcf, 0xb1, 0x4a, 0x3f, 0x32, 0x5d, 0x17, 0xa0, 0xe8, - 0x39, 0x24, 0x7f, 0x1b, 0xc7, 0xad, 0x23, 0x91, 0x9f, 0x2d, 0x77, 0x82, 0x97, 0xc1, 0x93, 0x51, - 0x7b, 0xdb, 0x4a, 0x6f, 0x26, 0xe5, 0x6c, 0x76, 0x75, 0xed, 0x18, 0xbf, 0xaf, 0x1d, 0xe2, 0xf9, - 0x37, 0x6b, 0x9b, 0xdc, 0xae, 0x6d, 0xf2, 0x6b, 0x6d, 0x93, 0x6f, 0x1b, 0xdb, 0xb8, 0xdd, 0xd8, - 0xc6, 0xf7, 0x8d, 0x6d, 0xbc, 0x7f, 0xb1, 0x55, 0x64, 0xc7, 0x65, 0xad, 0x4e, 0xd9, 0xe5, 0xd6, - 0x79, 0x75, 0xe5, 0xe2, 0xfd, 0x6e, 0x2f, 0xa7, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xa5, 0x40, - 0xbb, 0x89, 0x8f, 0x02, 0x00, 0x00, + // 483 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x93, 0xbd, 0x8e, 0xd3, 0x4e, + 0x14, 0xc5, 0x3d, 0xff, 0xcd, 0x3f, 0x04, 0xc3, 0x22, 0x64, 0x51, 0x98, 0x20, 0x6c, 0x2b, 0x12, + 0x68, 0x0b, 0x32, 0xa3, 0x65, 0x25, 0x8a, 0xed, 0x30, 0x5b, 0x20, 0xa4, 0x95, 0xa2, 0x40, 0x45, + 0x63, 0xf9, 0x63, 0x70, 0x46, 0xf1, 0xcc, 0x35, 0x9e, 0x71, 0xb4, 0xe6, 0x05, 0x68, 0x69, 0x90, + 0xb6, 0xdc, 0xe7, 0xe0, 0x09, 0xb6, 0xdc, 0x12, 0x51, 0x04, 0x94, 0x34, 0x88, 0x92, 0x27, 0x40, + 0xfe, 0x94, 0x59, 0x01, 0x5b, 0x25, 0xd7, 0xe7, 0x9e, 0xdf, 0xdc, 0x7b, 0x46, 0xa3, 0x4f, 0xa3, + 0x82, 0x53, 0x21, 0x19, 0x88, 0x93, 0xe2, 0x1d, 0xe9, 0x0a, 0x22, 0xe9, 0xdb, 0x9c, 0x8a, 0x90, + 0x66, 0x24, 0xf5, 0x33, 0x9f, 0x4b, 0x9c, 0x66, 0xa0, 0xc0, 0x70, 0xfa, 0xed, 0xb8, 0x2b, 0x70, + 0xd7, 0x3e, 0xbe, 0x13, 0x43, 0x0c, 0x55, 0x33, 0x29, 0xff, 0xd5, 0xbe, 0xb1, 0x15, 0x82, 0xe4, + 0x20, 0x49, 0xe0, 0x4b, 0x4a, 0x56, 0xfb, 0x01, 0x55, 0xfe, 0x3e, 0x09, 0x81, 0x89, 0x56, 0x8f, + 0x01, 0xe2, 0x84, 0x92, 0xaa, 0x0a, 0xf2, 0x37, 0x24, 0xca, 0x33, 0x5f, 0x95, 0xe4, 0xea, 0xcb, + 0xe4, 0xd3, 0x40, 0x1f, 0xce, 0xaa, 0x41, 0x8c, 0x99, 0x3e, 0xe2, 0x4c, 0x78, 0x01, 0x88, 0xc8, + 0x44, 0x0e, 0xda, 0xbb, 0xf1, 0xf8, 0x2e, 0xae, 0xe9, 0xb8, 0xa4, 0xe3, 0x86, 0x8e, 0x9f, 0x01, + 0x13, 0xee, 0xf8, 0x7c, 0x6d, 0x6b, 0x3f, 0xd6, 0xb6, 0xd1, 0x5a, 0x1e, 0x01, 0x67, 0x8a, 0xf2, + 0x54, 0x15, 0xf3, 0x6b, 0x9c, 0x09, 0x17, 0x44, 0x64, 0x04, 0xfa, 0xad, 0x25, 0x0b, 0x97, 0x9e, + 0x5a, 0x64, 0x54, 0x2e, 0x20, 0x89, 0xcc, 0xff, 0xaf, 0xe2, 0x3a, 0x0d, 0xd7, 0xfc, 0xdd, 0xd8, + 0xa3, 0xef, 0x96, 0xca, 0xab, 0x56, 0x30, 0x9e, 0xeb, 0xbb, 0x02, 0x14, 0x0b, 0xa9, 0x97, 0xd2, + 0x8c, 0x41, 0x64, 0xee, 0x34, 0x47, 0xd4, 0x8b, 0xe3, 0x76, 0x71, 0x7c, 0xd4, 0x2c, 0xee, 0x8e, + 0xca, 0x23, 0x4e, 0xbf, 0xda, 0x68, 0x7e, 0xb3, 0x76, 0xce, 0x2a, 0xa3, 0xf1, 0x11, 0xe9, 0xf7, + 0x13, 0xb6, 0xa2, 0x82, 0x4a, 0xe9, 0xc9, 0xc4, 0x97, 0x0b, 0xaf, 0x5c, 0x8e, 0xe7, 0x89, 0x62, + 0x69, 0xc2, 0x68, 0x66, 0x0e, 0x1c, 0xb4, 0x77, 0xdd, 0x9d, 0x97, 0xfe, 0x2f, 0x6b, 0xfb, 0x61, + 0xcc, 0xd4, 0x22, 0x0f, 0x70, 0x08, 0x9c, 0x34, 0xb7, 0x50, 0xff, 0x4c, 0x65, 0xb4, 0x24, 0xaa, + 0x48, 0xa9, 0xc4, 0x47, 0x34, 0xfc, 0xb9, 0xb6, 0x9d, 0xc2, 0xe7, 0xc9, 0xe1, 0xe4, 0x32, 0xbc, + 0x03, 0x4f, 0xe6, 0xe3, 0x56, 0x7b, 0x59, 0x4a, 0xc7, 0x4c, 0x1c, 0x77, 0xa2, 0xf1, 0x1e, 0xe9, + 0xf7, 0xfe, 0x30, 0x97, 0x1f, 0x48, 0x48, 0x72, 0x45, 0xcd, 0xe1, 0x55, 0x99, 0x4e, 0x9b, 0x4c, + 0x1f, 0xfc, 0x83, 0xd2, 0x0b, 0xd8, 0xbc, 0x3c, 0xcb, 0xd3, 0xa6, 0xe7, 0x70, 0x74, 0x7a, 0x66, + 0x6b, 0xdf, 0xcf, 0x6c, 0xf4, 0x62, 0x30, 0xfa, 0xef, 0xf6, 0x8e, 0x3b, 0x3b, 0xdf, 0x58, 0xe8, + 0x62, 0x63, 0xa1, 0x6f, 0x1b, 0x0b, 0x7d, 0xd8, 0x5a, 0xda, 0xc5, 0xd6, 0xd2, 0x3e, 0x6f, 0x2d, + 0xed, 0xf5, 0x93, 0x5e, 0x36, 0x7f, 0x79, 0x08, 0xab, 0x03, 0x72, 0xd2, 0x7b, 0x0d, 0x55, 0x5e, + 0xc1, 0xb0, 0xba, 0xae, 0x83, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x8e, 0xed, 0x24, 0xe8, 0x3e, + 0x03, 0x00, 0x00, } func (this *Params) Equal(that interface{}) bool { @@ -156,13 +170,16 @@ func (this *Params) Equal(that interface{}) bool { if !this.MinBond.Equal(&that1.MinBond) { return false } - if this.UnbondingTime != that1.UnbondingTime { + if !this.KickThreshold.Equal(&that1.KickThreshold) { return false } if this.NoticePeriod != that1.NoticePeriod { return false } - if !this.LivenessSlashMultiplier.Equal(that1.LivenessSlashMultiplier) { + if !this.LivenessSlashMinMultiplier.Equal(that1.LivenessSlashMinMultiplier) { + return false + } + if !this.LivenessSlashMinAbsolute.Equal(&that1.LivenessSlashMinAbsolute) { return false } return true @@ -188,31 +205,43 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { var l int _ = l { - size := m.LivenessSlashMultiplier.Size() + size, err := m.LivenessSlashMinAbsolute.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } i -= size - if _, err := m.LivenessSlashMultiplier.MarshalTo(dAtA[i:]); err != nil { + i = encodeVarintParams(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x32 + { + size, err := m.KickThreshold.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { return 0, err } + i -= size i = encodeVarintParams(dAtA, i, uint64(size)) } i-- - dAtA[i] = 0x22 - n1, err1 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.NoticePeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.NoticePeriod):]) - if err1 != nil { - return 0, err1 + dAtA[i] = 0x2a + { + size := m.LivenessSlashMinMultiplier.Size() + i -= size + if _, err := m.LivenessSlashMinMultiplier.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + i = encodeVarintParams(dAtA, i, uint64(size)) } - i -= n1 - i = encodeVarintParams(dAtA, i, uint64(n1)) i-- - dAtA[i] = 0x1a - n2, err2 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.UnbondingTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.UnbondingTime):]) - if err2 != nil { - return 0, err2 + dAtA[i] = 0x22 + n3, err3 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(m.NoticePeriod, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.NoticePeriod):]) + if err3 != nil { + return 0, err3 } - i -= n2 - i = encodeVarintParams(dAtA, i, uint64(n2)) + i -= n3 + i = encodeVarintParams(dAtA, i, uint64(n3)) i-- - dAtA[i] = 0x12 + dAtA[i] = 0x1a { size, err := m.MinBond.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -245,11 +274,13 @@ func (m *Params) Size() (n int) { _ = l l = m.MinBond.Size() n += 1 + l + sovParams(uint64(l)) - l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.UnbondingTime) - n += 1 + l + sovParams(uint64(l)) l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(m.NoticePeriod) n += 1 + l + sovParams(uint64(l)) - l = m.LivenessSlashMultiplier.Size() + l = m.LivenessSlashMinMultiplier.Size() + n += 1 + l + sovParams(uint64(l)) + l = m.KickThreshold.Size() + n += 1 + l + sovParams(uint64(l)) + l = m.LivenessSlashMinAbsolute.Size() n += 1 + l + sovParams(uint64(l)) return n } @@ -322,9 +353,9 @@ func (m *Params) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 2: + case 3: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UnbondingTime", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field NoticePeriod", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -351,13 +382,47 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.UnbondingTime, dAtA[iNdEx:postIndex]); err != nil { + if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.NoticePeriod, dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 3: + case 4: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field NoticePeriod", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LivenessSlashMinMultiplier", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowParams + } + 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 ErrInvalidLengthParams + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthParams + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if err := m.LivenessSlashMinMultiplier.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field KickThreshold", wireType) } var msglen int for shift := uint(0); ; shift += 7 { @@ -384,15 +449,15 @@ func (m *Params) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - if err := github_com_cosmos_gogoproto_types.StdDurationUnmarshal(&m.NoticePeriod, dAtA[iNdEx:postIndex]); err != nil { + if err := m.KickThreshold.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex - case 4: + case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field LivenessSlashMultiplier", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field LivenessSlashMinAbsolute", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowParams @@ -402,23 +467,22 @@ func (m *Params) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthParams } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthParams } if postIndex > l { return io.ErrUnexpectedEOF } - if err := m.LivenessSlashMultiplier.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + if err := m.LivenessSlashMinAbsolute.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err } iNdEx = postIndex diff --git a/x/sequencer/types/params_legacy.go b/x/sequencer/types/params_legacy.go index 8fa02953a..8f32f7c31 100644 --- a/x/sequencer/types/params_legacy.go +++ b/x/sequencer/types/params_legacy.go @@ -7,15 +7,17 @@ package types import ( paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/dymensionxyz/sdk-utils/utils/uparam" ) var _ paramtypes.ParamSet = &Params{} var ( - KeyMinBond = []byte("MinBond") - KeyUnbondingTime = []byte("UnbondingTime") - KeyNoticePeriod = []byte("NoticePeriod") - KeyLivenessSlashMultiplier = []byte("LivenessSlashMultiplier") + KeyMinBond = []byte("MinBond") + KeyKickThreshold = []byte("KickThreshold") + KeyNoticePeriod = []byte("NoticePeriod") + keyLivenessSlashMinMultiplier = []byte("LivenessSlashMultiplier") + KeyLivenessSlashMinAbsolute = []byte("LivenessSlashMinAbsolute") ) // Deprecated: ParamKeyTable for module @@ -28,8 +30,9 @@ func ParamKeyTable() paramtypes.KeyTable { func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { return paramtypes.ParamSetPairs{ paramtypes.NewParamSetPair(KeyMinBond, &p.MinBond, validateMinBond), - paramtypes.NewParamSetPair(KeyUnbondingTime, &p.UnbondingTime, validateTime), + paramtypes.NewParamSetPair(KeyKickThreshold, &p.KickThreshold, uparam.ValidateCoin), paramtypes.NewParamSetPair(KeyNoticePeriod, &p.NoticePeriod, validateTime), - paramtypes.NewParamSetPair(KeyLivenessSlashMultiplier, &p.LivenessSlashMultiplier, validateLivenessSlashMultiplier), + paramtypes.NewParamSetPair(keyLivenessSlashMinMultiplier, &p.LivenessSlashMinMultiplier, validateLivenessSlashMultiplier), + paramtypes.NewParamSetPair(KeyLivenessSlashMinAbsolute, &p.LivenessSlashMinAbsolute, uparam.ValidateCoin), } } diff --git a/x/sequencer/types/params_test.go b/x/sequencer/types/params_test.go index 94b92965c..829f54758 100644 --- a/x/sequencer/types/params_test.go +++ b/x/sequencer/types/params_test.go @@ -2,7 +2,6 @@ package types import ( "testing" - "time" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/stretchr/testify/require" @@ -24,27 +23,33 @@ func TestValidateBasic(t *testing.T) { { "invalid min bond", Params{ - MinBond: sdk.Coin{Denom: "testdenom", Amount: sdk.NewInt(-5)}, - UnbondingTime: params.UnbondingTime, - LivenessSlashMultiplier: params.LivenessSlashMultiplier, + MinBond: sdk.Coin{Denom: "testdenom", Amount: sdk.NewInt(-5)}, + NoticePeriod: params.NoticePeriod, + LivenessSlashMinMultiplier: params.LivenessSlashMinMultiplier, + LivenessSlashMinAbsolute: params.LivenessSlashMinAbsolute, + KickThreshold: params.KickThreshold, }, true, }, { - "invalid unbonding time", + "invalid notice period", Params{ - MinBond: params.MinBond, - UnbondingTime: -time.Second, - LivenessSlashMultiplier: params.LivenessSlashMultiplier, + MinBond: params.MinBond, + NoticePeriod: 0, + LivenessSlashMinMultiplier: params.LivenessSlashMinMultiplier, + LivenessSlashMinAbsolute: params.LivenessSlashMinAbsolute, + KickThreshold: params.KickThreshold, }, true, }, { "invalid liveness slash multiplier", Params{ - MinBond: params.MinBond, - UnbondingTime: params.UnbondingTime, - LivenessSlashMultiplier: sdk.NewDec(-1), + MinBond: params.MinBond, + NoticePeriod: params.NoticePeriod, + LivenessSlashMinMultiplier: sdk.NewDec(-1), + LivenessSlashMinAbsolute: params.LivenessSlashMinAbsolute, + KickThreshold: params.KickThreshold, }, true, }, diff --git a/x/sequencer/types/sequencer.go b/x/sequencer/types/sequencer.go index cd0d0b24c..810066a51 100644 --- a/x/sequencer/types/sequencer.go +++ b/x/sequencer/types/sequencer.go @@ -2,86 +2,197 @@ package types import ( "slices" + "time" - tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" - cometbfttypes "github.com/cometbft/cometbft/types" - "github.com/cosmos/cosmos-sdk/codec" - cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + errorsmod "cosmossdk.io/errors" + comettypes "github.com/cometbft/cometbft/types" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/gerr-cosmos/gerrc" + "github.com/dymensionxyz/sdk-utils/utils/uevent" +) + +const ( + SentinelSeqAddr = "sentinel" ) +func NewTestSequencer( + pk cryptotypes.PubKey, +) Sequencer { + pkAny, err := codectypes.NewAnyWithValue(pk) + if err != nil { + panic(err) + } + return Sequencer{ + Address: pk.Address().String(), + DymintPubKey: pkAny, + } +} + // ValidateBasic performs basic validation of the sequencer object func (seq Sequencer) ValidateBasic() error { - if seq.Status == Unbonding && (seq.UnbondRequestHeight == 0 || seq.UnbondTime.IsZero()) { - return ErrInvalidSequencerStatus + if seq.Tokens.Len() != 1 { + return gerrc.ErrInvalidArgument.Wrap("expect one coin") } + return nil +} - // validate notice period - if seq.IsNoticePeriodInProgress() && seq.NoticePeriodTime.IsZero() { - return ErrInvalidSequencerStatus +func (seq *Sequencer) SetOptedIn(ctx sdk.Context, x bool) error { + if err := uevent.EmitTypedEvent(ctx, &EventOptInStatusChange{ + seq.RollappId, + seq.Address, + seq.OptedIn, + x, + }); err != nil { + return err } - + seq.OptedIn = x return nil } -func (seq Sequencer) IsEmpty() bool { - return seq.Address == "" +func (seq Sequencer) Sentinel() bool { + return seq.Address == SentinelSeqAddr } -func (seq Sequencer) IsBonded() bool { +func (seq Sequencer) Bonded() bool { return seq.Status == Bonded } -// IsNoticePeriodInProgress returns true if the sequencer is bonded and has an unbond request -func (seq Sequencer) IsNoticePeriodInProgress() bool { - return seq.Status == Bonded && seq.UnbondRequestHeight != 0 +func (seq Sequencer) IsPotentialProposer() bool { + return seq.Bonded() && seq.OptedIn } -// GetDymintPubKeyHash returns the hash of the sequencer -// as expected to be written on the rollapp ibc client headers -func (seq Sequencer) GetDymintPubKeyHash() ([]byte, error) { - pubKey, err := seq.getCosmosPubKey() +func (seq Sequencer) TokensCoin() sdk.Coin { + return seq.Tokens[0] +} + +func (seq Sequencer) SetTokensCoin(c sdk.Coin) { + seq.Tokens[0] = c +} + +func (seq Sequencer) AccAddr() sdk.AccAddress { + return sdk.MustAccAddressFromBech32(seq.Address) +} + +func (seq Sequencer) NoticeInProgress(now time.Time) bool { + return seq.NoticeStarted() && !seq.NoticeElapsed(now) +} + +func (seq Sequencer) NoticeElapsed(now time.Time) bool { + return seq.NoticeStarted() && !now.Before(seq.NoticePeriodTime) +} + +func (seq Sequencer) NoticeStarted() bool { + return seq.NoticePeriodTime != time.Time{} +} + +func (seq Sequencer) ProposerAddr() ([]byte, error) { + return PubKeyAddr(seq.DymintPubKey) +} + +func (seq *Sequencer) SetWhitelistedRelayers(relayers []string) { + slices.Sort(relayers) + seq.WhitelistedRelayers = relayers +} + +// MustProposerAddr : intended for tests +func (seq Sequencer) MustProposerAddr() []byte { + ret, err := seq.ProposerAddr() if err != nil { - return nil, err + panic(err) } + return ret +} - // convert the pubkey to tmPubKey - tmPubKey, err := cryptocodec.ToTmPubKeyInterface(pubKey) +// MustPubKey is intended for tests +func (seq Sequencer) MustPubKey() cryptotypes.PubKey { + x, err := PubKey(seq.DymintPubKey) if err != nil { - return nil, err + panic(err) } - // Create a new tmValidator with fixed voting power of 1 - // TODO: Make sure the voting power is a param coming from hub and - // not being set independently in dymint and hub - tmValidator := cometbfttypes.NewValidator(tmPubKey, 1) - tmValidatorSet := cometbfttypes.NewValidatorSet([]*cometbfttypes.Validator{tmValidator}) - return tmValidatorSet.Hash(), nil + return x } -// GetCometPubKey returns the bytes of the sequencer's dymint pubkey -func (seq Sequencer) GetCometPubKey() (tmprotocrypto.PublicKey, error) { - pubKey, err := seq.getCosmosPubKey() +func (seq Sequencer) Valset() (*comettypes.ValidatorSet, error) { + pubKey, err := PubKey(seq.DymintPubKey) if err != nil { - return tmprotocrypto.PublicKey{}, err + return nil, errorsmod.Wrap(err, "pub key") } + return Valset(pubKey) +} - // convert the pubkey to tmPubKey - tmPubKey, err := cryptocodec.ToTmProtoPublicKey(pubKey) - return tmPubKey, err +func (seq Sequencer) ValsetHash() ([]byte, error) { + pubKey, err := PubKey(seq.DymintPubKey) + if err != nil { + return nil, errorsmod.Wrap(err, "pub key") + } + return ValsetHash(pubKey) +} + +// MustValset : intended for tests +func (seq Sequencer) MustValset() *comettypes.ValidatorSet { + x, err := seq.Valset() + if err != nil { + panic(err) + } + return x +} + +// MustValsetHash : intended for tests +func (seq Sequencer) MustValsetHash() []byte { + x, err := seq.ValsetHash() + if err != nil { + panic(err) + } + return x } -func (seq Sequencer) getCosmosPubKey() (cryptotypes.PubKey, error) { - interfaceRegistry := cdctypes.NewInterfaceRegistry() - cryptocodec.RegisterInterfaces(interfaceRegistry) - protoCodec := codec.NewProtoCodec(interfaceRegistry) +var _ codectypes.UnpackInterfacesMessage = (*Sequencer)(nil) +func (s Sequencer) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { var pubKey cryptotypes.PubKey - err := protoCodec.UnpackAny(seq.DymintPubKey, &pubKey) + return unpacker.UnpackAny(s.DymintPubKey, &pubKey) +} + +// TODO: move these utils to a more suitable package + +func PubKey(pk *codectypes.Any) (cryptotypes.PubKey, error) { + cdc := ModuleCdc + var pubKey cryptotypes.PubKey + err := cdc.UnpackAny(pk, &pubKey) return pubKey, err } -func (seq *Sequencer) SetWhitelistedRelayers(relayers []string) { - slices.Sort(relayers) - seq.WhitelistedRelayers = relayers +// PubKeyAddr returns comet/dymint 'proposer address' if pkA is an ed25519 pubkey +func PubKeyAddr(pkA *codectypes.Any) ([]byte, error) { + pk, err := PubKey(pkA) + if err != nil { + return nil, err + } + return pk.Address(), nil +} + +func Valset(pubKey cryptotypes.PubKey) (*comettypes.ValidatorSet, error) { + // convert the pubkey to tmPubKey + tmPubKey, err := cryptocodec.ToTmPubKeyInterface(pubKey) + if err != nil { + return nil, errorsmod.Wrap(err, "tm pub key") + } + + val := comettypes.NewValidator(tmPubKey, 1) + + return comettypes.ValidatorSetFromExistingValidators([]*comettypes.Validator{ + val, + }) +} + +func ValsetHash(pubKey cryptotypes.PubKey) ([]byte, error) { + vs, err := Valset(pubKey) + if err != nil { + return nil, err + } + return vs.Hash(), nil } diff --git a/x/sequencer/types/sequencer.pb.go b/x/sequencer/types/sequencer.pb.go index ea69bee45..d427d376e 100644 --- a/x/sequencer/types/sequencer.pb.go +++ b/x/sequencer/types/sequencer.pb.go @@ -35,27 +35,23 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // Sequencer defines a sequencer identified by its' address (sequencerAddress). // The sequencer could be attached to only one rollapp (rollappId). type Sequencer struct { - // address is the bech32-encoded address of the sequencer account which is the account that the message was sent from. + // Address is the bech32-encoded address of the sequencer account which is the account that the message was sent from. Address string `protobuf:"bytes,1,opt,name=address,proto3" json:"address,omitempty"` - // pubkey is the public key of the sequencers' dymint client, as a Protobuf Any. + // DymintPubKey is the public key of the sequencers' dymint client, as a Protobuf Any. DymintPubKey *types.Any `protobuf:"bytes,2,opt,name=dymintPubKey,proto3" json:"dymintPubKey,omitempty"` - // rollappId defines the rollapp to which the sequencer belongs. + // RollappId defines the rollapp to which the sequencer belongs. RollappId string `protobuf:"bytes,3,opt,name=rollappId,proto3" json:"rollappId,omitempty"` - // metadata defines the extra information for the sequencer. + // SequencerMetadata defines the extra information for the sequencer. Metadata SequencerMetadata `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata"` - // jailed defined whether the sequencer has been jailed from bonded status or not. - Jailed bool `protobuf:"varint,5,opt,name=jailed,proto3" json:"jailed,omitempty"` - Proposer bool `protobuf:"varint,6,opt,name=proposer,proto3" json:"proposer,omitempty"` // Deprecated: Do not use. - // status is the sequencer status (bonded/unbonding/unbonded). + Proposer bool `protobuf:"varint,6,opt,name=proposer,proto3" json:"proposer,omitempty"` // Deprecated: Do not use. + // OperatingStatus is the sequencer status (bonded/unbonded). Status OperatingStatus `protobuf:"varint,7,opt,name=status,proto3,enum=dymensionxyz.dymension.sequencer.OperatingStatus" json:"status,omitempty"` - // tokens define the delegated tokens (incl. self-delegation). + // OptedIn : when true and bonded, the sequencer can be chosen as proposer or successor + // has no effect if already proposer or successor + OptedIn bool `protobuf:"varint,14,opt,name=opted_in,json=optedIn,proto3" json:"opted_in,omitempty"` + // Tokens: A coins which should always be one dym coin. It's the amount of tokens the sequencer has given to the module. Tokens github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,8,rep,name=tokens,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"tokens"` - // unbond_request_height stores the height at which this sequencer has - // requested to unbond. - UnbondRequestHeight int64 `protobuf:"varint,9,opt,name=unbond_request_height,json=unbondRequestHeight,proto3" json:"unbond_request_height,omitempty"` - // unbond_time defines the time when the sequencer will complete unbonding. - UnbondTime time.Time `protobuf:"bytes,10,opt,name=unbond_time,json=unbondTime,proto3,stdtime" json:"unbond_time"` - // notice_period_time defines the time when the sequencer will finish it's notice period if started + // NoticePeriodTime defines the time when the sequencer will finish it's notice period. Zero means not started. NoticePeriodTime time.Time `protobuf:"bytes,11,opt,name=notice_period_time,json=noticePeriodTime,proto3,stdtime" json:"notice_period_time"` // RewardAddr is a bech32 encoded sdk acc address RewardAddr string `protobuf:"bytes,12,opt,name=reward_addr,json=rewardAddr,proto3" json:"reward_addr,omitempty"` @@ -124,13 +120,6 @@ func (m *Sequencer) GetMetadata() SequencerMetadata { return SequencerMetadata{} } -func (m *Sequencer) GetJailed() bool { - if m != nil { - return m.Jailed - } - return false -} - // Deprecated: Do not use. func (m *Sequencer) GetProposer() bool { if m != nil { @@ -146,25 +135,18 @@ func (m *Sequencer) GetStatus() OperatingStatus { return Unbonded } -func (m *Sequencer) GetTokens() github_com_cosmos_cosmos_sdk_types.Coins { - if m != nil { - return m.Tokens - } - return nil -} - -func (m *Sequencer) GetUnbondRequestHeight() int64 { +func (m *Sequencer) GetOptedIn() bool { if m != nil { - return m.UnbondRequestHeight + return m.OptedIn } - return 0 + return false } -func (m *Sequencer) GetUnbondTime() time.Time { +func (m *Sequencer) GetTokens() github_com_cosmos_cosmos_sdk_types.Coins { if m != nil { - return m.UnbondTime + return m.Tokens } - return time.Time{} + return nil } func (m *Sequencer) GetNoticePeriodTime() time.Time { @@ -188,73 +170,8 @@ func (m *Sequencer) GetWhitelistedRelayers() []string { return nil } -// BondReduction defines an object which holds the information about the sequencer and its queued unbonding amount -type BondReduction struct { - // sequencer_address is the bech32-encoded address of the sequencer account which is the account that the message was sent from. - SequencerAddress string `protobuf:"bytes,1,opt,name=sequencer_address,json=sequencerAddress,proto3" json:"sequencer_address,omitempty"` - // decrease_bond_amount is the amount of tokens to be unbonded. - DecreaseBondAmount types1.Coin `protobuf:"bytes,2,opt,name=decrease_bond_amount,json=decreaseBondAmount,proto3" json:"decrease_bond_amount"` - // decrease_bond_time defines, if unbonding, the min time for the sequencer to complete unbonding. - DecreaseBondTime time.Time `protobuf:"bytes,3,opt,name=decrease_bond_time,json=decreaseBondTime,proto3,stdtime" json:"decrease_bond_time"` -} - -func (m *BondReduction) Reset() { *m = BondReduction{} } -func (m *BondReduction) String() string { return proto.CompactTextString(m) } -func (*BondReduction) ProtoMessage() {} -func (*BondReduction) Descriptor() ([]byte, []int) { - return fileDescriptor_997b8663a5fc0f58, []int{1} -} -func (m *BondReduction) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *BondReduction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_BondReduction.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 *BondReduction) XXX_Merge(src proto.Message) { - xxx_messageInfo_BondReduction.Merge(m, src) -} -func (m *BondReduction) XXX_Size() int { - return m.Size() -} -func (m *BondReduction) XXX_DiscardUnknown() { - xxx_messageInfo_BondReduction.DiscardUnknown(m) -} - -var xxx_messageInfo_BondReduction proto.InternalMessageInfo - -func (m *BondReduction) GetSequencerAddress() string { - if m != nil { - return m.SequencerAddress - } - return "" -} - -func (m *BondReduction) GetDecreaseBondAmount() types1.Coin { - if m != nil { - return m.DecreaseBondAmount - } - return types1.Coin{} -} - -func (m *BondReduction) GetDecreaseBondTime() time.Time { - if m != nil { - return m.DecreaseBondTime - } - return time.Time{} -} - func init() { proto.RegisterType((*Sequencer)(nil), "dymensionxyz.dymension.sequencer.Sequencer") - proto.RegisterType((*BondReduction)(nil), "dymensionxyz.dymension.sequencer.BondReduction") } func init() { @@ -262,51 +179,45 @@ func init() { } var fileDescriptor_997b8663a5fc0f58 = []byte{ - // 695 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x41, 0x6f, 0xd3, 0x3e, - 0x1c, 0x6d, 0xd6, 0xad, 0x6b, 0xdd, 0xed, 0xaf, 0xfd, 0xbd, 0x02, 0xde, 0x84, 0xd2, 0x68, 0xa7, - 0x48, 0x68, 0xc9, 0xda, 0x49, 0x70, 0x6e, 0x11, 0x12, 0x13, 0x42, 0x8c, 0x0c, 0x2e, 0x5c, 0x22, - 0x37, 0x31, 0x69, 0x58, 0x63, 0x07, 0xdb, 0xd9, 0x16, 0x3e, 0xc5, 0x3e, 0x07, 0x67, 0x3e, 0xc4, - 0xc4, 0x69, 0x47, 0x4e, 0x0c, 0xad, 0x9f, 0x82, 0x1b, 0x8a, 0xe3, 0x66, 0x1d, 0x08, 0xaa, 0x9d, - 0x92, 0x9f, 0x9f, 0xdf, 0xcb, 0xef, 0xf7, 0xfc, 0x1c, 0xb0, 0x17, 0xe6, 0x09, 0xa1, 0x22, 0x66, - 0xf4, 0x2c, 0xff, 0xe4, 0x56, 0x85, 0x2b, 0xc8, 0xc7, 0x8c, 0xd0, 0x80, 0xf0, 0x9b, 0x37, 0x27, - 0xe5, 0x4c, 0x32, 0x68, 0xcd, 0x33, 0x9c, 0xaa, 0x70, 0xaa, 0x7d, 0xdb, 0x5b, 0x01, 0x13, 0x09, - 0x13, 0xbe, 0xda, 0xef, 0x96, 0x45, 0x49, 0xde, 0xde, 0x8a, 0x18, 0x8b, 0x26, 0xc4, 0x55, 0xd5, - 0x28, 0x7b, 0xef, 0x62, 0x9a, 0x6b, 0xa8, 0x13, 0xb1, 0x88, 0x95, 0x94, 0xe2, 0x4d, 0xaf, 0x76, - 0x7f, 0x27, 0xc8, 0x38, 0x21, 0x42, 0xe2, 0x24, 0xd5, 0x1b, 0xcc, 0x52, 0xdf, 0x1d, 0x61, 0x41, - 0xdc, 0x93, 0xde, 0x88, 0x48, 0xdc, 0x73, 0x03, 0x16, 0x53, 0x8d, 0x3f, 0xd0, 0x78, 0x22, 0x22, - 0xf7, 0xa4, 0x57, 0x3c, 0x34, 0xe0, 0x2e, 0x9c, 0x3c, 0x21, 0x12, 0x87, 0x58, 0x62, 0x4d, 0x78, - 0xb2, 0x90, 0xc0, 0x52, 0xc2, 0xb1, 0x8c, 0x69, 0xe4, 0x0b, 0x89, 0x65, 0xa6, 0x87, 0xde, 0xf9, - 0xb9, 0x02, 0x5a, 0x47, 0xb3, 0x4d, 0x10, 0x81, 0x55, 0x1c, 0x86, 0x9c, 0x08, 0x81, 0x0c, 0xcb, - 0xb0, 0x5b, 0xde, 0xac, 0x84, 0x1e, 0x58, 0x0b, 0xf3, 0x24, 0xa6, 0xf2, 0x30, 0x1b, 0xbd, 0x20, - 0x39, 0x5a, 0xb2, 0x0c, 0xbb, 0xdd, 0xef, 0x38, 0xa5, 0x05, 0xce, 0xcc, 0x02, 0x67, 0x40, 0xf3, - 0x21, 0xfa, 0xfa, 0x65, 0xb7, 0xa3, 0xad, 0x0d, 0x78, 0x9e, 0x4a, 0xe6, 0x94, 0x2c, 0xef, 0x96, - 0x06, 0x7c, 0x08, 0x5a, 0x9c, 0x4d, 0x26, 0x38, 0x4d, 0x0f, 0x42, 0x54, 0x57, 0xdf, 0xbb, 0x59, - 0x80, 0x6f, 0x41, 0x73, 0x36, 0x24, 0x5a, 0x56, 0x5f, 0xdb, 0x77, 0x16, 0x1d, 0xaf, 0x53, 0x8d, - 0xf2, 0x52, 0x53, 0x87, 0xcb, 0x17, 0xdf, 0xbb, 0x35, 0xaf, 0x92, 0x82, 0xf7, 0x41, 0xe3, 0x03, - 0x8e, 0x27, 0x24, 0x44, 0x2b, 0x96, 0x61, 0x37, 0x3d, 0x5d, 0x41, 0x13, 0x34, 0x53, 0xce, 0x52, - 0x26, 0x08, 0x47, 0x8d, 0x02, 0x19, 0x2e, 0x21, 0xc3, 0xab, 0xd6, 0xe0, 0x01, 0x68, 0x94, 0xc6, - 0xa1, 0x55, 0xcb, 0xb0, 0xff, 0xeb, 0xf7, 0x16, 0x37, 0xf3, 0x6a, 0x66, 0xf9, 0x91, 0x22, 0x7a, - 0x5a, 0x00, 0x06, 0xa0, 0x21, 0xd9, 0x31, 0xa1, 0x02, 0x35, 0xad, 0xba, 0xdd, 0xee, 0x6f, 0x39, - 0xda, 0xac, 0x22, 0x27, 0x8e, 0xce, 0x89, 0xf3, 0x94, 0xc5, 0x74, 0xb8, 0x57, 0x74, 0xff, 0xf9, - 0xaa, 0x6b, 0x47, 0xb1, 0x1c, 0x67, 0x23, 0x27, 0x60, 0x89, 0x0e, 0xad, 0x7e, 0xec, 0x8a, 0xf0, - 0xd8, 0x95, 0x79, 0x4a, 0x84, 0x22, 0x08, 0x4f, 0x4b, 0xc3, 0x3e, 0xb8, 0x97, 0xd1, 0x11, 0xa3, - 0xa1, 0xcf, 0x8b, 0x86, 0x84, 0xf4, 0xc7, 0x24, 0x8e, 0xc6, 0x12, 0xb5, 0x2c, 0xc3, 0xae, 0x7b, - 0x9b, 0x25, 0xe8, 0x95, 0xd8, 0x73, 0x05, 0xc1, 0x67, 0xa0, 0xad, 0x39, 0x45, 0x92, 0x11, 0x50, - 0xae, 0x6f, 0xff, 0x71, 0xc6, 0x6f, 0x66, 0x31, 0x1f, 0x36, 0x8b, 0xf6, 0xce, 0xaf, 0xba, 0x86, - 0x07, 0x4a, 0x62, 0x01, 0x41, 0x0f, 0x40, 0xca, 0x64, 0x1c, 0x10, 0x3f, 0x25, 0x3c, 0x66, 0x5a, - 0xad, 0x7d, 0x07, 0xb5, 0x8d, 0x92, 0x7f, 0xa8, 0xe8, 0x4a, 0xb3, 0x0b, 0xda, 0x9c, 0x9c, 0x62, - 0x1e, 0xfa, 0x45, 0x22, 0xd1, 0x9a, 0x4a, 0x0b, 0x28, 0x97, 0x06, 0x61, 0xc8, 0x61, 0x0f, 0x74, - 0x4e, 0xc7, 0xb1, 0x24, 0x93, 0x58, 0x48, 0x52, 0x0c, 0x3d, 0xc1, 0x39, 0xe1, 0x02, 0xad, 0x5b, - 0x75, 0xbb, 0xe5, 0x6d, 0xce, 0x61, 0x9e, 0x86, 0x76, 0xa6, 0x06, 0x58, 0x1f, 0x2a, 0x13, 0xc2, - 0x2c, 0x90, 0x31, 0xa3, 0xf0, 0x11, 0xf8, 0xbf, 0x3a, 0x3e, 0xff, 0xf6, 0x4d, 0xd8, 0xa8, 0x80, - 0x81, 0xbe, 0x12, 0xaf, 0x41, 0x27, 0x24, 0x01, 0x27, 0x58, 0x10, 0x5f, 0x99, 0x86, 0x13, 0x96, - 0x51, 0xa9, 0xaf, 0xc6, 0x3f, 0x0e, 0xb5, 0x8c, 0x24, 0x9c, 0x91, 0x8b, 0x16, 0x06, 0x8a, 0x5a, - 0x38, 0x77, 0x5b, 0x52, 0x39, 0x57, 0xbf, 0x8b, 0x73, 0xf3, 0xaa, 0xc5, 0x86, 0xe1, 0xe1, 0xc5, - 0xb5, 0x69, 0x5c, 0x5e, 0x9b, 0xc6, 0x8f, 0x6b, 0xd3, 0x38, 0x9f, 0x9a, 0xb5, 0xcb, 0xa9, 0x59, - 0xfb, 0x36, 0x35, 0x6b, 0xef, 0x1e, 0xcf, 0x85, 0xea, 0x2f, 0xff, 0x8f, 0x93, 0x7d, 0xf7, 0x6c, - 0xee, 0x27, 0xa2, 0x82, 0x36, 0x6a, 0xa8, 0x0e, 0xf6, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x05, - 0x14, 0xe1, 0x41, 0xa0, 0x05, 0x00, 0x00, + // 597 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x52, 0xcd, 0x4e, 0x1b, 0x3d, + 0x14, 0xcd, 0x40, 0x08, 0x13, 0x87, 0x0f, 0x45, 0xfe, 0x22, 0xd5, 0x41, 0xd5, 0x64, 0xd4, 0xd5, + 0x6c, 0xf0, 0x10, 0x90, 0xda, 0x35, 0xe9, 0x0a, 0xaa, 0xaa, 0x68, 0x68, 0x37, 0xdd, 0x44, 0xce, + 0xd8, 0x1d, 0x2c, 0x32, 0xf6, 0xd4, 0x76, 0x80, 0xe9, 0x53, 0x20, 0xf5, 0x2d, 0xba, 0xee, 0x43, + 0xa0, 0xae, 0x58, 0x76, 0x55, 0x2a, 0x78, 0x91, 0x6a, 0x3c, 0x4e, 0x48, 0x5b, 0x55, 0x59, 0xd9, + 0xf7, 0xe7, 0xdc, 0xab, 0x73, 0xee, 0x01, 0x7b, 0xb4, 0xcc, 0x99, 0xd0, 0x5c, 0x8a, 0xab, 0xf2, + 0x53, 0xbc, 0x08, 0x62, 0xcd, 0x3e, 0xce, 0x98, 0x48, 0x99, 0x7a, 0xfc, 0xe1, 0x42, 0x49, 0x23, + 0x61, 0xb8, 0x8c, 0xc0, 0x8b, 0x00, 0x2f, 0xfa, 0x76, 0xfa, 0xa9, 0xd4, 0xb9, 0xd4, 0x63, 0xdb, + 0x1f, 0xd7, 0x41, 0x0d, 0xde, 0xe9, 0x67, 0x52, 0x66, 0x53, 0x16, 0xdb, 0x68, 0x32, 0xfb, 0x10, + 0x13, 0x51, 0xba, 0x52, 0x2f, 0x93, 0x99, 0xac, 0x21, 0xd5, 0xcf, 0x65, 0x07, 0x7f, 0x02, 0x0c, + 0xcf, 0x99, 0x36, 0x24, 0x2f, 0x5c, 0x43, 0x50, 0xcf, 0x8f, 0x27, 0x44, 0xb3, 0xf8, 0x62, 0x38, + 0x61, 0x86, 0x0c, 0xe3, 0x54, 0x72, 0xe1, 0xea, 0x4f, 0x5c, 0x3d, 0xd7, 0x59, 0x7c, 0x31, 0xac, + 0x1e, 0x57, 0x88, 0x57, 0x32, 0xcf, 0x99, 0x21, 0x94, 0x18, 0xe2, 0x00, 0x2f, 0x56, 0x02, 0x64, + 0xc1, 0x14, 0x31, 0x5c, 0x64, 0x63, 0x6d, 0x88, 0x99, 0x39, 0xd2, 0xcf, 0x3e, 0x6f, 0x80, 0xf6, + 0xe9, 0xbc, 0x09, 0x22, 0xb0, 0x49, 0x28, 0x55, 0x4c, 0x6b, 0xe4, 0x85, 0x5e, 0xd4, 0x4e, 0xe6, + 0x21, 0x4c, 0xc0, 0x16, 0x2d, 0x73, 0x2e, 0xcc, 0xc9, 0x6c, 0xf2, 0x8a, 0x95, 0x68, 0x2d, 0xf4, + 0xa2, 0xce, 0x7e, 0x0f, 0xd7, 0x12, 0xe0, 0xb9, 0x04, 0xf8, 0x50, 0x94, 0x23, 0xf4, 0xed, 0xeb, + 0x6e, 0xcf, 0x49, 0x9b, 0xaa, 0xb2, 0x30, 0x12, 0xd7, 0xa8, 0xe4, 0xb7, 0x19, 0xf0, 0x29, 0x68, + 0x2b, 0x39, 0x9d, 0x92, 0xa2, 0x38, 0xa2, 0x68, 0xdd, 0xee, 0x7b, 0x4c, 0xc0, 0x77, 0xc0, 0x9f, + 0x93, 0x44, 0x4d, 0xbb, 0xed, 0x00, 0xaf, 0x3a, 0x2f, 0x5e, 0x50, 0x79, 0xed, 0xa0, 0xa3, 0xe6, + 0xcd, 0x8f, 0x41, 0x23, 0x59, 0x8c, 0x82, 0x01, 0xf0, 0x0b, 0x25, 0x0b, 0xa9, 0x99, 0x42, 0xad, + 0xd0, 0x8b, 0xfc, 0xd1, 0x1a, 0xf2, 0x92, 0x45, 0x0e, 0x1e, 0x81, 0x56, 0x2d, 0x10, 0xda, 0x0c, + 0xbd, 0x68, 0x7b, 0x7f, 0xb8, 0x7a, 0xe9, 0x9b, 0xb9, 0xb4, 0xa7, 0x16, 0x98, 0xb8, 0x01, 0xb0, + 0x0f, 0x7c, 0x59, 0x18, 0x46, 0xc7, 0x5c, 0xa0, 0xed, 0x6a, 0x55, 0xb2, 0x69, 0xe3, 0x23, 0x01, + 0x53, 0xd0, 0x32, 0xf2, 0x9c, 0x09, 0x8d, 0xfc, 0x70, 0x3d, 0xea, 0xec, 0xf7, 0xb1, 0xd3, 0xab, + 0xb2, 0x0a, 0x76, 0x56, 0xc1, 0x2f, 0x25, 0x17, 0xa3, 0xbd, 0x8a, 0xc0, 0x97, 0xbb, 0x41, 0x94, + 0x71, 0x73, 0x36, 0x9b, 0xe0, 0x54, 0xe6, 0xce, 0xb7, 0xee, 0xd9, 0xd5, 0xf4, 0x3c, 0x36, 0x65, + 0xc1, 0xb4, 0x05, 0xe8, 0xc4, 0x8d, 0x86, 0x09, 0x80, 0x42, 0x1a, 0x9e, 0xb2, 0x71, 0xc1, 0x14, + 0x97, 0x74, 0x5c, 0xf9, 0x13, 0x75, 0xac, 0x96, 0x3b, 0x7f, 0x5d, 0xee, 0xed, 0xdc, 0xbc, 0x23, + 0xbf, 0xda, 0x78, 0x7d, 0x37, 0xf0, 0x92, 0x6e, 0x8d, 0x3f, 0xb1, 0xf0, 0xaa, 0x01, 0x0e, 0x40, + 0x47, 0xb1, 0x4b, 0xa2, 0xe8, 0xb8, 0x72, 0x06, 0xda, 0xb2, 0x57, 0x03, 0x75, 0xea, 0x90, 0x52, + 0x05, 0x87, 0xa0, 0x77, 0x79, 0xc6, 0x0d, 0x9b, 0x72, 0x5d, 0x51, 0x57, 0x6c, 0x4a, 0x4a, 0xa6, + 0x34, 0xfa, 0x2f, 0x5c, 0x8f, 0xda, 0xc9, 0xff, 0x4b, 0xb5, 0xc4, 0x95, 0x8e, 0x9b, 0xfe, 0x46, + 0xb7, 0x75, 0xdc, 0xf4, 0xdb, 0x5d, 0x70, 0xdc, 0xf4, 0x41, 0xb7, 0x33, 0x3a, 0xb9, 0xb9, 0x0f, + 0xbc, 0xdb, 0xfb, 0xc0, 0xfb, 0x79, 0x1f, 0x78, 0xd7, 0x0f, 0x41, 0xe3, 0xf6, 0x21, 0x68, 0x7c, + 0x7f, 0x08, 0x1a, 0xef, 0x9f, 0x2f, 0xa9, 0xf0, 0x0f, 0xcf, 0x5f, 0x1c, 0xc4, 0x57, 0x4b, 0xc6, + 0xb7, 0xca, 0x4c, 0x5a, 0x96, 0xe7, 0xc1, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4c, 0x22, 0x5c, + 0x9a, 0x54, 0x04, 0x00, 0x00, } func (m *Sequencer) Marshal() (dAtA []byte, err error) { @@ -329,6 +240,16 @@ func (m *Sequencer) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.OptedIn { + i-- + if m.OptedIn { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x70 + } if len(m.WhitelistedRelayers) > 0 { for iNdEx := len(m.WhitelistedRelayers) - 1; iNdEx >= 0; iNdEx-- { i -= len(m.WhitelistedRelayers[iNdEx]) @@ -353,19 +274,6 @@ func (m *Sequencer) MarshalToSizedBuffer(dAtA []byte) (int, error) { i = encodeVarintSequencer(dAtA, i, uint64(n1)) i-- dAtA[i] = 0x5a - n2, err2 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.UnbondTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.UnbondTime):]) - if err2 != nil { - return 0, err2 - } - i -= n2 - i = encodeVarintSequencer(dAtA, i, uint64(n2)) - i-- - dAtA[i] = 0x52 - if m.UnbondRequestHeight != 0 { - i = encodeVarintSequencer(dAtA, i, uint64(m.UnbondRequestHeight)) - i-- - dAtA[i] = 0x48 - } if len(m.Tokens) > 0 { for iNdEx := len(m.Tokens) - 1; iNdEx >= 0; iNdEx-- { { @@ -395,16 +303,6 @@ func (m *Sequencer) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x30 } - if m.Jailed { - i-- - if m.Jailed { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x28 - } { size, err := m.Metadata.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -444,54 +342,6 @@ func (m *Sequencer) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *BondReduction) 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 *BondReduction) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *BondReduction) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - n5, err5 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.DecreaseBondTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.DecreaseBondTime):]) - if err5 != nil { - return 0, err5 - } - i -= n5 - i = encodeVarintSequencer(dAtA, i, uint64(n5)) - i-- - dAtA[i] = 0x1a - { - size, err := m.DecreaseBondAmount.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintSequencer(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x12 - if len(m.SequencerAddress) > 0 { - i -= len(m.SequencerAddress) - copy(dAtA[i:], m.SequencerAddress) - i = encodeVarintSequencer(dAtA, i, uint64(len(m.SequencerAddress))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func encodeVarintSequencer(dAtA []byte, offset int, v uint64) int { offset -= sovSequencer(v) base := offset @@ -523,9 +373,6 @@ func (m *Sequencer) Size() (n int) { } l = m.Metadata.Size() n += 1 + l + sovSequencer(uint64(l)) - if m.Jailed { - n += 2 - } if m.Proposer { n += 2 } @@ -538,11 +385,6 @@ func (m *Sequencer) Size() (n int) { n += 1 + l + sovSequencer(uint64(l)) } } - if m.UnbondRequestHeight != 0 { - n += 1 + sovSequencer(uint64(m.UnbondRequestHeight)) - } - l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.UnbondTime) - n += 1 + l + sovSequencer(uint64(l)) l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.NoticePeriodTime) n += 1 + l + sovSequencer(uint64(l)) l = len(m.RewardAddr) @@ -555,23 +397,9 @@ func (m *Sequencer) Size() (n int) { n += 1 + l + sovSequencer(uint64(l)) } } - return n -} - -func (m *BondReduction) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.SequencerAddress) - if l > 0 { - n += 1 + l + sovSequencer(uint64(l)) + if m.OptedIn { + n += 2 } - l = m.DecreaseBondAmount.Size() - n += 1 + l + sovSequencer(uint64(l)) - l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.DecreaseBondTime) - n += 1 + l + sovSequencer(uint64(l)) return n } @@ -743,26 +571,6 @@ func (m *Sequencer) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Jailed", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSequencer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.Jailed = bool(v != 0) case 6: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field Proposer", wireType) @@ -836,58 +644,6 @@ func (m *Sequencer) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - case 9: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field UnbondRequestHeight", wireType) - } - m.UnbondRequestHeight = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSequencer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.UnbondRequestHeight |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 10: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UnbondTime", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSequencer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthSequencer - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthSequencer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.UnbondTime, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex case 11: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field NoticePeriodTime", wireType) @@ -985,126 +741,11 @@ func (m *Sequencer) Unmarshal(dAtA []byte) error { } m.WhitelistedRelayers = append(m.WhitelistedRelayers, string(dAtA[iNdEx:postIndex])) iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipSequencer(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthSequencer - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *BondReduction) 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 ErrIntOverflowSequencer - } - 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: BondReduction: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: BondReduction: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SequencerAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSequencer - } - 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 ErrInvalidLengthSequencer - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthSequencer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SequencerAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DecreaseBondAmount", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowSequencer - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthSequencer - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthSequencer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := m.DecreaseBondAmount.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field DecreaseBondTime", wireType) + case 14: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OptedIn", wireType) } - var msglen int + var v int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowSequencer @@ -1114,25 +755,12 @@ func (m *BondReduction) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + v |= int(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { - return ErrInvalidLengthSequencer - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthSequencer - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.DecreaseBondTime, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex + m.OptedIn = bool(v != 0) default: iNdEx = preIndex skippy, err := skipSequencer(dAtA[iNdEx:]) diff --git a/x/sequencer/types/status.go b/x/sequencer/types/status.go new file mode 100644 index 000000000..cd83471b3 --- /dev/null +++ b/x/sequencer/types/status.go @@ -0,0 +1,6 @@ +package types + +var AllStatus = []OperatingStatus{ + Unbonded, + Bonded, +} diff --git a/x/sequencer/types/tx.pb.go b/x/sequencer/types/tx.pb.go index 744586c32..35d925089 100644 --- a/x/sequencer/types/tx.pb.go +++ b/x/sequencer/types/tx.pb.go @@ -268,6 +268,88 @@ func (m *MsgCreateSequencerResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgCreateSequencerResponse proto.InternalMessageInfo +// Try to kick the current proposer whose bond is below kick threshold +type MsgKickProposer struct { + // creator is the bech32-encoded address of the sequencer account which is the account that the message was sent from. + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` +} + +func (m *MsgKickProposer) Reset() { *m = MsgKickProposer{} } +func (m *MsgKickProposer) String() string { return proto.CompactTextString(m) } +func (*MsgKickProposer) ProtoMessage() {} +func (*MsgKickProposer) Descriptor() ([]byte, []int) { + return fileDescriptor_02cdd6b9ffa005b4, []int{4} +} +func (m *MsgKickProposer) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgKickProposer) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgKickProposer.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 *MsgKickProposer) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgKickProposer.Merge(m, src) +} +func (m *MsgKickProposer) XXX_Size() int { + return m.Size() +} +func (m *MsgKickProposer) XXX_DiscardUnknown() { + xxx_messageInfo_MsgKickProposer.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgKickProposer proto.InternalMessageInfo + +func (m *MsgKickProposer) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +type MsgKickProposerResponse struct { +} + +func (m *MsgKickProposerResponse) Reset() { *m = MsgKickProposerResponse{} } +func (m *MsgKickProposerResponse) String() string { return proto.CompactTextString(m) } +func (*MsgKickProposerResponse) ProtoMessage() {} +func (*MsgKickProposerResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_02cdd6b9ffa005b4, []int{5} +} +func (m *MsgKickProposerResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgKickProposerResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgKickProposerResponse.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 *MsgKickProposerResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgKickProposerResponse.Merge(m, src) +} +func (m *MsgKickProposerResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgKickProposerResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgKickProposerResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgKickProposerResponse proto.InternalMessageInfo + type MsgUpdateSequencerInformation struct { // creator is the bech32-encoded address of the sequencer account which is the account that the message was sent from. Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` @@ -279,7 +361,7 @@ func (m *MsgUpdateSequencerInformation) Reset() { *m = MsgUpdateSequence func (m *MsgUpdateSequencerInformation) String() string { return proto.CompactTextString(m) } func (*MsgUpdateSequencerInformation) ProtoMessage() {} func (*MsgUpdateSequencerInformation) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{4} + return fileDescriptor_02cdd6b9ffa005b4, []int{6} } func (m *MsgUpdateSequencerInformation) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -329,7 +411,7 @@ func (m *MsgUpdateSequencerInformationResponse) Reset() { *m = MsgUpdate func (m *MsgUpdateSequencerInformationResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateSequencerInformationResponse) ProtoMessage() {} func (*MsgUpdateSequencerInformationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{5} + return fileDescriptor_02cdd6b9ffa005b4, []int{7} } func (m *MsgUpdateSequencerInformationResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -369,7 +451,7 @@ func (m *MsgUpdateRewardAddress) Reset() { *m = MsgUpdateRewardAddress{} func (m *MsgUpdateRewardAddress) String() string { return proto.CompactTextString(m) } func (*MsgUpdateRewardAddress) ProtoMessage() {} func (*MsgUpdateRewardAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{6} + return fileDescriptor_02cdd6b9ffa005b4, []int{8} } func (m *MsgUpdateRewardAddress) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -419,7 +501,7 @@ func (m *MsgUpdateRewardAddressResponse) Reset() { *m = MsgUpdateRewardA func (m *MsgUpdateRewardAddressResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateRewardAddressResponse) ProtoMessage() {} func (*MsgUpdateRewardAddressResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{7} + return fileDescriptor_02cdd6b9ffa005b4, []int{9} } func (m *MsgUpdateRewardAddressResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -459,7 +541,7 @@ func (m *MsgUpdateWhitelistedRelayers) Reset() { *m = MsgUpdateWhitelist func (m *MsgUpdateWhitelistedRelayers) String() string { return proto.CompactTextString(m) } func (*MsgUpdateWhitelistedRelayers) ProtoMessage() {} func (*MsgUpdateWhitelistedRelayers) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{8} + return fileDescriptor_02cdd6b9ffa005b4, []int{10} } func (m *MsgUpdateWhitelistedRelayers) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -509,7 +591,7 @@ func (m *MsgUpdateWhitelistedRelayersResponse) Reset() { *m = MsgUpdateW func (m *MsgUpdateWhitelistedRelayersResponse) String() string { return proto.CompactTextString(m) } func (*MsgUpdateWhitelistedRelayersResponse) ProtoMessage() {} func (*MsgUpdateWhitelistedRelayersResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{9} + return fileDescriptor_02cdd6b9ffa005b4, []int{11} } func (m *MsgUpdateWhitelistedRelayersResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -538,6 +620,96 @@ func (m *MsgUpdateWhitelistedRelayersResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgUpdateWhitelistedRelayersResponse proto.InternalMessageInfo +type MsgUpdateOptInStatus struct { + // creator is the bech32-encoded address of the sequencer account which is the account that the message was sent from. + Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` + // OptedIn : the new value + OptedIn bool `protobuf:"varint,2,opt,name=opted_in,json=optedIn,proto3" json:"opted_in,omitempty"` +} + +func (m *MsgUpdateOptInStatus) Reset() { *m = MsgUpdateOptInStatus{} } +func (m *MsgUpdateOptInStatus) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateOptInStatus) ProtoMessage() {} +func (*MsgUpdateOptInStatus) Descriptor() ([]byte, []int) { + return fileDescriptor_02cdd6b9ffa005b4, []int{12} +} +func (m *MsgUpdateOptInStatus) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateOptInStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateOptInStatus.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 *MsgUpdateOptInStatus) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateOptInStatus.Merge(m, src) +} +func (m *MsgUpdateOptInStatus) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateOptInStatus) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateOptInStatus.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateOptInStatus proto.InternalMessageInfo + +func (m *MsgUpdateOptInStatus) GetCreator() string { + if m != nil { + return m.Creator + } + return "" +} + +func (m *MsgUpdateOptInStatus) GetOptedIn() bool { + if m != nil { + return m.OptedIn + } + return false +} + +type MsgUpdateOptInStatusResponse struct { +} + +func (m *MsgUpdateOptInStatusResponse) Reset() { *m = MsgUpdateOptInStatusResponse{} } +func (m *MsgUpdateOptInStatusResponse) String() string { return proto.CompactTextString(m) } +func (*MsgUpdateOptInStatusResponse) ProtoMessage() {} +func (*MsgUpdateOptInStatusResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_02cdd6b9ffa005b4, []int{13} +} +func (m *MsgUpdateOptInStatusResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgUpdateOptInStatusResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgUpdateOptInStatusResponse.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 *MsgUpdateOptInStatusResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgUpdateOptInStatusResponse.Merge(m, src) +} +func (m *MsgUpdateOptInStatusResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgUpdateOptInStatusResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgUpdateOptInStatusResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgUpdateOptInStatusResponse proto.InternalMessageInfo + // MsgUnbond defines a SDK message for performing an undelegation from a // bond and a sequencer. type MsgUnbond struct { @@ -548,7 +720,7 @@ func (m *MsgUnbond) Reset() { *m = MsgUnbond{} } func (m *MsgUnbond) String() string { return proto.CompactTextString(m) } func (*MsgUnbond) ProtoMessage() {} func (*MsgUnbond) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{10} + return fileDescriptor_02cdd6b9ffa005b4, []int{14} } func (m *MsgUnbond) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -586,12 +758,8 @@ func (m *MsgUnbond) GetCreator() string { // MsgUnbondResponse defines the Msg/Unbond response type. type MsgUnbondResponse struct { - // completion_time defines the time at which the unbonding will be completed. - // If unbonding the proposer, the completion time is the time at which the notice period will be completed. - // // Types that are valid to be assigned to CompletionTime: // - // *MsgUnbondResponse_UnbondingCompletionTime // *MsgUnbondResponse_NoticePeriodCompletionTime CompletionTime isMsgUnbondResponse_CompletionTime `protobuf_oneof:"completion_time"` } @@ -600,7 +768,7 @@ func (m *MsgUnbondResponse) Reset() { *m = MsgUnbondResponse{} } func (m *MsgUnbondResponse) String() string { return proto.CompactTextString(m) } func (*MsgUnbondResponse) ProtoMessage() {} func (*MsgUnbondResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{11} + return fileDescriptor_02cdd6b9ffa005b4, []int{15} } func (m *MsgUnbondResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -635,14 +803,10 @@ type isMsgUnbondResponse_CompletionTime interface { Size() int } -type MsgUnbondResponse_UnbondingCompletionTime struct { - UnbondingCompletionTime *time.Time `protobuf:"bytes,1,opt,name=unbonding_completion_time,json=unbondingCompletionTime,proto3,oneof,stdtime" json:"unbonding_completion_time,omitempty"` -} type MsgUnbondResponse_NoticePeriodCompletionTime struct { NoticePeriodCompletionTime *time.Time `protobuf:"bytes,2,opt,name=notice_period_completion_time,json=noticePeriodCompletionTime,proto3,oneof,stdtime" json:"notice_period_completion_time,omitempty"` } -func (*MsgUnbondResponse_UnbondingCompletionTime) isMsgUnbondResponse_CompletionTime() {} func (*MsgUnbondResponse_NoticePeriodCompletionTime) isMsgUnbondResponse_CompletionTime() {} func (m *MsgUnbondResponse) GetCompletionTime() isMsgUnbondResponse_CompletionTime { @@ -652,13 +816,6 @@ func (m *MsgUnbondResponse) GetCompletionTime() isMsgUnbondResponse_CompletionTi return nil } -func (m *MsgUnbondResponse) GetUnbondingCompletionTime() *time.Time { - if x, ok := m.GetCompletionTime().(*MsgUnbondResponse_UnbondingCompletionTime); ok { - return x.UnbondingCompletionTime - } - return nil -} - func (m *MsgUnbondResponse) GetNoticePeriodCompletionTime() *time.Time { if x, ok := m.GetCompletionTime().(*MsgUnbondResponse_NoticePeriodCompletionTime); ok { return x.NoticePeriodCompletionTime @@ -669,7 +826,6 @@ func (m *MsgUnbondResponse) GetNoticePeriodCompletionTime() *time.Time { // XXX_OneofWrappers is for the internal use of the proto package. func (*MsgUnbondResponse) XXX_OneofWrappers() []interface{} { return []interface{}{ - (*MsgUnbondResponse_UnbondingCompletionTime)(nil), (*MsgUnbondResponse_NoticePeriodCompletionTime)(nil), } } @@ -686,7 +842,7 @@ func (m *MsgIncreaseBond) Reset() { *m = MsgIncreaseBond{} } func (m *MsgIncreaseBond) String() string { return proto.CompactTextString(m) } func (*MsgIncreaseBond) ProtoMessage() {} func (*MsgIncreaseBond) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{12} + return fileDescriptor_02cdd6b9ffa005b4, []int{16} } func (m *MsgIncreaseBond) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -737,7 +893,7 @@ func (m *MsgIncreaseBondResponse) Reset() { *m = MsgIncreaseBondResponse func (m *MsgIncreaseBondResponse) String() string { return proto.CompactTextString(m) } func (*MsgIncreaseBondResponse) ProtoMessage() {} func (*MsgIncreaseBondResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{13} + return fileDescriptor_02cdd6b9ffa005b4, []int{17} } func (m *MsgIncreaseBondResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -778,7 +934,7 @@ func (m *MsgDecreaseBond) Reset() { *m = MsgDecreaseBond{} } func (m *MsgDecreaseBond) String() string { return proto.CompactTextString(m) } func (*MsgDecreaseBond) ProtoMessage() {} func (*MsgDecreaseBond) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{14} + return fileDescriptor_02cdd6b9ffa005b4, []int{18} } func (m *MsgDecreaseBond) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -823,14 +979,13 @@ func (m *MsgDecreaseBond) GetDecreaseAmount() types1.Coin { // MsgDecreaseBondResponse defines the Msg/DecreaseBond response type. type MsgDecreaseBondResponse struct { - CompletionTime time.Time `protobuf:"bytes,1,opt,name=completion_time,json=completionTime,proto3,stdtime" json:"completion_time"` } func (m *MsgDecreaseBondResponse) Reset() { *m = MsgDecreaseBondResponse{} } func (m *MsgDecreaseBondResponse) String() string { return proto.CompactTextString(m) } func (*MsgDecreaseBondResponse) ProtoMessage() {} func (*MsgDecreaseBondResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_02cdd6b9ffa005b4, []int{15} + return fileDescriptor_02cdd6b9ffa005b4, []int{19} } func (m *MsgDecreaseBondResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -859,24 +1014,21 @@ func (m *MsgDecreaseBondResponse) XXX_DiscardUnknown() { var xxx_messageInfo_MsgDecreaseBondResponse proto.InternalMessageInfo -func (m *MsgDecreaseBondResponse) GetCompletionTime() time.Time { - if m != nil { - return m.CompletionTime - } - return time.Time{} -} - func init() { proto.RegisterType((*MsgUpdateParams)(nil), "dymensionxyz.dymension.sequencer.MsgUpdateParams") proto.RegisterType((*MsgUpdateParamsResponse)(nil), "dymensionxyz.dymension.sequencer.MsgUpdateParamsResponse") proto.RegisterType((*MsgCreateSequencer)(nil), "dymensionxyz.dymension.sequencer.MsgCreateSequencer") proto.RegisterType((*MsgCreateSequencerResponse)(nil), "dymensionxyz.dymension.sequencer.MsgCreateSequencerResponse") + proto.RegisterType((*MsgKickProposer)(nil), "dymensionxyz.dymension.sequencer.MsgKickProposer") + proto.RegisterType((*MsgKickProposerResponse)(nil), "dymensionxyz.dymension.sequencer.MsgKickProposerResponse") proto.RegisterType((*MsgUpdateSequencerInformation)(nil), "dymensionxyz.dymension.sequencer.MsgUpdateSequencerInformation") proto.RegisterType((*MsgUpdateSequencerInformationResponse)(nil), "dymensionxyz.dymension.sequencer.MsgUpdateSequencerInformationResponse") proto.RegisterType((*MsgUpdateRewardAddress)(nil), "dymensionxyz.dymension.sequencer.MsgUpdateRewardAddress") proto.RegisterType((*MsgUpdateRewardAddressResponse)(nil), "dymensionxyz.dymension.sequencer.MsgUpdateRewardAddressResponse") proto.RegisterType((*MsgUpdateWhitelistedRelayers)(nil), "dymensionxyz.dymension.sequencer.MsgUpdateWhitelistedRelayers") proto.RegisterType((*MsgUpdateWhitelistedRelayersResponse)(nil), "dymensionxyz.dymension.sequencer.MsgUpdateWhitelistedRelayersResponse") + proto.RegisterType((*MsgUpdateOptInStatus)(nil), "dymensionxyz.dymension.sequencer.MsgUpdateOptInStatus") + proto.RegisterType((*MsgUpdateOptInStatusResponse)(nil), "dymensionxyz.dymension.sequencer.MsgUpdateOptInStatusResponse") proto.RegisterType((*MsgUnbond)(nil), "dymensionxyz.dymension.sequencer.MsgUnbond") proto.RegisterType((*MsgUnbondResponse)(nil), "dymensionxyz.dymension.sequencer.MsgUnbondResponse") proto.RegisterType((*MsgIncreaseBond)(nil), "dymensionxyz.dymension.sequencer.MsgIncreaseBond") @@ -890,71 +1042,75 @@ func init() { } var fileDescriptor_02cdd6b9ffa005b4 = []byte{ - // 1014 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcb, 0x6f, 0x1b, 0x45, - 0x18, 0xf7, 0x3a, 0x69, 0x1a, 0x7f, 0x89, 0x12, 0xba, 0x8d, 0xc8, 0x7a, 0xd5, 0xd8, 0x96, 0xc5, - 0x23, 0x14, 0x75, 0x57, 0x8e, 0x51, 0x05, 0x11, 0x2a, 0xc4, 0x41, 0xa5, 0x11, 0xb2, 0x14, 0xb6, - 0x54, 0x48, 0x1c, 0xb0, 0xc6, 0x9e, 0xe9, 0x66, 0x91, 0x77, 0x67, 0xd9, 0x19, 0xa7, 0x59, 0xd4, - 0x03, 0x42, 0xe2, 0x4c, 0x11, 0x67, 0x10, 0x08, 0x89, 0x73, 0x0f, 0xfc, 0x11, 0x15, 0xa7, 0x8a, - 0x13, 0x17, 0x1e, 0x4a, 0x0e, 0xe5, 0xc2, 0xff, 0x80, 0x76, 0x77, 0x76, 0x62, 0xaf, 0x1d, 0x3f, - 0x92, 0x9e, 0xda, 0x99, 0xf9, 0x7e, 0x8f, 0xf9, 0x7e, 0x93, 0x2f, 0x1b, 0x78, 0x0d, 0x87, 0x2e, - 0xf1, 0x98, 0x43, 0xbd, 0xa3, 0xf0, 0x0b, 0x53, 0x2e, 0x4c, 0x46, 0x3e, 0xef, 0x11, 0xaf, 0x43, - 0x02, 0x93, 0x1f, 0x19, 0x7e, 0x40, 0x39, 0x55, 0x2b, 0xfd, 0xa5, 0x86, 0x5c, 0x18, 0xb2, 0x54, - 0x2f, 0xda, 0x94, 0xda, 0x5d, 0x62, 0xc6, 0xf5, 0xed, 0xde, 0x7d, 0x13, 0x79, 0x61, 0x02, 0xd6, - 0x8b, 0x1d, 0xca, 0x5c, 0xca, 0x5a, 0xf1, 0xca, 0x4c, 0x16, 0xe2, 0x68, 0xcd, 0xa6, 0x36, 0x4d, - 0xf6, 0xa3, 0xff, 0x89, 0xdd, 0x52, 0x52, 0x63, 0xb6, 0x11, 0x23, 0xe6, 0x61, 0xad, 0x4d, 0x38, - 0xaa, 0x99, 0x1d, 0xea, 0x78, 0xe2, 0xbc, 0x9c, 0xd5, 0xe2, 0x8e, 0x4b, 0x18, 0x47, 0xae, 0x2f, - 0x0a, 0xd6, 0x05, 0x81, 0xcb, 0x6c, 0xf3, 0xb0, 0x16, 0xfd, 0x23, 0x0e, 0x6e, 0x4c, 0xbc, 0xb2, - 0x8f, 0x02, 0xe4, 0xa6, 0xf6, 0xcc, 0x89, 0xe5, 0x2e, 0xe1, 0x08, 0x23, 0x8e, 0x12, 0x40, 0xf5, - 0x27, 0x05, 0x56, 0x9b, 0xcc, 0xbe, 0xe7, 0x63, 0xc4, 0xc9, 0x7e, 0x4c, 0xa5, 0xde, 0x84, 0x02, - 0xea, 0xf1, 0x03, 0x1a, 0x38, 0x3c, 0xd4, 0x94, 0x8a, 0xb2, 0x59, 0x68, 0x68, 0xbf, 0xff, 0x7a, - 0x63, 0x4d, 0x34, 0x62, 0x07, 0xe3, 0x80, 0x30, 0x76, 0x97, 0x07, 0x8e, 0x67, 0x5b, 0xa7, 0xa5, - 0xea, 0x6d, 0x58, 0x48, 0xcc, 0x68, 0xf9, 0x8a, 0xb2, 0xb9, 0xb4, 0xb5, 0x69, 0x4c, 0x0a, 0xc1, - 0x48, 0x14, 0x1b, 0xf3, 0x4f, 0xfe, 0x2a, 0xe7, 0x2c, 0x81, 0xde, 0x5e, 0xf9, 0xea, 0xd9, 0xe3, - 0xeb, 0xa7, 0xbc, 0xd5, 0x22, 0xac, 0x67, 0x2c, 0x5a, 0x84, 0xf9, 0xd4, 0x63, 0xa4, 0xfa, 0xcd, - 0x1c, 0xa8, 0x4d, 0x66, 0xef, 0x06, 0x04, 0x71, 0x72, 0x37, 0xa5, 0x55, 0x35, 0xb8, 0xdc, 0x89, - 0xb6, 0x68, 0x90, 0xf8, 0xb7, 0xd2, 0xa5, 0x6a, 0xc1, 0x32, 0x0e, 0x5d, 0xc7, 0xe3, 0xfb, 0xbd, - 0xf6, 0x07, 0x24, 0x14, 0x4e, 0xd7, 0x8c, 0x24, 0x20, 0x23, 0x0d, 0xc8, 0xd8, 0xf1, 0xc2, 0x86, - 0xf6, 0xdb, 0xe9, 0xa5, 0x3b, 0x41, 0xe8, 0x73, 0x6a, 0x24, 0x28, 0x6b, 0x80, 0x43, 0xdd, 0x00, - 0x08, 0x68, 0xb7, 0x8b, 0x7c, 0xbf, 0xe5, 0x60, 0x6d, 0x2e, 0x16, 0x2c, 0x88, 0x9d, 0x3d, 0xac, - 0xde, 0x83, 0xc5, 0xb4, 0xe9, 0xda, 0x7c, 0x2c, 0x57, 0x9f, 0xdc, 0x18, 0x79, 0x97, 0xa6, 0x80, - 0x8a, 0x1e, 0x49, 0x2a, 0xb5, 0x0e, 0xf3, 0x6d, 0xea, 0x61, 0xed, 0x52, 0x4c, 0x59, 0x34, 0x84, - 0xd1, 0xe8, 0x09, 0x1a, 0xe2, 0x09, 0x1a, 0xbb, 0xd4, 0xf1, 0x04, 0x30, 0x2e, 0x56, 0xcb, 0xb0, - 0x14, 0x90, 0x07, 0x28, 0xc0, 0x2d, 0x84, 0x71, 0xa0, 0x2d, 0xc4, 0x5e, 0x21, 0xd9, 0x8a, 0x72, - 0x55, 0x6b, 0xb0, 0xf6, 0xe0, 0xc0, 0xe1, 0xa4, 0xeb, 0x30, 0x4e, 0x70, 0x2b, 0x20, 0x5d, 0x14, - 0x92, 0x80, 0x69, 0x97, 0x2b, 0x73, 0x9b, 0x05, 0xeb, 0x6a, 0xdf, 0x99, 0x25, 0x8e, 0xb6, 0x97, - 0xa3, 0xb8, 0xd2, 0x06, 0x57, 0xaf, 0x81, 0x3e, 0x1c, 0x88, 0xcc, 0xeb, 0x07, 0x05, 0x36, 0x64, - 0x96, 0xf2, 0x78, 0xcf, 0xbb, 0x4f, 0x03, 0x17, 0x71, 0x87, 0x7a, 0x63, 0xa2, 0xeb, 0xef, 0x63, - 0xfe, 0xb9, 0xf5, 0x31, 0x63, 0xff, 0x55, 0x78, 0x79, 0xac, 0x3f, 0x79, 0x13, 0x04, 0x2f, 0xca, - 0x42, 0x4b, 0xf6, 0x8f, 0x30, 0x36, 0xe6, 0x06, 0x99, 0xee, 0xe7, 0xb3, 0xdd, 0xcf, 0x78, 0xa9, - 0x40, 0x69, 0xb4, 0x84, 0x34, 0xd1, 0x86, 0x6b, 0xb2, 0xe2, 0xe3, 0xe1, 0x68, 0xc6, 0x58, 0xd1, - 0x61, 0x51, 0x66, 0x9b, 0x8f, 0xb3, 0x95, 0xeb, 0x8c, 0x8b, 0x57, 0xe0, 0xa5, 0x71, 0x1a, 0xd2, - 0xcb, 0x87, 0x50, 0x88, 0xea, 0xbc, 0xf8, 0x9d, 0x6d, 0x65, 0x84, 0xc7, 0x0c, 0x90, 0xb4, 0x70, - 0xfb, 0x85, 0x7f, 0x7f, 0x2c, 0xe7, 0x06, 0xa4, 0xff, 0x53, 0xe0, 0x8a, 0xe4, 0x4c, 0x85, 0xd4, - 0x4f, 0xa1, 0xd8, 0x8b, 0x77, 0x1c, 0xcf, 0x6e, 0x75, 0xa8, 0xeb, 0x77, 0x49, 0x94, 0x4c, 0x2b, - 0x9a, 0xa9, 0xb1, 0xda, 0xd2, 0x96, 0x3e, 0xf4, 0xf3, 0xfc, 0x51, 0x3a, 0x70, 0x1b, 0xf3, 0x8f, - 0xfe, 0x2e, 0x2b, 0x77, 0x72, 0xd6, 0xba, 0x24, 0xd9, 0x95, 0x1c, 0x51, 0x95, 0x4a, 0x60, 0xc3, - 0xa3, 0xdc, 0xe9, 0x90, 0x96, 0x4f, 0x02, 0x87, 0xe2, 0x21, 0x8d, 0xfc, 0xd4, 0x1a, 0x7a, 0x42, - 0xb4, 0x1f, 0xf3, 0x0c, 0xca, 0x34, 0xae, 0xc0, 0x6a, 0x86, 0xb8, 0xfa, 0x5d, 0x32, 0x8c, 0xf7, - 0xbc, 0xa8, 0x01, 0x8c, 0x34, 0xce, 0xd9, 0x49, 0xf5, 0x16, 0x00, 0xc2, 0xb8, 0x85, 0x5c, 0xda, - 0xf3, 0xb8, 0xb0, 0x3b, 0x71, 0x40, 0x14, 0x10, 0xc6, 0x3b, 0x31, 0x22, 0xf3, 0x00, 0x92, 0xf1, - 0xdb, 0x6f, 0x4a, 0x66, 0xfe, 0x7d, 0x62, 0xf8, 0x3d, 0x72, 0x41, 0xc3, 0x77, 0x60, 0x15, 0x0b, - 0x8e, 0x19, 0x5d, 0xaf, 0xa4, 0xb8, 0x91, 0xd6, 0x0f, 0x62, 0xeb, 0xfd, 0xf6, 0xe4, 0x2b, 0x6a, - 0x0e, 0xb5, 0x7f, 0x8a, 0xb7, 0xb3, 0x18, 0x69, 0x46, 0xd9, 0x5a, 0x2b, 0x9d, 0x81, 0x34, 0xb7, - 0xfe, 0x5c, 0x84, 0xb9, 0x26, 0xb3, 0xd5, 0xaf, 0x15, 0x58, 0xcd, 0xfe, 0x36, 0x7a, 0x63, 0xf2, - 0x98, 0x1a, 0x1e, 0x99, 0xfa, 0xdb, 0xe7, 0x41, 0xc9, 0xeb, 0xfd, 0xa2, 0x80, 0x3e, 0x66, 0xca, - 0xbe, 0x33, 0x15, 0xf9, 0xd9, 0x04, 0xfa, 0xfb, 0x17, 0x24, 0x90, 0x46, 0xbf, 0x55, 0xe0, 0xea, - 0xa8, 0x29, 0xfa, 0xe6, 0x0c, 0x02, 0x03, 0x48, 0xfd, 0xdd, 0xf3, 0x22, 0xa5, 0xa7, 0x9f, 0x15, - 0x28, 0x9e, 0x3d, 0x54, 0x6f, 0xcd, 0xc0, 0x3f, 0x02, 0xaf, 0xdf, 0xbe, 0x18, 0x5e, 0xba, 0xfc, - 0x0c, 0x16, 0xc4, 0xb4, 0x7d, 0x7d, 0x3a, 0xc6, 0xb8, 0x58, 0xaf, 0xcf, 0x50, 0x2c, 0xb5, 0x1e, - 0xc2, 0xf2, 0xc0, 0x54, 0xaa, 0x4d, 0x45, 0xd2, 0x0f, 0xd1, 0xdf, 0x9a, 0x19, 0xd2, 0xaf, 0x3e, - 0x30, 0x62, 0xa6, 0x53, 0xef, 0x87, 0x4c, 0xa9, 0x3e, 0x72, 0x52, 0x3c, 0x84, 0xe5, 0x81, 0xcf, - 0xe3, 0xda, 0x0c, 0xf9, 0x25, 0x90, 0x29, 0xd5, 0x47, 0x7d, 0xe1, 0xea, 0x97, 0xbe, 0x7c, 0xf6, - 0xf8, 0xba, 0xd2, 0xd8, 0x7f, 0x72, 0x5c, 0x52, 0x9e, 0x1e, 0x97, 0x94, 0x7f, 0x8e, 0x4b, 0xca, - 0xa3, 0x93, 0x52, 0xee, 0xe9, 0x49, 0x29, 0xf7, 0xc7, 0x49, 0x29, 0xf7, 0xc9, 0x4d, 0xdb, 0xe1, - 0x07, 0xbd, 0xb6, 0xd1, 0xa1, 0xee, 0x59, 0x5f, 0xff, 0x87, 0x75, 0xf3, 0xa8, 0xff, 0x8f, 0xa4, - 0xd0, 0x27, 0xac, 0xbd, 0x10, 0xcf, 0xb7, 0xfa, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x21, 0x97, - 0x23, 0x18, 0x55, 0x0d, 0x00, 0x00, + // 1076 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xcf, 0x6f, 0xdc, 0xc4, + 0x17, 0x5f, 0x27, 0x69, 0x92, 0x7d, 0x8d, 0x9a, 0xc6, 0x8d, 0xbe, 0xf5, 0x5a, 0xcd, 0x6e, 0x14, + 0x7d, 0x81, 0x50, 0x54, 0x5b, 0x9b, 0xa0, 0x88, 0x56, 0xa8, 0x90, 0x0d, 0x2a, 0x5d, 0xaa, 0x88, + 0xc5, 0xa1, 0x42, 0x70, 0x59, 0xcd, 0xae, 0xa7, 0x8e, 0x61, 0x3d, 0x63, 0x3c, 0xb3, 0x69, 0x8c, + 0x7a, 0x40, 0x20, 0xce, 0x14, 0x71, 0x06, 0x81, 0x90, 0x38, 0xf7, 0xc0, 0x1f, 0x51, 0x71, 0xaa, + 0x38, 0x71, 0xe2, 0x47, 0x72, 0x28, 0x7f, 0x06, 0xb2, 0x3d, 0x9e, 0x78, 0xbd, 0x9b, 0xfd, 0x91, + 0x70, 0x4a, 0x66, 0xe6, 0x7d, 0x7e, 0xbc, 0x79, 0x6f, 0xdf, 0xc8, 0xf0, 0xb2, 0x1d, 0x7a, 0x98, + 0x30, 0x97, 0x92, 0xc3, 0xf0, 0x33, 0x53, 0x2e, 0x4c, 0x86, 0x3f, 0xed, 0x62, 0xd2, 0xc6, 0x81, + 0xc9, 0x0f, 0x0d, 0x3f, 0xa0, 0x9c, 0xaa, 0xab, 0xd9, 0x50, 0x43, 0x2e, 0x0c, 0x19, 0xaa, 0x97, + 0x1c, 0x4a, 0x9d, 0x0e, 0x36, 0xe3, 0xf8, 0x56, 0xf7, 0x81, 0x89, 0x48, 0x98, 0x80, 0xf5, 0x52, + 0x9b, 0x32, 0x8f, 0xb2, 0x66, 0xbc, 0x32, 0x93, 0x85, 0x38, 0x5a, 0x76, 0xa8, 0x43, 0x93, 0xfd, + 0xe8, 0x3f, 0xb1, 0x5b, 0x4e, 0x62, 0xcc, 0x16, 0x62, 0xd8, 0x3c, 0xa8, 0xb6, 0x30, 0x47, 0x55, + 0xb3, 0x4d, 0x5d, 0x22, 0xce, 0x2b, 0x79, 0x2d, 0xee, 0x7a, 0x98, 0x71, 0xe4, 0xf9, 0x22, 0xe0, + 0xaa, 0x20, 0xf0, 0x98, 0x63, 0x1e, 0x54, 0xa3, 0x3f, 0xe2, 0xe0, 0xc6, 0xc8, 0x94, 0x7d, 0x14, + 0x20, 0x2f, 0xb5, 0x67, 0x8e, 0x0c, 0xf7, 0x30, 0x47, 0x36, 0xe2, 0x28, 0x01, 0xac, 0xfd, 0xa8, + 0xc0, 0xe2, 0x2e, 0x73, 0xee, 0xfb, 0x36, 0xe2, 0xb8, 0x11, 0x53, 0xa9, 0x5b, 0x50, 0x44, 0x5d, + 0xbe, 0x4f, 0x03, 0x97, 0x87, 0x9a, 0xb2, 0xaa, 0xac, 0x17, 0x6b, 0xda, 0x6f, 0xbf, 0xdc, 0x58, + 0x16, 0x17, 0xb1, 0x6d, 0xdb, 0x01, 0x66, 0x6c, 0x8f, 0x07, 0x2e, 0x71, 0xac, 0x93, 0x50, 0xf5, + 0x0e, 0xcc, 0x26, 0x66, 0xb4, 0xa9, 0x55, 0x65, 0xfd, 0xe2, 0xc6, 0xba, 0x31, 0xaa, 0x08, 0x46, + 0xa2, 0x58, 0x9b, 0x79, 0xfa, 0x47, 0xa5, 0x60, 0x09, 0xf4, 0xad, 0x4b, 0x5f, 0x3c, 0x7f, 0x72, + 0xfd, 0x84, 0x77, 0xad, 0x04, 0x57, 0x73, 0x16, 0x2d, 0xcc, 0x7c, 0x4a, 0x18, 0x5e, 0xfb, 0x7a, + 0x1a, 0xd4, 0x5d, 0xe6, 0xec, 0x04, 0x18, 0x71, 0xbc, 0x97, 0xd2, 0xaa, 0x1a, 0xcc, 0xb5, 0xa3, + 0x2d, 0x1a, 0x24, 0xfe, 0xad, 0x74, 0xa9, 0x5a, 0xb0, 0x60, 0x87, 0x9e, 0x4b, 0x78, 0xa3, 0xdb, + 0xba, 0x87, 0x43, 0xe1, 0x74, 0xd9, 0x48, 0x0a, 0x64, 0xa4, 0x05, 0x32, 0xb6, 0x49, 0x58, 0xd3, + 0x7e, 0x3d, 0x49, 0xba, 0x1d, 0x84, 0x3e, 0xa7, 0x46, 0x82, 0xb2, 0x7a, 0x38, 0xd4, 0x15, 0x80, + 0x80, 0x76, 0x3a, 0xc8, 0xf7, 0x9b, 0xae, 0xad, 0x4d, 0xc7, 0x82, 0x45, 0xb1, 0x53, 0xb7, 0xd5, + 0xfb, 0x30, 0x9f, 0x5e, 0xba, 0x36, 0x13, 0xcb, 0x6d, 0x8e, 0xbe, 0x18, 0x99, 0xcb, 0xae, 0x80, + 0x8a, 0x3b, 0x92, 0x54, 0xea, 0x26, 0xcc, 0xb4, 0x28, 0xb1, 0xb5, 0x0b, 0x31, 0x65, 0xc9, 0x10, + 0x46, 0xa3, 0x16, 0x34, 0x44, 0x0b, 0x1a, 0x3b, 0xd4, 0x25, 0x02, 0x18, 0x07, 0xab, 0x15, 0xb8, + 0x18, 0xe0, 0x87, 0x28, 0xb0, 0x9b, 0xc8, 0xb6, 0x03, 0x6d, 0x36, 0xf6, 0x0a, 0xc9, 0x56, 0x54, + 0x57, 0xb5, 0x0a, 0xcb, 0x0f, 0xf7, 0x5d, 0x8e, 0x3b, 0x2e, 0xe3, 0xd8, 0x6e, 0x06, 0xb8, 0x83, + 0x42, 0x1c, 0x30, 0x6d, 0x6e, 0x75, 0x7a, 0xbd, 0x68, 0x5d, 0xc9, 0x9c, 0x59, 0xe2, 0xe8, 0xd6, + 0x42, 0x54, 0xae, 0xf4, 0x82, 0xd7, 0xae, 0x81, 0xde, 0x5f, 0x10, 0x59, 0xaf, 0x9b, 0x71, 0xb7, + 0xdd, 0x73, 0xdb, 0x9f, 0x34, 0x02, 0xea, 0x53, 0x36, 0xac, 0x56, 0x39, 0xe2, 0xa4, 0x0b, 0xb2, + 0x50, 0xc9, 0xfa, 0xbd, 0x02, 0x2b, 0xb2, 0x43, 0xa4, 0x68, 0x9d, 0x3c, 0xa0, 0x81, 0x87, 0xb8, + 0x4b, 0xc9, 0x90, 0x86, 0xc8, 0x56, 0x67, 0xea, 0x3f, 0xab, 0x4e, 0xce, 0xfb, 0x4b, 0xf0, 0xc2, + 0x50, 0x7f, 0x32, 0x13, 0x04, 0xff, 0x93, 0x81, 0x96, 0xac, 0x0a, 0x66, 0x6c, 0x48, 0x06, 0xb9, + 0x9a, 0x4e, 0xe5, 0x6b, 0x9a, 0xf3, 0xb2, 0x0a, 0xe5, 0xc1, 0x12, 0xd2, 0x44, 0x0b, 0xae, 0xc9, + 0x88, 0x0f, 0xfa, 0x0b, 0x3e, 0xc4, 0x8a, 0x0e, 0xf3, 0xb2, 0x63, 0xa6, 0xe2, 0x8e, 0x91, 0xeb, + 0x9c, 0x8b, 0x17, 0xe1, 0xff, 0xc3, 0x34, 0xa4, 0x97, 0x0f, 0x61, 0x59, 0xc6, 0xbd, 0xeb, 0xf3, + 0x3a, 0xd9, 0xe3, 0x88, 0x77, 0x87, 0x79, 0x28, 0xc1, 0x3c, 0xf5, 0xa3, 0xde, 0x75, 0x49, 0x7c, + 0x17, 0xf3, 0xd6, 0x5c, 0xbc, 0xae, 0x93, 0x9c, 0x85, 0x72, 0x26, 0xcd, 0x0c, 0xb5, 0x94, 0x7e, + 0x0f, 0x8a, 0xd1, 0x39, 0x89, 0x7f, 0x38, 0x1b, 0x39, 0xbd, 0x21, 0x13, 0x51, 0xf6, 0xef, 0xe5, + 0x7f, 0x7e, 0xa8, 0x14, 0x7a, 0x24, 0xbf, 0x55, 0x60, 0x49, 0x72, 0xa6, 0x42, 0x2a, 0x86, 0x15, + 0x42, 0xb9, 0xdb, 0xc6, 0x4d, 0x1f, 0x07, 0x2e, 0xb5, 0x9b, 0x6d, 0xea, 0xf9, 0x1d, 0x1c, 0x35, + 0x46, 0x33, 0x7a, 0x28, 0x44, 0x5f, 0xea, 0x7d, 0x43, 0xea, 0xfd, 0xf4, 0x15, 0xa9, 0xcd, 0x3c, + 0xfe, 0xb3, 0xa2, 0xdc, 0x2d, 0x58, 0x7a, 0x42, 0xd4, 0x88, 0x79, 0x76, 0x24, 0x4d, 0x14, 0x58, + 0x5b, 0x82, 0xc5, 0x1c, 0xf1, 0x3b, 0x33, 0xf3, 0xca, 0xe5, 0xa9, 0xc8, 0x55, 0xf4, 0xab, 0xac, + 0x93, 0xc8, 0x26, 0xc3, 0xb5, 0x33, 0xe6, 0xab, 0xde, 0x06, 0x40, 0xb6, 0xdd, 0x44, 0x1e, 0xed, + 0x12, 0x2e, 0x4c, 0x8f, 0x9c, 0x4b, 0x45, 0x64, 0xdb, 0xdb, 0x31, 0x62, 0xe0, 0xef, 0x3d, 0x6b, + 0x4a, 0x56, 0xe6, 0xbb, 0xc4, 0xf0, 0x5b, 0xf8, 0x9c, 0x86, 0xef, 0xc2, 0xa2, 0x2d, 0x38, 0x26, + 0x74, 0x7d, 0x29, 0xc5, 0x0d, 0xb4, 0x5e, 0x89, 0xad, 0x67, 0xed, 0xa5, 0xd6, 0x93, 0x1b, 0xdf, + 0xf8, 0x1b, 0x60, 0x7a, 0x97, 0x39, 0xea, 0x57, 0x0a, 0x2c, 0xe6, 0xdf, 0xae, 0x57, 0x47, 0x8f, + 0x9f, 0xfe, 0x01, 0xab, 0xbf, 0x7e, 0x16, 0x94, 0xec, 0xc0, 0x9f, 0x15, 0xd0, 0x87, 0x4c, 0xcf, + 0x37, 0xc6, 0x22, 0x3f, 0x9d, 0x40, 0x7f, 0xfb, 0x9c, 0x04, 0xd2, 0xe8, 0x37, 0x0a, 0x5c, 0x19, + 0x34, 0x1d, 0x5f, 0x9b, 0x40, 0xa0, 0x07, 0xa9, 0xbf, 0x79, 0x56, 0xa4, 0xf4, 0xf4, 0x93, 0x02, + 0xa5, 0xd3, 0x87, 0xe5, 0xed, 0x09, 0xf8, 0x07, 0xe0, 0xf5, 0x3b, 0xe7, 0xc3, 0x4b, 0x97, 0x5f, + 0x2a, 0xb0, 0xd4, 0x3f, 0x46, 0xb7, 0x26, 0x60, 0xcf, 0xe0, 0xf4, 0x33, 0xe2, 0xd4, 0x47, 0xb0, + 0xd0, 0xf3, 0xf8, 0x57, 0xc7, 0xe2, 0xc9, 0x42, 0xf4, 0x9b, 0x13, 0x43, 0xe4, 0x1d, 0x7c, 0x0c, + 0xb3, 0x62, 0x9c, 0xbf, 0x32, 0x9e, 0xff, 0x38, 0x58, 0xdf, 0x9c, 0x20, 0x58, 0x6a, 0x3d, 0x82, + 0x85, 0x9e, 0x81, 0x3a, 0x5e, 0xa6, 0x59, 0xc8, 0x98, 0x99, 0x0e, 0x9a, 0x90, 0x91, 0x7a, 0xcf, + 0x74, 0x1c, 0x4f, 0x3d, 0x0b, 0x19, 0x53, 0x7d, 0xd0, 0x90, 0x8b, 0xd4, 0x7b, 0x3e, 0x28, 0xaa, + 0x13, 0x74, 0x4b, 0x02, 0x19, 0x53, 0x7d, 0xd0, 0x37, 0x81, 0x7e, 0xe1, 0xf3, 0xe7, 0x4f, 0xae, + 0x2b, 0xb5, 0xc6, 0xd3, 0xa3, 0xb2, 0xf2, 0xec, 0xa8, 0xac, 0xfc, 0x75, 0x54, 0x56, 0x1e, 0x1f, + 0x97, 0x0b, 0xcf, 0x8e, 0xcb, 0x85, 0xdf, 0x8f, 0xcb, 0x85, 0x8f, 0xb6, 0x1c, 0x97, 0xef, 0x77, + 0x5b, 0x46, 0x9b, 0x7a, 0xa7, 0x7d, 0x2f, 0x1d, 0x6c, 0x9a, 0x87, 0xd9, 0xcf, 0xca, 0xd0, 0xc7, + 0xac, 0x35, 0x1b, 0x3f, 0xbc, 0x9b, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x1a, 0x95, 0xd6, 0xb8, + 0x87, 0x0e, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -977,6 +1133,11 @@ type MsgClient interface { UpdateRewardAddress(ctx context.Context, in *MsgUpdateRewardAddress, opts ...grpc.CallOption) (*MsgUpdateRewardAddressResponse, error) // UpdateWhitelistedRelayers defines a method for updating the sequencer's whitelisted relater list. UpdateWhitelistedRelayers(ctx context.Context, in *MsgUpdateWhitelistedRelayers, opts ...grpc.CallOption) (*MsgUpdateWhitelistedRelayersResponse, error) + // UpdateOptInStatus allows toggling optedIn bool + // NOTE: arguably should have just used UpdateSequencerInformation instead of having a new message, but want to avoid changing + // frontends last minute. + UpdateOptInStatus(ctx context.Context, in *MsgUpdateOptInStatus, opts ...grpc.CallOption) (*MsgUpdateOptInStatus, error) + KickProposer(ctx context.Context, in *MsgKickProposer, opts ...grpc.CallOption) (*MsgKickProposerResponse, error) // Unbond defines a method for removing coins from sequencer's bond Unbond(ctx context.Context, in *MsgUnbond, opts ...grpc.CallOption) (*MsgUnbondResponse, error) // IncreaseBond defines a method for increasing a sequencer's bond amount @@ -1032,6 +1193,24 @@ func (c *msgClient) UpdateWhitelistedRelayers(ctx context.Context, in *MsgUpdate return out, nil } +func (c *msgClient) UpdateOptInStatus(ctx context.Context, in *MsgUpdateOptInStatus, opts ...grpc.CallOption) (*MsgUpdateOptInStatus, error) { + out := new(MsgUpdateOptInStatus) + err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.sequencer.Msg/UpdateOptInStatus", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) KickProposer(ctx context.Context, in *MsgKickProposer, opts ...grpc.CallOption) (*MsgKickProposerResponse, error) { + out := new(MsgKickProposerResponse) + err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.sequencer.Msg/KickProposer", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *msgClient) Unbond(ctx context.Context, in *MsgUnbond, opts ...grpc.CallOption) (*MsgUnbondResponse, error) { out := new(MsgUnbondResponse) err := c.cc.Invoke(ctx, "/dymensionxyz.dymension.sequencer.Msg/Unbond", in, out, opts...) @@ -1078,6 +1257,11 @@ type MsgServer interface { UpdateRewardAddress(context.Context, *MsgUpdateRewardAddress) (*MsgUpdateRewardAddressResponse, error) // UpdateWhitelistedRelayers defines a method for updating the sequencer's whitelisted relater list. UpdateWhitelistedRelayers(context.Context, *MsgUpdateWhitelistedRelayers) (*MsgUpdateWhitelistedRelayersResponse, error) + // UpdateOptInStatus allows toggling optedIn bool + // NOTE: arguably should have just used UpdateSequencerInformation instead of having a new message, but want to avoid changing + // frontends last minute. + UpdateOptInStatus(context.Context, *MsgUpdateOptInStatus) (*MsgUpdateOptInStatus, error) + KickProposer(context.Context, *MsgKickProposer) (*MsgKickProposerResponse, error) // Unbond defines a method for removing coins from sequencer's bond Unbond(context.Context, *MsgUnbond) (*MsgUnbondResponse, error) // IncreaseBond defines a method for increasing a sequencer's bond amount @@ -1105,6 +1289,12 @@ func (*UnimplementedMsgServer) UpdateRewardAddress(ctx context.Context, req *Msg func (*UnimplementedMsgServer) UpdateWhitelistedRelayers(ctx context.Context, req *MsgUpdateWhitelistedRelayers) (*MsgUpdateWhitelistedRelayersResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateWhitelistedRelayers not implemented") } +func (*UnimplementedMsgServer) UpdateOptInStatus(ctx context.Context, req *MsgUpdateOptInStatus) (*MsgUpdateOptInStatus, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateOptInStatus not implemented") +} +func (*UnimplementedMsgServer) KickProposer(ctx context.Context, req *MsgKickProposer) (*MsgKickProposerResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method KickProposer not implemented") +} func (*UnimplementedMsgServer) Unbond(ctx context.Context, req *MsgUnbond) (*MsgUnbondResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Unbond not implemented") } @@ -1194,6 +1384,42 @@ func _Msg_UpdateWhitelistedRelayers_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } +func _Msg_UpdateOptInStatus_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgUpdateOptInStatus) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).UpdateOptInStatus(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dymensionxyz.dymension.sequencer.Msg/UpdateOptInStatus", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).UpdateOptInStatus(ctx, req.(*MsgUpdateOptInStatus)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_KickProposer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgKickProposer) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).KickProposer(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dymensionxyz.dymension.sequencer.Msg/KickProposer", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).KickProposer(ctx, req.(*MsgKickProposer)) + } + return interceptor(ctx, in, info, handler) +} + func _Msg_Unbond_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgUnbond) if err := dec(in); err != nil { @@ -1286,6 +1512,14 @@ var _Msg_serviceDesc = grpc.ServiceDesc{ MethodName: "UpdateWhitelistedRelayers", Handler: _Msg_UpdateWhitelistedRelayers_Handler, }, + { + MethodName: "UpdateOptInStatus", + Handler: _Msg_UpdateOptInStatus_Handler, + }, + { + MethodName: "KickProposer", + Handler: _Msg_KickProposer_Handler, + }, { MethodName: "Unbond", Handler: _Msg_Unbond_Handler, @@ -1478,6 +1712,59 @@ func (m *MsgCreateSequencerResponse) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } +func (m *MsgKickProposer) 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 *MsgKickProposer) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgKickProposer) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgKickProposerResponse) 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 *MsgKickProposerResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgKickProposerResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + func (m *MsgUpdateSequencerInformation) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -1663,7 +1950,7 @@ func (m *MsgUpdateWhitelistedRelayersResponse) MarshalToSizedBuffer(dAtA []byte) return len(dAtA) - i, nil } -func (m *MsgUnbond) Marshal() (dAtA []byte, err error) { +func (m *MsgUpdateOptInStatus) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1673,16 +1960,26 @@ func (m *MsgUnbond) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgUnbond) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgUpdateOptInStatus) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgUnbond) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgUpdateOptInStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l + if m.OptedIn { + i-- + if m.OptedIn { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x10 + } if len(m.Creator) > 0 { i -= len(m.Creator) copy(dAtA[i:], m.Creator) @@ -1693,7 +1990,7 @@ func (m *MsgUnbond) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *MsgUnbondResponse) Marshal() (dAtA []byte, err error) { +func (m *MsgUpdateOptInStatusResponse) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) n, err := m.MarshalToSizedBuffer(dAtA[:size]) @@ -1703,47 +2000,81 @@ func (m *MsgUnbondResponse) Marshal() (dAtA []byte, err error) { return dAtA[:n], nil } -func (m *MsgUnbondResponse) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgUpdateOptInStatusResponse) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) } -func (m *MsgUnbondResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { +func (m *MsgUpdateOptInStatusResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) _ = i var l int _ = l - if m.CompletionTime != nil { - { - size := m.CompletionTime.Size() - i -= size - if _, err := m.CompletionTime.MarshalTo(dAtA[i:]); err != nil { - return 0, err - } - } - } return len(dAtA) - i, nil } -func (m *MsgUnbondResponse_UnbondingCompletionTime) MarshalTo(dAtA []byte) (int, error) { +func (m *MsgUnbond) Marshal() (dAtA []byte, err error) { size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *MsgUnbondResponse_UnbondingCompletionTime) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - if m.UnbondingCompletionTime != nil { - n6, err6 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(*m.UnbondingCompletionTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(*m.UnbondingCompletionTime):]) - if err6 != nil { - return 0, err6 - } - i -= n6 - i = encodeVarintTx(dAtA, i, uint64(n6)) + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgUnbond) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUnbond) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Creator) > 0 { + i -= len(m.Creator) + copy(dAtA[i:], m.Creator) + i = encodeVarintTx(dAtA, i, uint64(len(m.Creator))) i-- dAtA[i] = 0xa } return len(dAtA) - i, nil } + +func (m *MsgUnbondResponse) 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 *MsgUnbondResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgUnbondResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.CompletionTime != nil { + { + size := m.CompletionTime.Size() + i -= size + if _, err := m.CompletionTime.MarshalTo(dAtA[i:]); err != nil { + return 0, err + } + } + } + return len(dAtA) - i, nil +} + func (m *MsgUnbondResponse_NoticePeriodCompletionTime) MarshalTo(dAtA []byte) (int, error) { size := m.Size() return m.MarshalToSizedBuffer(dAtA[:size]) @@ -1752,12 +2083,12 @@ func (m *MsgUnbondResponse_NoticePeriodCompletionTime) MarshalTo(dAtA []byte) (i func (m *MsgUnbondResponse_NoticePeriodCompletionTime) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) if m.NoticePeriodCompletionTime != nil { - n7, err7 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(*m.NoticePeriodCompletionTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(*m.NoticePeriodCompletionTime):]) - if err7 != nil { - return 0, err7 + n6, err6 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(*m.NoticePeriodCompletionTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(*m.NoticePeriodCompletionTime):]) + if err6 != nil { + return 0, err6 } - i -= n7 - i = encodeVarintTx(dAtA, i, uint64(n7)) + i -= n6 + i = encodeVarintTx(dAtA, i, uint64(n6)) i-- dAtA[i] = 0x12 } @@ -1886,14 +2217,6 @@ func (m *MsgDecreaseBondResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - n10, err10 := github_com_cosmos_gogoproto_types.StdTimeMarshalTo(m.CompletionTime, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdTime(m.CompletionTime):]) - if err10 != nil { - return 0, err10 - } - i -= n10 - i = encodeVarintTx(dAtA, i, uint64(n10)) - i-- - dAtA[i] = 0xa return len(dAtA) - i, nil } @@ -1976,6 +2299,28 @@ func (m *MsgCreateSequencerResponse) Size() (n int) { return n } +func (m *MsgKickProposer) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Creator) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgKickProposerResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + func (m *MsgUpdateSequencerInformation) Size() (n int) { if m == nil { return 0 @@ -2054,7 +2399,7 @@ func (m *MsgUpdateWhitelistedRelayersResponse) Size() (n int) { return n } -func (m *MsgUnbond) Size() (n int) { +func (m *MsgUpdateOptInStatus) Size() (n int) { if m == nil { return 0 } @@ -2064,33 +2409,46 @@ func (m *MsgUnbond) Size() (n int) { if l > 0 { n += 1 + l + sovTx(uint64(l)) } + if m.OptedIn { + n += 2 + } return n } -func (m *MsgUnbondResponse) Size() (n int) { +func (m *MsgUpdateOptInStatusResponse) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.CompletionTime != nil { - n += m.CompletionTime.Size() - } return n } -func (m *MsgUnbondResponse_UnbondingCompletionTime) Size() (n int) { +func (m *MsgUnbond) Size() (n int) { if m == nil { return 0 } var l int _ = l - if m.UnbondingCompletionTime != nil { - l = github_com_cosmos_gogoproto_types.SizeOfStdTime(*m.UnbondingCompletionTime) + l = len(m.Creator) + if l > 0 { n += 1 + l + sovTx(uint64(l)) } return n } + +func (m *MsgUnbondResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.CompletionTime != nil { + n += m.CompletionTime.Size() + } + return n +} + func (m *MsgUnbondResponse_NoticePeriodCompletionTime) Size() (n int) { if m == nil { return 0 @@ -2148,8 +2506,6 @@ func (m *MsgDecreaseBondResponse) Size() (n int) { } var l int _ = l - l = github_com_cosmos_gogoproto_types.SizeOfStdTime(m.CompletionTime) - n += 1 + l + sovTx(uint64(l)) return n } @@ -2654,6 +3010,138 @@ func (m *MsgCreateSequencerResponse) Unmarshal(dAtA []byte) error { } return nil } +func (m *MsgKickProposer) 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 ErrIntOverflowTx + } + 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: MsgKickProposer: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgKickProposer: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + 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 ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgKickProposerResponse) 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 ErrIntOverflowTx + } + 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: MsgKickProposerResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgKickProposerResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *MsgUpdateSequencerInformation) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -3147,7 +3635,7 @@ func (m *MsgUpdateWhitelistedRelayersResponse) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUnbond) Unmarshal(dAtA []byte) error { +func (m *MsgUpdateOptInStatus) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3170,10 +3658,10 @@ func (m *MsgUnbond) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUnbond: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUpdateOptInStatus: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUnbond: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUpdateOptInStatus: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: @@ -3208,6 +3696,26 @@ func (m *MsgUnbond) Unmarshal(dAtA []byte) error { } m.Creator = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field OptedIn", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.OptedIn = bool(v != 0) default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) @@ -3229,7 +3737,7 @@ func (m *MsgUnbond) Unmarshal(dAtA []byte) error { } return nil } -func (m *MsgUnbondResponse) Unmarshal(dAtA []byte) error { +func (m *MsgUpdateOptInStatusResponse) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 for iNdEx < l { @@ -3252,17 +3760,67 @@ func (m *MsgUnbondResponse) Unmarshal(dAtA []byte) error { fieldNum := int32(wire >> 3) wireType := int(wire & 0x7) if wireType == 4 { - return fmt.Errorf("proto: MsgUnbondResponse: wiretype end group for non-group") + return fmt.Errorf("proto: MsgUpdateOptInStatusResponse: wiretype end group for non-group") } if fieldNum <= 0 { - return fmt.Errorf("proto: MsgUnbondResponse: illegal tag %d (wire type %d)", fieldNum, wire) + return fmt.Errorf("proto: MsgUpdateOptInStatusResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUnbond) 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 ErrIntOverflowTx + } + 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: MsgUnbond: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUnbond: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { case 1: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field UnbondingCompletionTime", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field Creator", wireType) } - var msglen int + var stringLen uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -3272,27 +3830,74 @@ func (m *MsgUnbondResponse) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - msglen |= int(b&0x7F) << shift + stringLen |= uint64(b&0x7F) << shift if b < 0x80 { break } } - if msglen < 0 { + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthTx } - postIndex := iNdEx + msglen + postIndex := iNdEx + intStringLen if postIndex < 0 { return ErrInvalidLengthTx } if postIndex > l { return io.ErrUnexpectedEOF } - v := new(time.Time) - if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(v, dAtA[iNdEx:postIndex]); err != nil { + m.Creator = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { return err } - m.CompletionTime = &MsgUnbondResponse_UnbondingCompletionTime{v} - iNdEx = postIndex + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgUnbondResponse) 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 ErrIntOverflowTx + } + 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: MsgUnbondResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgUnbondResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { case 2: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field NoticePeriodCompletionTime", wireType) @@ -3658,39 +4263,6 @@ func (m *MsgDecreaseBondResponse) Unmarshal(dAtA []byte) error { return fmt.Errorf("proto: MsgDecreaseBondResponse: illegal tag %d (wire type %d)", fieldNum, wire) } switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field CompletionTime", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTx - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if err := github_com_cosmos_gogoproto_types.StdTimeUnmarshal(&m.CompletionTime, dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/sponsorship/keeper/votes.go b/x/sponsorship/keeper/votes.go index 2d67f9968..3c4bfdb54 100644 --- a/x/sponsorship/keeper/votes.go +++ b/x/sponsorship/keeper/votes.go @@ -140,7 +140,7 @@ func (k Keeper) validateWeights(ctx sdk.Context, weights []types.GaugeWeight, mi // no additional restrictions for asset gauges case *incentivestypes.Gauge_Rollapp: // we allow sponsoring only rollapps with bonded sequencers - bondedSequencers := k.sequencerKeeper.GetSequencersByRollappByStatus(ctx, distrTo.Rollapp.RollappId, sequencertypes.Bonded) + bondedSequencers := k.sequencerKeeper.RollappSequencersByStatus(ctx, distrTo.Rollapp.RollappId, sequencertypes.Bonded) if len(bondedSequencers) == 0 { return fmt.Errorf("rollapp has no bonded sequencers: %s'", distrTo.Rollapp.RollappId) } diff --git a/x/sponsorship/keeper/votes_test.go b/x/sponsorship/keeper/votes_test.go index 0bc4ca1d5..6135ecebc 100644 --- a/x/sponsorship/keeper/votes_test.go +++ b/x/sponsorship/keeper/votes_test.go @@ -396,9 +396,9 @@ func (s *KeeperTestSuite) TestMsgVoteRollAppGaugeBondedSequencer() { proposer := s.CreateDefaultSequencer(s.Ctx, raName) // verify the sequencer is bonded - seq, found := s.App.SequencerKeeper.GetSequencer(s.Ctx, proposer) - s.Require().True(found) - s.Require().True(seq.IsBonded()) + seq, err := s.App.SequencerKeeper.RealSequencer(s.Ctx, proposer) + s.Require().NoError(err) + s.Require().True(seq.Bonded()) // create a validator and a delegator initial := sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1_000_000)) @@ -433,12 +433,6 @@ func (s *KeeperTestSuite) TestMsgVoteRollAppGaugeNonBondedSequencer() { // create a rollapp, subsequently the rollapp gauge must be created s.CreateRollappByName(raName) - // create a bonded sequencer - proposer := s.CreateDefaultSequencer(s.Ctx, raName) - - // jail the sequencer - err := s.App.SequencerKeeper.JailSequencerOnFraud(s.Ctx, proposer) - s.Require().NoError(err) // create a validator and a delegator initial := sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(1_000_000)) diff --git a/x/sponsorship/types/expected_keepers.go b/x/sponsorship/types/expected_keepers.go index c00e42346..71345ae89 100644 --- a/x/sponsorship/types/expected_keepers.go +++ b/x/sponsorship/types/expected_keepers.go @@ -24,5 +24,5 @@ type IncentivesKeeper interface { } type SequencerKeeper interface { - GetSequencersByRollappByStatus(ctx sdk.Context, rollappId string, status sequencertypes.OperatingStatus) []sequencertypes.Sequencer + RollappSequencersByStatus(ctx sdk.Context, rollappId string, status sequencertypes.OperatingStatus) []sequencertypes.Sequencer } From 99e00acd824c7bb499b03f64157ebfd989d88e2b Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 11:01:46 +0200 Subject: [PATCH 29/68] linter --- x/delayedack/keeper/rollapp_packet.go | 3 +-- x/rollapp/keeper/sequencer_hooks.go | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/x/delayedack/keeper/rollapp_packet.go b/x/delayedack/keeper/rollapp_packet.go index 7dce2f82a..d60c8a998 100644 --- a/x/delayedack/keeper/rollapp_packet.go +++ b/x/delayedack/keeper/rollapp_packet.go @@ -1,9 +1,8 @@ package keeper import ( - "fmt" - "errors" + "fmt" "cosmossdk.io/collections" sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/x/rollapp/keeper/sequencer_hooks.go b/x/rollapp/keeper/sequencer_hooks.go index d9ee26e0d..6d6d7607f 100644 --- a/x/rollapp/keeper/sequencer_hooks.go +++ b/x/rollapp/keeper/sequencer_hooks.go @@ -30,7 +30,6 @@ func (h SequencerHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, sInfo.NextProposer = after.Address h.Keeper.SetStateInfo(ctx, sInfo) } - } func (h SequencerHooks) AfterKickProposer(ctx sdk.Context, kicked sequencertypes.Sequencer) { From 10186d4c3a0d11727a26f4f0a1f683eab6fed90f Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 11:36:54 +0200 Subject: [PATCH 30/68] UT fix --- app/upgrades/v4/upgrade.go | 7 ++++--- ibctesting/utils_test.go | 2 ++ x/delayedack/keeper/fraud.go | 3 +++ x/delayedack/keeper/keeper.go | 11 ----------- x/lightclient/keeper/rollback.go | 5 ++++- x/rollapp/keeper/sequencer_hooks.go | 5 ++++- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/app/upgrades/v4/upgrade.go b/app/upgrades/v4/upgrade.go index 554ebc925..a316f17dd 100644 --- a/app/upgrades/v4/upgrade.go +++ b/app/upgrades/v4/upgrade.go @@ -267,9 +267,10 @@ func ConvertOldRollappToNew(oldRollapp rollapptypes.Rollapp) rollapptypes.Rollap InitialSupply: sdk.NewInt(100000), // placeholder data Sealed: true, }, - InitialSequencer: "*", - Launched: true, - RevisionNumber: 0, + InitialSequencer: "*", + Launched: true, + RevisionNumber: 0, + RevisionStartHeight: 0, } } diff --git a/ibctesting/utils_test.go b/ibctesting/utils_test.go index 2e1e3e079..6d31ae3ab 100644 --- a/ibctesting/utils_test.go +++ b/ibctesting/utils_test.go @@ -110,6 +110,8 @@ func (s *utilSuite) rollappMsgServer() rollapptypes.MsgServer { // 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 diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 93fdd38b3..ad8e26d78 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -45,6 +45,9 @@ func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64 if err != nil { logger.Error("failed to delete reverted packet", append(logContext, "error", err.Error())...) } + + // FIXME: delete pendingPacketsByAddress>???? + logger.Debug("reverted IBC rollapp packet", logContext...) } diff --git a/x/delayedack/keeper/keeper.go b/x/delayedack/keeper/keeper.go index dd5107ac2..7534a98a8 100644 --- a/x/delayedack/keeper/keeper.go +++ b/x/delayedack/keeper/keeper.go @@ -80,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/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index f85f10160..ac7182679 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -40,7 +40,10 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraud }) // clean the optimistic updates valset - k.PruneSignersAbove(ctx, client, fraudHeight-1) + err := k.PruneSignersAbove(ctx, client, fraudHeight-1) + if err != nil { + k.Logger(ctx).Error("Failed to prune signers", "err", err) + } // marks that hard fork is in progress k.setHardForkInProgress(ctx, rollappId) diff --git a/x/rollapp/keeper/sequencer_hooks.go b/x/rollapp/keeper/sequencer_hooks.go index 6d6d7607f..619a37588 100644 --- a/x/rollapp/keeper/sequencer_hooks.go +++ b/x/rollapp/keeper/sequencer_hooks.go @@ -33,5 +33,8 @@ func (h SequencerHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, } func (h SequencerHooks) AfterKickProposer(ctx sdk.Context, kicked sequencertypes.Sequencer) { - h.Keeper.HardForkToLatest(ctx, kicked.RollappId) + err := h.Keeper.HardForkToLatest(ctx, kicked.RollappId) + if err != nil { + h.Keeper.Logger(ctx).Error("hard fork after kick proposer", "error", err) + } } From 839b3f32b1c1e9e9e8b442e12bb803528e063094 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 11:45:18 +0200 Subject: [PATCH 31/68] minor update to fraud proposal --- .../dymension/rollapp/fraud_proposal.proto | 7 +- x/rollapp/keeper/fraud_proposal.go | 5 +- x/rollapp/types/fraud_proposal.pb.go | 116 ++++++------------ x/rollapp/types/genesis.pb.go | 77 ++++++------ 4 files changed, 78 insertions(+), 127 deletions(-) diff --git a/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto index 893987c46..3c68c327a 100644 --- a/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto +++ b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto @@ -26,11 +26,8 @@ message MsgRollappFraudProposal { // The height of the fraudelent block uint64 fraud_height = 4; - // hard fork required? - bool hard_fork = 5; - - // sequencer address to jail. optional - string slash_sequencer_address = 6; + // sequencer address to punish. optional + string punish_sequencer_address = 6; } message MsgRollappFraudProposalResponse { diff --git a/x/rollapp/keeper/fraud_proposal.go b/x/rollapp/keeper/fraud_proposal.go index 6c6dabe8f..28a9a3c55 100644 --- a/x/rollapp/keeper/fraud_proposal.go +++ b/x/rollapp/keeper/fraud_proposal.go @@ -51,14 +51,13 @@ func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappF } // punish the sequencer if needed - if msg.SlashSequencerAddress != "" { - err := k.sequencerKeeper.PunishSequencer(ctx, msg.SlashSequencerAddress) + if msg.PunishSequencerAddress != "" { + err := k.sequencerKeeper.PunishSequencer(ctx, msg.PunishSequencerAddress) if err != nil { return nil, errorsmod.Wrap(err, "jail sequencer") } } - // FIXME: remove hard fork bool from the msg err := k.HardFork(ctx, msg.RollappId, msg.FraudHeight) if err != nil { return nil, errorsmod.Wrap(err, "hard fork") diff --git a/x/rollapp/types/fraud_proposal.pb.go b/x/rollapp/types/fraud_proposal.pb.go index 3af1d9822..abdd3dc44 100644 --- a/x/rollapp/types/fraud_proposal.pb.go +++ b/x/rollapp/types/fraud_proposal.pb.go @@ -38,10 +38,8 @@ type MsgRollappFraudProposal struct { 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"` - // hard fork required? - HardFork bool `protobuf:"varint,5,opt,name=hard_fork,json=hardFork,proto3" json:"hard_fork,omitempty"` - // sequencer address to jail. optional - SlashSequencerAddress string `protobuf:"bytes,6,opt,name=slash_sequencer_address,json=slashSequencerAddress,proto3" json:"slash_sequencer_address,omitempty"` + // sequencer address to punish. optional + PunishSequencerAddress string `protobuf:"bytes,6,opt,name=punish_sequencer_address,json=punishSequencerAddress,proto3" json:"punish_sequencer_address,omitempty"` } func (m *MsgRollappFraudProposal) Reset() { *m = MsgRollappFraudProposal{} } @@ -105,16 +103,9 @@ func (m *MsgRollappFraudProposal) GetFraudHeight() uint64 { return 0 } -func (m *MsgRollappFraudProposal) GetHardFork() bool { +func (m *MsgRollappFraudProposal) GetPunishSequencerAddress() string { if m != nil { - return m.HardFork - } - return false -} - -func (m *MsgRollappFraudProposal) GetSlashSequencerAddress() string { - if m != nil { - return m.SlashSequencerAddress + return m.PunishSequencerAddress } return "" } @@ -165,33 +156,31 @@ func init() { } var fileDescriptor_120f0332aea0a45b = []byte{ - // 401 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xbf, 0x6e, 0xda, 0x50, - 0x14, 0xc6, 0xb9, 0x94, 0x22, 0xb8, 0x54, 0x6d, 0x75, 0xd5, 0x0a, 0x8b, 0xb6, 0x2e, 0x30, 0xd1, - 0x0e, 0xbe, 0x4a, 0x88, 0x12, 0x29, 0x4b, 0x94, 0x0c, 0x28, 0x19, 0x88, 0x22, 0xb3, 0x65, 0xb1, - 0x0c, 0xbe, 0xd8, 0x16, 0xb6, 0xaf, 0x73, 0x8f, 0x8d, 0x70, 0xc6, 0x6c, 0x59, 0xa2, 0x3c, 0x41, - 0x9e, 0x21, 0x8f, 0x91, 0x91, 0x31, 0x63, 0x04, 0x43, 0x5e, 0x23, 0xf2, 0x3f, 0x60, 0x21, 0x43, - 0x26, 0xfb, 0xfc, 0xbe, 0xf3, 0xe9, 0x3b, 0xc7, 0x3e, 0xb8, 0x6b, 0x44, 0x2e, 0xf3, 0xc0, 0xe6, - 0xde, 0x2c, 0xba, 0xa6, 0xab, 0x82, 0x0a, 0xee, 0x38, 0xba, 0xef, 0xd3, 0xb1, 0xd0, 0x43, 0x43, - 0xf3, 0x05, 0xf7, 0x39, 0xe8, 0x8e, 0xe2, 0x0b, 0x1e, 0x70, 0x22, 0x6f, 0x9a, 0x94, 0x55, 0xa1, - 0x64, 0xa6, 0xc6, 0x0f, 0x93, 0x9b, 0x3c, 0x69, 0xa5, 0xf1, 0x5b, 0xea, 0x6a, 0xd4, 0x47, 0x1c, - 0x5c, 0x0e, 0xd4, 0x05, 0x93, 0x4e, 0x77, 0xe2, 0x47, 0x2a, 0xb4, 0x6f, 0x8b, 0xb8, 0xde, 0x07, - 0x53, 0x4d, 0xdd, 0xbd, 0x38, 0xf1, 0x22, 0x0b, 0x24, 0xbf, 0x71, 0x55, 0x0f, 0x03, 0x8b, 0x0b, - 0x3b, 0x88, 0x24, 0xd4, 0x44, 0x9d, 0xaa, 0xba, 0x06, 0xe4, 0x0f, 0xc6, 0x59, 0xa6, 0x66, 0x1b, - 0x52, 0x31, 0x95, 0x33, 0x72, 0x66, 0x90, 0x7f, 0xf8, 0x7b, 0x2e, 0x0b, 0x36, 0xb5, 0xe3, 0x19, - 0xa5, 0x4f, 0x4d, 0xd4, 0x29, 0xa9, 0xdf, 0x32, 0xae, 0x66, 0x98, 0xb4, 0xf0, 0x97, 0x74, 0x55, - 0x8b, 0xd9, 0xa6, 0x15, 0x48, 0xa5, 0xa4, 0xad, 0x96, 0xb0, 0xd3, 0x04, 0x91, 0x5f, 0xb8, 0x6a, - 0xe9, 0xc2, 0xd0, 0xc6, 0x5c, 0x4c, 0xa4, 0xcf, 0x4d, 0xd4, 0xa9, 0xa8, 0x95, 0x18, 0xf4, 0xb8, - 0x98, 0x90, 0x7d, 0x5c, 0x07, 0x47, 0x07, 0x4b, 0x03, 0x76, 0x15, 0x32, 0x6f, 0xc4, 0x84, 0xa6, - 0x1b, 0x86, 0x60, 0x00, 0x52, 0x39, 0x19, 0xeb, 0x67, 0x22, 0x0f, 0x72, 0xf5, 0x38, 0x15, 0x0f, - 0xbf, 0xde, 0xbc, 0x3e, 0xfe, 0x5f, 0x6f, 0xd4, 0x6e, 0xe1, 0xbf, 0x5b, 0x3e, 0x85, 0xca, 0xc0, - 0xe7, 0x1e, 0xb0, 0xdd, 0x07, 0x84, 0x6b, 0x39, 0xec, 0x83, 0x49, 0xee, 0x10, 0x26, 0x83, 0x70, - 0xe8, 0xda, 0xc1, 0xa6, 0x8d, 0x1c, 0x28, 0xef, 0xff, 0x25, 0x65, 0x4b, 0x4e, 0xe3, 0xe8, 0x83, - 0xc6, 0x7c, 0xc0, 0x93, 0xf3, 0xa7, 0x85, 0x8c, 0xe6, 0x0b, 0x19, 0xbd, 0x2c, 0x64, 0x74, 0xbf, - 0x94, 0x0b, 0xf3, 0xa5, 0x5c, 0x78, 0x5e, 0xca, 0x85, 0xcb, 0x3d, 0xd3, 0x0e, 0xac, 0x70, 0xa8, - 0x8c, 0xb8, 0x4b, 0xb7, 0x1c, 0xde, 0xb4, 0x4b, 0x67, 0xab, 0xeb, 0x0b, 0x22, 0x9f, 0xc1, 0xb0, - 0x9c, 0x9c, 0x49, 0xf7, 0x2d, 0x00, 0x00, 0xff, 0xff, 0xab, 0xb2, 0xbc, 0xaf, 0xac, 0x02, 0x00, - 0x00, + // 375 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xb1, 0x4e, 0xc2, 0x40, + 0x18, 0xc7, 0x39, 0x25, 0x24, 0x1c, 0x46, 0xcd, 0xc5, 0x48, 0x43, 0xb4, 0x02, 0x13, 0x3a, 0xf4, + 0xa2, 0x98, 0x68, 0x5c, 0x8c, 0x0e, 0x46, 0x07, 0x8c, 0x29, 0x9b, 0x4b, 0x53, 0xe8, 0xd9, 0x5e, + 0x42, 0x7b, 0xe7, 0x5d, 0x4b, 0xa8, 0xa3, 0x0f, 0x60, 0x7c, 0x02, 0x9f, 0xc1, 0xc7, 0x70, 0x64, + 0x74, 0x34, 0x30, 0xb8, 0xf9, 0x0c, 0xa6, 0xbd, 0x16, 0x58, 0x70, 0x70, 0x6a, 0xbf, 0xdf, 0xff, + 0xfb, 0xe7, 0xff, 0x7d, 0xb9, 0x0f, 0xb6, 0x9d, 0xd8, 0x27, 0x81, 0xa4, 0x2c, 0x18, 0xc5, 0x4f, + 0x78, 0x56, 0x60, 0xc1, 0x06, 0x03, 0x9b, 0x73, 0xfc, 0x20, 0xec, 0xc8, 0xb1, 0xb8, 0x60, 0x9c, + 0x49, 0x7b, 0x60, 0x70, 0xc1, 0x42, 0x86, 0xf4, 0x45, 0x93, 0x31, 0x2b, 0x8c, 0xcc, 0x54, 0xdb, + 0x72, 0x99, 0xcb, 0xd2, 0x56, 0x9c, 0xfc, 0x29, 0x57, 0xad, 0xda, 0x67, 0xd2, 0x67, 0x12, 0xfb, + 0xd2, 0xc5, 0xc3, 0xc3, 0xe4, 0xa3, 0x84, 0xe6, 0x0f, 0x80, 0xd5, 0x8e, 0x74, 0x4d, 0xe5, 0xbe, + 0x4a, 0x12, 0xef, 0xb2, 0x40, 0xb4, 0x03, 0xcb, 0x76, 0x14, 0x7a, 0x4c, 0xd0, 0x30, 0xd6, 0x40, + 0x1d, 0xb4, 0xca, 0xe6, 0x1c, 0xa0, 0x5d, 0x08, 0xb3, 0x4c, 0x8b, 0x3a, 0xda, 0x8a, 0x92, 0x33, + 0x72, 0xe3, 0xa0, 0x7d, 0xb8, 0x99, 0xcb, 0x82, 0x0c, 0x69, 0x32, 0xa3, 0xb6, 0x5a, 0x07, 0xad, + 0xa2, 0xb9, 0x91, 0x71, 0x33, 0xc3, 0xa8, 0x01, 0xd7, 0xd4, 0xaa, 0x1e, 0xa1, 0xae, 0x17, 0x6a, + 0xc5, 0xb4, 0xad, 0x92, 0xb2, 0xeb, 0x14, 0xa1, 0x53, 0xa8, 0xf1, 0x28, 0xa0, 0xd2, 0xb3, 0x24, + 0x79, 0x8c, 0x48, 0xd0, 0x27, 0xc2, 0xb2, 0x1d, 0x47, 0x10, 0x29, 0xb5, 0x52, 0x1a, 0xbd, 0xad, + 0xf4, 0x6e, 0x2e, 0x5f, 0x28, 0xf5, 0x6c, 0xfd, 0xf9, 0xfb, 0xfd, 0x60, 0x3e, 0x76, 0xb3, 0x01, + 0xf7, 0x96, 0xec, 0x6b, 0x12, 0xc9, 0x59, 0x20, 0xc9, 0xd1, 0x1b, 0x80, 0x95, 0x1c, 0x76, 0xa4, + 0x8b, 0x5e, 0x00, 0x44, 0xdd, 0xa8, 0xe7, 0xd3, 0x70, 0xd1, 0x86, 0x4e, 0x8c, 0xbf, 0x9f, 0xc2, + 0x58, 0x92, 0x53, 0x3b, 0xff, 0xa7, 0x31, 0x1f, 0xf0, 0xf2, 0xf6, 0x63, 0xa2, 0x83, 0xf1, 0x44, + 0x07, 0x5f, 0x13, 0x1d, 0xbc, 0x4e, 0xf5, 0xc2, 0x78, 0xaa, 0x17, 0x3e, 0xa7, 0x7a, 0xe1, 0xfe, + 0xd8, 0xa5, 0xa1, 0x17, 0xf5, 0x8c, 0x3e, 0xf3, 0xf1, 0x92, 0xeb, 0x1a, 0xb6, 0xf1, 0x68, 0x76, + 0x62, 0x61, 0xcc, 0x89, 0xec, 0x95, 0xd2, 0x5b, 0x68, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xe3, + 0x76, 0x5c, 0xd6, 0x91, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -294,23 +283,13 @@ func (m *MsgRollappFraudProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l - if len(m.SlashSequencerAddress) > 0 { - i -= len(m.SlashSequencerAddress) - copy(dAtA[i:], m.SlashSequencerAddress) - i = encodeVarintFraudProposal(dAtA, i, uint64(len(m.SlashSequencerAddress))) + 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.HardFork { - i-- - if m.HardFork { - dAtA[i] = 1 - } else { - dAtA[i] = 0 - } - i-- - dAtA[i] = 0x28 - } if m.FraudHeight != 0 { i = encodeVarintFraudProposal(dAtA, i, uint64(m.FraudHeight)) i-- @@ -392,10 +371,7 @@ func (m *MsgRollappFraudProposal) Size() (n int) { if m.FraudHeight != 0 { n += 1 + sovFraudProposal(uint64(m.FraudHeight)) } - if m.HardFork { - n += 2 - } - l = len(m.SlashSequencerAddress) + l = len(m.PunishSequencerAddress) if l > 0 { n += 1 + l + sovFraudProposal(uint64(l)) } @@ -548,29 +524,9 @@ func (m *MsgRollappFraudProposal) Unmarshal(dAtA []byte) error { break } } - case 5: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field HardFork", wireType) - } - var v int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowFraudProposal - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - v |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - m.HardFork = bool(v != 0) case 6: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SlashSequencerAddress", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field PunishSequencerAddress", wireType) } var stringLen uint64 for shift := uint(0); ; shift += 7 { @@ -598,7 +554,7 @@ func (m *MsgRollappFraudProposal) Unmarshal(dAtA []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.SlashSequencerAddress = string(dAtA[iNdEx:postIndex]) + m.PunishSequencerAddress = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex diff --git a/x/rollapp/types/genesis.pb.go b/x/rollapp/types/genesis.pb.go index 03cee006b..401528206 100644 --- a/x/rollapp/types/genesis.pb.go +++ b/x/rollapp/types/genesis.pb.go @@ -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, + // 592 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, 0x14, 0x6a, 0x45, 0xd4, 0x44, 0x41, + 0x82, 0x20, 0xa8, 0x2d, 0x35, 0x08, 0x76, 0x48, 0x84, 0xf0, 0x27, 0xa2, 0x82, 0xe0, 0x02, 0x0b, + 0x58, 0x44, 0x4e, 0x7c, 0xeb, 0x8c, 0x70, 0x66, 0x8c, 0x67, 0x12, 0x25, 0x79, 0x0a, 0x16, 0xbc, + 0x0a, 0xef, 0xd0, 0x65, 0x97, 0xac, 0x10, 0x4a, 0x5e, 0x04, 0x79, 0x3c, 0x76, 0x43, 0xdb, 0xc4, + 0x91, 0x58, 0x39, 0xe3, 0x39, 0xf7, 0x77, 0x8e, 0x6f, 0xae, 0x2e, 0x7a, 0xe0, 0x8e, 0xfb, 0x40, + 0x39, 0x61, 0x74, 0x34, 0x9e, 0x58, 0xe9, 0xc1, 0x0a, 0x99, 0xef, 0x3b, 0x41, 0x60, 0x79, 0x40, + 0x81, 0x13, 0x6e, 0x06, 0x21, 0x13, 0x0c, 0x1b, 0xf3, 0x6a, 0x33, 0x3d, 0x98, 0x4a, 0x5d, 0xda, + 0xf1, 0x98, 0xc7, 0xa4, 0xd4, 0x8a, 0x7e, 0xc5, 0x55, 0xa5, 0xfb, 0x19, 0x1e, 0x81, 0x13, 0x3a, + 0x7d, 0x65, 0x51, 0xca, 0x0a, 0xa4, 0x9e, 0x4a, 0x6d, 0x65, 0xa8, 0xb9, 0x70, 0x04, 0xb4, 0x09, + 0x3d, 0x4e, 0xb2, 0xec, 0x67, 0x14, 0xf8, 0x64, 0x18, 0x7d, 0x71, 0x92, 0xa6, 0x9a, 0x21, 0x4f, + 0x93, 0x54, 0x7e, 0x6c, 0xa1, 0xff, 0x5f, 0xc6, 0xcd, 0x3a, 0x8a, 0x4c, 0x71, 0x03, 0xe5, 0xe3, + 0x0f, 0xd3, 0xb5, 0xb2, 0x56, 0x2d, 0x1e, 0xdc, 0x31, 0x97, 0x37, 0xcf, 0x6c, 0x49, 0x75, 0x7d, + 0xe3, 0xe4, 0xd7, 0xad, 0x9c, 0xad, 0x6a, 0xf1, 0x5b, 0x54, 0x54, 0xf7, 0x87, 0x84, 0x0b, 0x7d, + 0xad, 0xbc, 0x5e, 0x2d, 0x1e, 0xdc, 0xcd, 0x42, 0xd9, 0xf1, 0x53, 0xb1, 0xe6, 0x09, 0xf8, 0x03, + 0xda, 0x96, 0x4d, 0x69, 0xd2, 0x63, 0x26, 0x91, 0xeb, 0x12, 0x79, 0x2f, 0x0b, 0x79, 0x94, 0x14, + 0x29, 0xe8, 0xdf, 0x14, 0x1c, 0x20, 0xdd, 0x77, 0x04, 0x70, 0x91, 0xea, 0x9a, 0xd4, 0x85, 0x91, + 0x74, 0xd8, 0x90, 0x0e, 0xe6, 0xca, 0x0e, 0xb2, 0x52, 0xd9, 0x2c, 0xa4, 0xe2, 0x09, 0xda, 0x8b, + 0xef, 0x5e, 0x10, 0xea, 0xf8, 0x64, 0x02, 0xae, 0x12, 0x25, 0xb6, 0xff, 0xfd, 0x83, 0xed, 0x72, + 0x34, 0xfe, 0xae, 0xa1, 0x4a, 0xc7, 0x67, 0xdd, 0x2f, 0xaf, 0x80, 0x78, 0x3d, 0xf1, 0x9e, 0x29, + 0xa1, 0x23, 0x08, 0xa3, 0xef, 0x06, 0x30, 0x00, 0x99, 0x20, 0x2f, 0x13, 0x3c, 0xc9, 0x4a, 0x50, + 0x5f, 0x4a, 0x52, 0x89, 0x56, 0xf0, 0xc3, 0x9f, 0xd1, 0x95, 0x64, 0x7e, 0x9f, 0x0f, 0x81, 0x0a, + 0xae, 0x6f, 0xca, 0x04, 0xfb, 0x59, 0x09, 0x0e, 0xe7, 0xab, 0x94, 0xe1, 0x39, 0x14, 0x7e, 0x86, + 0x36, 0x93, 0x29, 0xdc, 0x92, 0xd4, 0xdb, 0x59, 0xd4, 0xa7, 0xe9, 0x04, 0x26, 0x95, 0x98, 0xa0, + 0xab, 0x21, 0x78, 0x84, 0x0b, 0x08, 0xc1, 0x6d, 0x00, 0x65, 0x7d, 0xae, 0x17, 0x24, 0xed, 0xf1, + 0x8a, 0x33, 0x6d, 0x9f, 0x2b, 0x57, 0x0e, 0x17, 0xb0, 0xb8, 0x8f, 0x76, 0x38, 0x7c, 0x1d, 0x00, + 0xed, 0x42, 0x18, 0xb7, 0xad, 0xe5, 0x90, 0x90, 0xeb, 0x48, 0xda, 0xd5, 0x32, 0xc7, 0xe2, 0x62, + 0xad, 0xb2, 0xba, 0x14, 0x8b, 0x1f, 0xa1, 0xdd, 0xe1, 0xc0, 0xa7, 0x10, 0x3a, 0x1d, 0x1f, 0xda, + 0x6e, 0xc8, 0xdb, 0x43, 0x08, 0x23, 0x22, 0xd7, 0x8b, 0xe5, 0xf5, 0xea, 0xb6, 0x7d, 0xfd, 0xec, + 0xba, 0x11, 0xf2, 0x8f, 0xea, 0xb2, 0xf2, 0x1a, 0x5d, 0xbb, 0xc4, 0x0a, 0xdf, 0x44, 0x85, 0xd4, + 0x46, 0x2e, 0x90, 0x82, 0x7d, 0xf6, 0x02, 0xdf, 0x40, 0xf9, 0x9e, 0xd4, 0xea, 0x6b, 0x65, 0xad, + 0xba, 0x61, 0xab, 0x53, 0xa5, 0x85, 0x76, 0x17, 0xb4, 0x09, 0xef, 0x21, 0xa4, 0x3e, 0xad, 0x4d, + 0xdc, 0x84, 0xa8, 0xde, 0x34, 0xdd, 0x88, 0xe8, 0xc6, 0x7f, 0x47, 0xb4, 0x62, 0x0a, 0xb6, 0x3a, + 0xd5, 0xdf, 0x9c, 0x4c, 0x0d, 0xed, 0x74, 0x6a, 0x68, 0xbf, 0xa7, 0x86, 0xf6, 0x6d, 0x66, 0xe4, + 0x4e, 0x67, 0x46, 0xee, 0xe7, 0xcc, 0xc8, 0x7d, 0x7a, 0xe8, 0x11, 0xd1, 0x1b, 0x74, 0xcc, 0x2e, + 0xeb, 0x2f, 0xda, 0xc2, 0xc3, 0x9a, 0x35, 0x4a, 0x57, 0xa5, 0x18, 0x07, 0xc0, 0x3b, 0x79, 0xb9, + 0x2d, 0x6b, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xfb, 0xd6, 0xd7, 0x55, 0x78, 0x06, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { From 5a25e6da4c37ee1a80f2f8e3dec6ddf1842930d5 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 12:10:01 +0200 Subject: [PATCH 32/68] delete pendingPacketsByAddress on the delayedAck --- ibctesting/genesis_bridge_test.go | 5 ----- x/delayedack/keeper/fraud.go | 12 +++++++++++- x/delayedack/keeper/fraud_test.go | 10 +++++++++- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/ibctesting/genesis_bridge_test.go b/ibctesting/genesis_bridge_test.go index 1e999e2ab..f288c1d7d 100644 --- a/ibctesting/genesis_bridge_test.go +++ b/ibctesting/genesis_bridge_test.go @@ -47,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/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index ad8e26d78..e567d889e 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -29,24 +29,34 @@ func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64 "sequence", rollappPacket.Packet.Sequence, } + pendingAddr := "" + transfer := rollappPacket.MustGetTransferPacketData() if rollappPacket.Type == commontypes.RollappPacket_ON_ACK || rollappPacket.Type == commontypes.RollappPacket_ON_TIMEOUT { // for sent packets, we restore the packet commitment // the packet will be handled over the new rollapp revision commitment := channeltypes.CommitPacket(k.cdc, rollappPacket.Packet) k.channelKeeper.SetPacketCommitment(ctx, rollappPacket.Packet.SourcePort, rollappPacket.Packet.SourceChannel, rollappPacket.Packet.Sequence, commitment) + pendingAddr = transfer.Sender } else { // for incoming packets, we need to reset the packet receipt ibcPacket := rollappPacket.Packet k.deletePacketReceipt(ctx, ibcPacket.GetDestPort(), ibcPacket.GetDestChannel(), ibcPacket.GetSequence()) + pendingAddr = transfer.Receiver } // delete the packet err := k.DeleteRollappPacket(ctx, &rollappPacket) if err != nil { logger.Error("failed to delete reverted packet", append(logContext, "error", err.Error())...) + continue } - // FIXME: delete pendingPacketsByAddress>???? + // delete the pending packet + err = k.DeletePendingPacketByAddress(ctx, pendingAddr, rollappPacket.RollappPacketKey()) + if err != nil { + logger.Error("failed to delete reverted pending packet", append(logContext, "error", err.Error())...) + continue + } logger.Debug("reverted IBC rollapp packet", logContext...) } diff --git a/x/delayedack/keeper/fraud_test.go b/x/delayedack/keeper/fraud_test.go index 4303fa00f..8383fc2e7 100644 --- a/x/delayedack/keeper/fraud_test.go +++ b/x/delayedack/keeper/fraud_test.go @@ -19,13 +19,17 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { for _, pkt := range append(pkts, pkts2...) { keeper.SetRollappPacket(ctx, pkt) + keeper.MustSetPendingPacketByAddress(ctx, apptesting.TestPacketReceiver, pkt.RollappPacketKey()) } 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 one packet - _, err := keeper.UpdateRollappPacketWithStatus(ctx, pkts[0], commontypes.Status_FINALIZED) + _, err = keeper.UpdateRollappPacketWithStatus(ctx, pkts[0], commontypes.Status_FINALIZED) suite.Require().Nil(err) _, err = keeper.UpdateRollappPacketWithStatus(ctx, pkts2[0], commontypes.Status_FINALIZED) suite.Require().Nil(err) @@ -46,6 +50,10 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { suite.Require().Equal(1, len(keeper.ListRollappPackets(ctx, prefixFinalized1))) suite.Require().Equal(2, len(keeper.ListRollappPackets(ctx, prefixPending1))) + 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(1, len(keeper.ListRollappPackets(ctx, prefixFinalized2))) suite.Require().Equal(9, len(keeper.ListRollappPackets(ctx, prefixPending2))) } From 36391565600a3395f6bbb28fc4d0829714043aa7 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 12:46:16 +0200 Subject: [PATCH 33/68] fixed seqeucner heoght pruning --- .../block_height_to_finalization_queue.go | 1 - ...block_height_to_finalization_queue_test.go | 7 ++++ x/rollapp/keeper/hard_fork.go | 34 +++++++++++++------ x/rollapp/keeper/hard_fork_test.go | 13 +++++++ 4 files changed, 43 insertions(+), 12 deletions(-) diff --git a/x/rollapp/keeper/block_height_to_finalization_queue.go b/x/rollapp/keeper/block_height_to_finalization_queue.go index bb6dd7c85..e1fe4f06c 100644 --- a/x/rollapp/keeper/block_height_to_finalization_queue.go +++ b/x/rollapp/keeper/block_height_to_finalization_queue.go @@ -25,7 +25,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 178c31cd4..3eeab9193 100644 --- a/x/rollapp/keeper/block_height_to_finalization_queue_test.go +++ b/x/rollapp/keeper/block_height_to_finalization_queue_test.go @@ -670,11 +670,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/hard_fork.go b/x/rollapp/keeper/hard_fork.go index ec6d1174c..29a8e3399 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -30,7 +30,7 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) k.SetRollapp(ctx, rollapp) // handle the sequencers, clean delayed packets, handle light client - err = k.hooks.OnHardFork(ctx, rollappID, fraudHeight) + err = k.hooks.OnHardFork(ctx, rollappID, lastCommittedHeight+1) if err != nil { return err } @@ -76,22 +76,19 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig } // clear pending states post the fraud height - revertedStatesCount := 0 // Counter for reverted state updates + 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++ { - sInfo := k.MustGetStateInfo(ctx, rollappID, i) + // Add the proposer to the unique map + uniqueProposers[k.MustGetStateInfo(ctx, rollappID, i).Sequencer] = struct{}{} - // clear the sequencer heights - for _, bd := range sInfo.BDs.BD { - if err := k.DelSequencerHeight(ctx, sInfo.Sequencer, bd.Height); err != nil { - return 0, errorsmod.Wrap(err, "del sequencer height") - } - } // clear the state info k.RemoveStateInfo(ctx, rollappID, i) revertedStatesCount++ // Increment the counter - } + k.SetLatestStateInfoIndex(ctx, types.StateInfoIndex{ RollappId: rollappID, Index: lastStateIdxToKeep, @@ -136,8 +133,15 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig }) } + // remove the sequencer 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 fraudHeight - 1, nil + return lastStateInfo.GetLatestHeight(), nil } // UpdateLastStateInfo truncates the state info to the last valid block before the fraud height. @@ -177,3 +181,11 @@ func (k Keeper) HardForkToLatest(ctx sdk.Context, rollappID string) error { // 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) + } + return keys +} diff --git a/x/rollapp/keeper/hard_fork_test.go b/x/rollapp/keeper/hard_fork_test.go index 2ca4a54aa..22bc6d0fc 100644 --- a/x/rollapp/keeper/hard_fork_test.go +++ b/x/rollapp/keeper/hard_fork_test.go @@ -132,6 +132,19 @@ func (suite *RollappTestSuite) assertFraudHandled(rollappId string, height uint6 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 := suite.App.RollappKeeper.GetAllBlockHeightToFinalizationQueue(suite.Ctx) suite.Require().Greater(len(queue), 0) From c65685906260a160ae43d841130bf914bf69f489 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 12:49:51 +0200 Subject: [PATCH 34/68] fraud proposal supports future heights --- x/rollapp/keeper/fraud_proposal.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/x/rollapp/keeper/fraud_proposal.go b/x/rollapp/keeper/fraud_proposal.go index 28a9a3c55..51324ea6f 100644 --- a/x/rollapp/keeper/fraud_proposal.go +++ b/x/rollapp/keeper/fraud_proposal.go @@ -37,11 +37,10 @@ func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappF return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "rollapp is not past genesis bridge phase") } - // validate the fraud height is already committed - // FIXME: allow the latest height +1 as well? + // validate we have state infos committed sinfo, found := k.GetLatestStateInfo(ctx, msg.RollappId) - if !found || sinfo.GetLatestHeight() < msg.FraudHeight { - return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height not committed") + if !found { + return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "no state info found") } // check wether the fraud height is already finalized From 204de23fcb39491dd0bab4e62755e29ae0e3cb41 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 12:55:29 +0200 Subject: [PATCH 35/68] fork hook doesn't return error --- ibctesting/delayed_ack_test.go | 3 +-- x/delayedack/keeper/fraud.go | 4 +--- x/delayedack/keeper/fraud_test.go | 3 +-- x/delayedack/keeper/invariants_test.go | 4 +--- x/dymns/keeper/hooks.go | 4 +--- x/lightclient/keeper/rollback.go | 3 +-- x/rollapp/keeper/hard_fork.go | 5 +---- x/rollapp/types/hooks.go | 12 ++++-------- x/sequencer/keeper/fraud_test.go | 4 ++-- x/sequencer/keeper/hook_listener.go | 6 ++---- 10 files changed, 15 insertions(+), 33 deletions(-) diff --git a/ibctesting/delayed_ack_test.go b/ibctesting/delayed_ack_test.go index 95e7d9969..51496543d 100644 --- a/ibctesting/delayed_ack_test.go +++ b/ibctesting/delayed_ack_test.go @@ -308,8 +308,7 @@ func (s *delayedAckSuite) TestHardFork_HubToRollapp() { s.Require().NotEqual(balanceBefore.String(), balanceAfter.String()) // hard fork - err = s.hubApp().DelayedAckKeeper.OnHardFork(s.hubCtx(), s.rollappCtx().ChainID(), 5) - s.Require().NoError(err) + s.hubApp().DelayedAckKeeper.OnHardFork(s.hubCtx(), s.rollappCtx().ChainID(), 5) // assert commitments are created again found = hubIBCKeeper.ChannelKeeper.HasPacketCommitment(s.hubCtx(), packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence()) diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index e567d889e..4e81f8937 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -13,7 +13,7 @@ import ( var _ rollapptypes.RollappHooks = &Keeper{} -func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error { +func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) { logger := ctx.Logger().With("module", "DelayedAckMiddleware") // Get all the pending packets from fork height inclusive @@ -62,8 +62,6 @@ func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64 } logger.Info("reverting IBC rollapp packets", "rollappID", rollappID, "numPackets", len(rollappPendingPackets)) - - return nil } // DeleteRollappPacket deletes a packet receipt from the store diff --git a/x/delayedack/keeper/fraud_test.go b/x/delayedack/keeper/fraud_test.go index 8383fc2e7..f1bdb1236 100644 --- a/x/delayedack/keeper/fraud_test.go +++ b/x/delayedack/keeper/fraud_test.go @@ -35,8 +35,7 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { suite.Require().Nil(err) // call fraud on the 4 packet - err = keeper.OnHardFork(ctx, rollappId, 4) - suite.Require().Nil(err) + keeper.OnHardFork(ctx, rollappId, 4) // expected result: // rollappId: diff --git a/x/delayedack/keeper/invariants_test.go b/x/delayedack/keeper/invariants_test.go index 48db10164..ba7c24afc 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -78,9 +78,7 @@ func (suite *DelayedAckTestSuite) TestInvariants() { // test fraud for rollapp := range seqPerRollapp { - err := suite.App.DelayedAckKeeper.OnHardFork(suite.Ctx, rollapp, uint64(suite.Ctx.BlockHeight())) - suite.Require().NoError(err) - break + suite.App.DelayedAckKeeper.OnHardFork(suite.Ctx, rollapp, uint64(suite.Ctx.BlockHeight())) } // check invariant diff --git a/x/dymns/keeper/hooks.go b/x/dymns/keeper/hooks.go index e384f9bb8..91c53ebc5 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) OnHardFork(_ sdk.Context, _ string, _ uint64) error { - return nil -} +func (h rollappHooks) OnHardFork(_ sdk.Context, _ string, _ uint64) {} func (h rollappHooks) AfterTransfersEnabled(_ sdk.Context, _, _ string) error { return nil diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index ac7182679..ef2def348 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -12,9 +12,8 @@ import ( ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ) -func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappId string, fraudHeight uint64) error { +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappId string, fraudHeight uint64) { hook.k.RollbackCanonicalClient(ctx, rollappId, fraudHeight) - return nil } func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraudHeight uint64) { diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index 29a8e3399..91bfa30b9 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -30,10 +30,7 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) k.SetRollapp(ctx, rollapp) // handle the sequencers, clean delayed packets, handle light client - err = k.hooks.OnHardFork(ctx, rollappID, lastCommittedHeight+1) - if err != nil { - return err - } + k.hooks.OnHardFork(ctx, rollappID, lastCommittedHeight+1) ctx.EventManager().EmitEvent( sdk.NewEvent( diff --git a/x/rollapp/types/hooks.go b/x/rollapp/types/hooks.go index 220c6f844..8f862967a 100644 --- a/x/rollapp/types/hooks.go +++ b/x/rollapp/types/hooks.go @@ -17,7 +17,7 @@ type RollappHooks interface { 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 + OnHardFork(ctx sdk.Context, rollappID string, height uint64) } var _ RollappHooks = MultiRollappHooks{} @@ -60,14 +60,10 @@ func (h MultiRollappHooks) AfterStateFinalized(ctx sdk.Context, rollappID string return nil } -func (h MultiRollappHooks) OnHardFork(ctx sdk.Context, rollappID string, height uint64) error { +func (h MultiRollappHooks) OnHardFork(ctx sdk.Context, rollappID string, height uint64) { for i := range h { - err := h[i].OnHardFork(ctx, rollappID, height) - if err != nil { - return err - } + h[i].OnHardFork(ctx, rollappID, height) } - return nil } // RollappCreated implements RollappHooks. @@ -103,7 +99,7 @@ func (StubRollappCreatedHooks) BeforeUpdateState(sdk.Context, string, string, bo func (StubRollappCreatedHooks) AfterUpdateState(sdk.Context, string, *StateInfo) error { return nil } -func (StubRollappCreatedHooks) OnHardFork(sdk.Context, string, uint64) error { return nil } +func (StubRollappCreatedHooks) OnHardFork(sdk.Context, string, uint64) {} func (StubRollappCreatedHooks) AfterStateFinalized(sdk.Context, string, *StateInfo) error { return nil } diff --git a/x/sequencer/keeper/fraud_test.go b/x/sequencer/keeper/fraud_test.go index 7440fd453..3852a8586 100644 --- a/x/sequencer/keeper/fraud_test.go +++ b/x/sequencer/keeper/fraud_test.go @@ -93,8 +93,8 @@ 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().RollappHooks().OnHardFork(s.Ctx, ra.RollappId, 0) - s.Require().NoError(err) + s.k().RollappHooks().OnHardFork(s.Ctx, ra.RollappId, 0) + // 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))) diff --git a/x/sequencer/keeper/hook_listener.go b/x/sequencer/keeper/hook_listener.go index 4dc208ddb..7c2cb2476 100644 --- a/x/sequencer/keeper/hook_listener.go +++ b/x/sequencer/keeper/hook_listener.go @@ -37,15 +37,13 @@ func (hook rollappHook) BeforeUpdateState(ctx sdk.Context, seqAddr, rollappId st // 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 { +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappID string, _ uint64) { err := hook.k.optOutAllSequencers(ctx, rollappID) if err != nil { - return errorsmod.Wrap(err, "opt out all sequencers") + hook.k.Logger(ctx).Error("failed to opt out all sequencers", "error", err) } // clear current proposer and successor hook.k.SetProposer(ctx, rollappID, types.SentinelSeqAddr) hook.k.SetSuccessor(ctx, rollappID, types.SentinelSeqAddr) - - return nil } From e3181803ec9244afba69bfd315c3a2922bb107f7 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 13:12:37 +0200 Subject: [PATCH 36/68] rotation doesn't go through sentinel proposer --- x/rollapp/keeper/msg_server_update_state.go | 2 +- x/sequencer/keeper/proposer.go | 1 + x/sequencer/keeper/rotation.go | 14 +++++++------- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/x/rollapp/keeper/msg_server_update_state.go b/x/rollapp/keeper/msg_server_update_state.go index d79f79c02..b82be8db5 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -143,7 +143,7 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) FinalizationQueue: newFinalizationQueue, }) - // FIXME: only single save can be done + // 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") diff --git a/x/sequencer/keeper/proposer.go b/x/sequencer/keeper/proposer.go index a15e7d0f7..a486df3d0 100644 --- a/x/sequencer/keeper/proposer.go +++ b/x/sequencer/keeper/proposer.go @@ -85,6 +85,7 @@ func (k Keeper) chooseSuccessor(ctx sdk.Context, rollapp string) error { // a valid successor is already set so there's no need to do anything return nil } + // FIXME: why it's needed? proposer := k.GetProposer(ctx, rollapp) if proposer.Sentinel() { return nil diff --git a/x/sequencer/keeper/rotation.go b/x/sequencer/keeper/rotation.go index a748e0052..05bd320e5 100644 --- a/x/sequencer/keeper/rotation.go +++ b/x/sequencer/keeper/rotation.go @@ -80,17 +80,17 @@ 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) - // FIXME: shouldn't go through sentinel, as it considered hard fork - if err := k.UpdateProposerIfNeeded(ctx, proposer.RollappId); err != nil { - return errorsmod.Wrap(err, "choose proposer") - } - after := k.GetProposer(ctx, proposer.RollappId) + rollapp := proposer.RollappId + + successor := k.GetSuccessor(ctx, rollapp) + k.SetProposer(ctx, rollapp, successor.Address) + k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) + 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 From 5ec9170d3945dad2629e7225732b9da8bc8e0fb3 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 13:21:09 +0200 Subject: [PATCH 37/68] simplified k.UpdateRollappPacketWithStatus interface --- app/ante/reject_msgs.go | 3 ++- x/delayedack/keeper/finalize.go | 2 +- x/delayedack/keeper/fraud_test.go | 4 ++-- x/delayedack/keeper/hooks_test.go | 2 +- x/delayedack/keeper/rollapp_packet.go | 10 +++------- x/delayedack/keeper/rollapp_packet_test.go | 6 ++---- x/eibc/keeper/hooks_test.go | 4 ++-- x/eibc/keeper/msg_server_test.go | 2 +- x/sequencer/keeper/proposer.go | 4 ++-- 9 files changed, 16 insertions(+), 21 deletions(-) diff --git a/app/ante/reject_msgs.go b/app/ante/reject_msgs.go index 00fb75271..e56f9b8a8 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" @@ -41,7 +42,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/x/delayedack/keeper/finalize.go b/x/delayedack/keeper/finalize.go index 0323ff6f9..d3b7dfdf9 100644 --- a/x/delayedack/keeper/finalize.go +++ b/x/delayedack/keeper/finalize.go @@ -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) } diff --git a/x/delayedack/keeper/fraud_test.go b/x/delayedack/keeper/fraud_test.go index f1bdb1236..6ad6dcafb 100644 --- a/x/delayedack/keeper/fraud_test.go +++ b/x/delayedack/keeper/fraud_test.go @@ -29,9 +29,9 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { suite.Require().Equal(20, len(pktsByAddr)) // finalize one packet - _, err = keeper.UpdateRollappPacketWithStatus(ctx, pkts[0], commontypes.Status_FINALIZED) + _, err = keeper.UpdateRollappPacketAfterFinalization(ctx, pkts[0]) suite.Require().Nil(err) - _, err = keeper.UpdateRollappPacketWithStatus(ctx, pkts2[0], commontypes.Status_FINALIZED) + _, err = keeper.UpdateRollappPacketAfterFinalization(ctx, pkts2[0]) suite.Require().Nil(err) // call fraud on the 4 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/rollapp_packet.go b/x/delayedack/keeper/rollapp_packet.go index d60c8a998..745d06ea2 100644 --- a/x/delayedack/keeper/rollapp_packet.go +++ b/x/delayedack/keeper/rollapp_packet.go @@ -1,7 +1,6 @@ package keeper import ( - "errors" "fmt" "cosmossdk.io/collections" @@ -153,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 { @@ -184,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) diff --git a/x/delayedack/keeper/rollapp_packet_test.go b/x/delayedack/keeper/rollapp_packet_test.go index 53a573be0..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) @@ -182,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/eibc/keeper/hooks_test.go b/x/eibc/keeper/hooks_test.go index 6d3a24587..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) @@ -64,7 +64,7 @@ func (suite *KeeperTestSuite) TestAfterRollappPacketDeleted() { // Update rollapp packet status if tc.packetStatus == commontypes.Status_FINALIZED { - _, err = suite.App.DelayedAckKeeper.UpdateRollappPacketWithStatus(suite.Ctx, *rollappPacket, tc.packetStatus) + _, err = suite.App.DelayedAckKeeper.UpdateRollappPacketAfterFinalization(suite.Ctx, *rollappPacket) suite.Require().NoError(err) } diff --git a/x/eibc/keeper/msg_server_test.go b/x/eibc/keeper/msg_server_test.go index 0dca13697..70230f692 100644 --- a/x/eibc/keeper/msg_server_test.go +++ b/x/eibc/keeper/msg_server_test.go @@ -116,7 +116,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, *rollappPacket, tc.demandOrderUnderlyingPacketStatus) + _, err = suite.App.DelayedAckKeeper.UpdateRollappPacketAfterFinalization(suite.Ctx, *rollappPacket) suite.Require().NoError(err, tc.name) } diff --git a/x/sequencer/keeper/proposer.go b/x/sequencer/keeper/proposer.go index a486df3d0..155f97d59 100644 --- a/x/sequencer/keeper/proposer.go +++ b/x/sequencer/keeper/proposer.go @@ -34,7 +34,7 @@ func (k Keeper) RollappPotentialProposers(ctx sdk.Context, rollappId string) []t seqs = slices.DeleteFunc(seqs, func(seq types.Sequencer) bool { return !seq.IsPotentialProposer() }) - // FIXME: sentinel should be added only if no sequencers are bonded + // FIXME: sentinel can be added only if no sequencers are bonded return append(seqs, k.SentinelSequencer(ctx)) } @@ -85,7 +85,7 @@ func (k Keeper) chooseSuccessor(ctx sdk.Context, rollapp string) error { // a valid successor is already set so there's no need to do anything return nil } - // FIXME: why it's needed? + // FIXME: why this check needed? proposer := k.GetProposer(ctx, rollapp) if proposer.Sentinel() { return nil From 7c40f539e78417ce26091cb64ccd94fcfd5fdf9d Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 14:15:07 +0200 Subject: [PATCH 38/68] minor --- x/rollapp/keeper/hard_fork.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index 91bfa30b9..8170c5721 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -2,6 +2,7 @@ package keeper import ( "fmt" + "sort" errorsmod "cosmossdk.io/errors" @@ -184,5 +185,6 @@ func mapKeysToSlice(m map[string]struct{}) []string { for k := range m { keys = append(keys, k) } + sort.Strings(keys) return keys } From 5a3f9b50c2d959f51e144b9582c3b6bfc31511c0 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 6 Nov 2024 14:54:59 +0200 Subject: [PATCH 39/68] minor log --- x/delayedack/keeper/fraud.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 4e81f8937..9d13b04ae 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -54,7 +54,7 @@ func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64 // delete the pending packet err = k.DeletePendingPacketByAddress(ctx, pendingAddr, rollappPacket.RollappPacketKey()) if err != nil { - logger.Error("failed to delete reverted pending packet", append(logContext, "error", err.Error())...) + logger.Error("failed to delete reverted PacketByAddress", append(logContext, "error", err.Error())...) continue } From 6914afb35baf76b4ceb7ea55e454347343d3c4b9 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Thu, 7 Nov 2024 15:41:25 +0200 Subject: [PATCH 40/68] fixed lightclient when setting canonical channel --- x/lightclient/keeper/hook_listener.go | 11 ++++++----- x/lightclient/keeper/rollback.go | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/x/lightclient/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index a340362cd..606951b3f 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -44,11 +44,6 @@ func (hook rollappHook) AfterUpdateState( client, ok = hook.k.GetProspectiveCanonicalClient(ctx, rollappId, stateInfo.GetLatestHeight()-1) if ok { hook.k.SetCanonicalClient(ctx, rollappId, client) - // we now verified everything up to and including stateInfo.GetLatestHeight()-1 - // so we should prune everything up to stateInfo.GetLatestHeight()-1 - if err := hook.k.PruneSignersBelow(ctx, rollappId, stateInfo.GetLatestHeight()); err != nil { - return errorsmod.Wrap(err, "prune signers") - } } return nil } @@ -70,6 +65,12 @@ func (hook rollappHook) AfterUpdateState( return errorsmod.Wrap(err, "validate optimistic update") } } + // we now verified everything up to and including stateInfo.GetLatestHeight()-1 + // so we should prune everything up to stateInfo.GetLatestHeight()-1 + if err := hook.k.PruneSignersBelow(ctx, rollappId, stateInfo.GetLatestHeight()); err != nil { + return errorsmod.Wrap(err, "prune signers") + } + return nil } diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index ef2def348..f67181077 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -75,6 +75,7 @@ func (k Keeper) ResolveHardFork(ctx sdk.Context, rollappID string) { } setConsensusState(clientStore, k.cdc, clienttypes.NewHeight(1, height), &cs) + _ = k.SaveSigner(ctx, proposer.Address, client, height) k.setHardForkResolved(ctx, rollappID) } From 47be8d350da61c828c1b5fc7cfb8690b56788e8b Mon Sep 17 00:00:00 2001 From: keruch <53012408+keruch@users.noreply.github.com> Date: Fri, 8 Nov 2024 13:03:28 +0300 Subject: [PATCH 41/68] feat(migrations): renamed vulnerable rollapps to obsolete (#1436) --- .../dymension/rollapp/events.proto | 8 +- .../dymension/rollapp/genesis.proto | 4 +- proto/dymensionxyz/dymension/rollapp/tx.proto | 10 +- x/rollapp/genesis.go | 10 +- x/rollapp/keeper/keeper.go | 8 +- ...o => msg_server_mark_obsolete_rollapps.go} | 46 ++-- ...msg_server_mark_obsolete_rollapps_test.go} | 92 +++---- x/rollapp/keeper/msg_server_update_state.go | 18 +- .../keeper/msg_server_update_state_test.go | 20 +- x/rollapp/keeper/rollapp.go | 14 +- x/rollapp/types/events.pb.go | 92 +++---- x/rollapp/types/genesis.go | 12 +- x/rollapp/types/genesis.pb.go | 102 +++---- x/rollapp/types/genesis_test.go | 6 +- x/rollapp/types/keys.go | 2 +- ...s.go => message_mark_obsolete_rollapps.go} | 6 +- x/rollapp/types/tx.pb.go | 258 +++++++++--------- 17 files changed, 354 insertions(+), 354 deletions(-) rename x/rollapp/keeper/{msg_server_mark_vulnerable_rollapps.go => msg_server_mark_obsolete_rollapps.go} (53%) rename x/rollapp/keeper/{msg_server_mark_vulnerable_rollapps_test.go => msg_server_mark_obsolete_rollapps_test.go} (55%) rename x/rollapp/types/{message_mark_vunerable_rollapps.go => message_mark_obsolete_rollapps.go} (76%) 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/genesis.proto b/proto/dymensionxyz/dymension/rollapp/genesis.proto index 6e179295c..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 { diff --git a/proto/dymensionxyz/dymension/rollapp/tx.proto b/proto/dymensionxyz/dymension/rollapp/tx.proto index 47bd3c509..56ef6e574 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. @@ -170,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/x/rollapp/genesis.go b/x/rollapp/genesis.go index 0aa090ae3..615e1c986 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) } @@ -106,11 +106,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/keeper/keeper.go b/x/rollapp/keeper/keeper.go index e4e1663b1..12008e706 100644 --- a/x/rollapp/keeper/keeper.go +++ b/x/rollapp/keeper/keeper.go @@ -30,7 +30,7 @@ type Keeper struct { bankKeeper BankKeeper transferKeeper TransferKeeper - vulnerableDRSVersions collections.KeySet[uint32] + obsoleteDRSVersions collections.KeySet[uint32] registeredRollappDenoms collections.KeySet[collections.Pair[string, string]] finalizePending func(ctx sdk.Context, stateInfoIndex types.StateInfoIndex) error @@ -74,10 +74,10 @@ func NewKeeper( 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]]( diff --git a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go b/x/rollapp/keeper/msg_server_mark_obsolete_rollapps.go similarity index 53% rename from x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go rename to x/rollapp/keeper/msg_server_mark_obsolete_rollapps.go index 89d256820..3766bb560 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go +++ b/x/rollapp/keeper/msg_server_mark_obsolete_rollapps.go @@ -13,48 +13,48 @@ import ( "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) -func (k msgServer) MarkVulnerableRollapps(goCtx context.Context, msg *types.MsgMarkVulnerableRollapps) (*types.MsgMarkVulnerableRollappsResponse, error) { +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 vulnerable rollapps") + return nil, errorsmod.Wrap(gerrc.ErrInvalidArgument, "only the gov module can mark obsolete rollapps") } ctx := sdk.UnwrapSDKContext(goCtx) - vulnerableNum, err := k.Keeper.MarkVulnerableRollapps(ctx, msg.DrsVersions) + obsoleteNum, err := k.Keeper.MarkObsoleteRollapps(ctx, msg.DrsVersions) if err != nil { - return nil, fmt.Errorf("mark vulnerable rollapps: %w", err) + return nil, fmt.Errorf("mark obsolete rollapps: %w", err) } - err = uevent.EmitTypedEvent(ctx, &types.EventMarkVulnerableRollapps{ - VulnerableRollappNum: uint64(vulnerableNum), - DrsVersions: msg.DrsVersions, + 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.MsgMarkVulnerableRollappsResponse{}, nil + return &types.MsgMarkObsoleteRollappsResponse{}, nil } -func (k Keeper) MarkVulnerableRollapps(ctx sdk.Context, drsVersions []uint32) (int, error) { - vulnerableVersions := make(map[uint32]struct{}) +func (k Keeper) MarkObsoleteRollapps(ctx sdk.Context, drsVersions []uint32) (int, error) { + obsoleteVersions := 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) + 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 vulnerable DRS version: %w", err) + return 0, fmt.Errorf("set obsolete DRS version: %w", err) } } var ( - logger = k.Logger(ctx) - vulnerableNum int + logger = k.Logger(ctx) + obsoleteNum int ) for _, rollapp := range k.GetAllRollapps(ctx) { info, found := k.GetLatestStateInfo(ctx, rollapp.RollappId) @@ -63,23 +63,23 @@ func (k Keeper) MarkVulnerableRollapps(ctx sdk.Context, drsVersions []uint32) (i 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 + // 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] - _, vulnerable := vulnerableVersions[bd.DrsVersion] - if vulnerable { + _, 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 vulnerable + // 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 vulnerable") + Error("Failed to mark rollapp as obsolete") } - vulnerableNum++ + obsoleteNum++ } } - return vulnerableNum, nil + 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 55% 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 8cf505654..6e5668e37 100644 --- a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps_test.go +++ b/x/rollapp/keeper/msg_server_mark_obsolete_rollapps_test.go @@ -13,7 +13,7 @@ import ( "github.com/dymensionxyz/dymension/v3/x/rollapp/types" ) -func (s *RollappTestSuite) TestMarkVulnerableRollapps() { +func (s *RollappTestSuite) TestMarkObsoleteRollapps() { type rollapp struct { name string drsVersion uint32 @@ -21,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", @@ -38,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, }, @@ -51,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, @@ -67,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}, @@ -84,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, @@ -98,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, @@ -110,11 +110,11 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { s.SetupTest() // prepare test data - vulnVersions := uslice.ToKeySet(tc.vulnVersions) - // list of expected vulnerable rollapps - expectedVulnRollappIDs := make([]string, 0, len(tc.rollapps)) - // list of expected non-vulnerable rollapps - expectedNonVulnRollappIDs := make([]string, 0, len(tc.rollapps)) + 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 @@ -127,17 +127,17 @@ 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 @@ -145,44 +145,44 @@ func (s *RollappTestSuite) TestMarkVulnerableRollapps() { 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, FilterNonForked) - 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, FilterForked) - 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, FilterNonForked) - 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, FilterForked) - 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) } }) } diff --git a/x/rollapp/keeper/msg_server_update_state.go b/x/rollapp/keeper/msg_server_update_state.go index b82be8db5..78f14494f 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -97,16 +97,16 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) val.Address, ) - // verify the DRS version is not vulnerable - // check only last block descriptor DRS, since if that last is not vulnerable it means the rollapp already upgraded and is not vulnerable anymore - // Rollapp is using a vulnerable DRS version, hard fork it - if k.IsStateUpdateVulnerable(ctx, stateInfo) { + // 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 + // Rollapp is using a obsolete DRS version, hard fork it + if k.IsStateUpdateObsolete(ctx, stateInfo) { err := k.HardForkToLatest(ctx, msg.RollappId) if err != nil { - return nil, fmt.Errorf("mark rollapp vulnerable: %w", err) + return nil, fmt.Errorf("mark rollapp obsolete: %w", err) } k.Logger(ctx).With("rollapp_id", msg.RollappId, "drs_version", stateInfo.GetLatestBlockDescriptor().DrsVersion). - Info("rollapp tried to submit MsgUpdateState with the vulnerable DRS version, mark the rollapp as vulnerable") + Info("rollapp tried to submit MsgUpdateState with the obsolete DRS version, mark the rollapp as obsolete") // we must return non-error if we want the changes to be saved return &types.MsgUpdateStateResponse{}, nil @@ -166,7 +166,7 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) return &types.MsgUpdateStateResponse{}, nil } -// IsStateUpdateVulnerable checks if the given DRS version is vulnerable -func (k msgServer) IsStateUpdateVulnerable(ctx sdk.Context, stateInfo *types.StateInfo) bool { - return k.IsDRSVersionVulnerable(ctx, stateInfo.GetLatestBlockDescriptor().DrsVersion) +// 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 a1c8d4d0f..d01373fd1 100644 --- a/x/rollapp/keeper/msg_server_update_state_test.go +++ b/x/rollapp/keeper/msg_server_update_state_test.go @@ -97,11 +97,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 @@ -109,20 +109,20 @@ func (s *RollappTestSuite) TestUpdateStateVulnerableRollapp() { // create a sequencer proposer := s.CreateDefaultSequencer(s.Ctx, raName) - // create the initial state update with non-vulnerable version - expectedNextHeight, 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(expectedNextHeight-1, actualLastHeight) - // mark a DRS version as vulnerable - err = s.App.RollappKeeper.SetVulnerableDRSVersion(s.Ctx, vulnerableVersion) + // mark a DRS version as obsolete + err = s.App.RollappKeeper.SetObsoleteDRSVersion(s.Ctx, obsoleteVersion) s.Require().NoError(err) - // create a new update using the vulnerable version - _, err = s.PostStateUpdateWithDRSVersion(s.Ctx, raName, proposer, expectedNextHeight, uint64(3), vulnerableVersion) + // create a new update using the obsolete version + _, err = s.PostStateUpdateWithDRSVersion(s.Ctx, raName, proposer, expectedNextHeight, uint64(3), obsoleteVersion) s.Require().NoError(err) s.assertFraudHandled(raName, expectedNextHeight) diff --git a/x/rollapp/keeper/rollapp.go b/x/rollapp/keeper/rollapp.go index a70383950..15cd51850 100644 --- a/x/rollapp/keeper/rollapp.go +++ b/x/rollapp/keeper/rollapp.go @@ -303,20 +303,20 @@ func (k Keeper) FilterRollapps(ctx sdk.Context, f func(types.Rollapp) bool) []ty return result } -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/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/genesis.go b/x/rollapp/types/genesis.go index b2d129a70..9feb1def3 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 401528206..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,44 +265,44 @@ func init() { } var fileDescriptor_b76890aebc09aa04 = []byte{ - // 592 bytes of a gzipped FileDescriptorProto + // 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, 0x14, 0x6a, 0x45, 0xd4, 0x44, 0x41, - 0x82, 0x20, 0xa8, 0x2d, 0x35, 0x08, 0x76, 0x48, 0x84, 0xf0, 0x27, 0xa2, 0x82, 0xe0, 0x02, 0x0b, - 0x58, 0x44, 0x4e, 0x7c, 0xeb, 0x8c, 0x70, 0x66, 0x8c, 0x67, 0x12, 0x25, 0x79, 0x0a, 0x16, 0xbc, - 0x0a, 0xef, 0xd0, 0x65, 0x97, 0xac, 0x10, 0x4a, 0x5e, 0x04, 0x79, 0x3c, 0x76, 0x43, 0xdb, 0xc4, - 0x91, 0x58, 0x39, 0xe3, 0x39, 0xf7, 0x77, 0x8e, 0x6f, 0xae, 0x2e, 0x7a, 0xe0, 0x8e, 0xfb, 0x40, - 0x39, 0x61, 0x74, 0x34, 0x9e, 0x58, 0xe9, 0xc1, 0x0a, 0x99, 0xef, 0x3b, 0x41, 0x60, 0x79, 0x40, - 0x81, 0x13, 0x6e, 0x06, 0x21, 0x13, 0x0c, 0x1b, 0xf3, 0x6a, 0x33, 0x3d, 0x98, 0x4a, 0x5d, 0xda, - 0xf1, 0x98, 0xc7, 0xa4, 0xd4, 0x8a, 0x7e, 0xc5, 0x55, 0xa5, 0xfb, 0x19, 0x1e, 0x81, 0x13, 0x3a, - 0x7d, 0x65, 0x51, 0xca, 0x0a, 0xa4, 0x9e, 0x4a, 0x6d, 0x65, 0xa8, 0xb9, 0x70, 0x04, 0xb4, 0x09, - 0x3d, 0x4e, 0xb2, 0xec, 0x67, 0x14, 0xf8, 0x64, 0x18, 0x7d, 0x71, 0x92, 0xa6, 0x9a, 0x21, 0x4f, - 0x93, 0x54, 0x7e, 0x6c, 0xa1, 0xff, 0x5f, 0xc6, 0xcd, 0x3a, 0x8a, 0x4c, 0x71, 0x03, 0xe5, 0xe3, - 0x0f, 0xd3, 0xb5, 0xb2, 0x56, 0x2d, 0x1e, 0xdc, 0x31, 0x97, 0x37, 0xcf, 0x6c, 0x49, 0x75, 0x7d, - 0xe3, 0xe4, 0xd7, 0xad, 0x9c, 0xad, 0x6a, 0xf1, 0x5b, 0x54, 0x54, 0xf7, 0x87, 0x84, 0x0b, 0x7d, - 0xad, 0xbc, 0x5e, 0x2d, 0x1e, 0xdc, 0xcd, 0x42, 0xd9, 0xf1, 0x53, 0xb1, 0xe6, 0x09, 0xf8, 0x03, - 0xda, 0x96, 0x4d, 0x69, 0xd2, 0x63, 0x26, 0x91, 0xeb, 0x12, 0x79, 0x2f, 0x0b, 0x79, 0x94, 0x14, - 0x29, 0xe8, 0xdf, 0x14, 0x1c, 0x20, 0xdd, 0x77, 0x04, 0x70, 0x91, 0xea, 0x9a, 0xd4, 0x85, 0x91, - 0x74, 0xd8, 0x90, 0x0e, 0xe6, 0xca, 0x0e, 0xb2, 0x52, 0xd9, 0x2c, 0xa4, 0xe2, 0x09, 0xda, 0x8b, - 0xef, 0x5e, 0x10, 0xea, 0xf8, 0x64, 0x02, 0xae, 0x12, 0x25, 0xb6, 0xff, 0xfd, 0x83, 0xed, 0x72, - 0x34, 0xfe, 0xae, 0xa1, 0x4a, 0xc7, 0x67, 0xdd, 0x2f, 0xaf, 0x80, 0x78, 0x3d, 0xf1, 0x9e, 0x29, - 0xa1, 0x23, 0x08, 0xa3, 0xef, 0x06, 0x30, 0x00, 0x99, 0x20, 0x2f, 0x13, 0x3c, 0xc9, 0x4a, 0x50, - 0x5f, 0x4a, 0x52, 0x89, 0x56, 0xf0, 0xc3, 0x9f, 0xd1, 0x95, 0x64, 0x7e, 0x9f, 0x0f, 0x81, 0x0a, - 0xae, 0x6f, 0xca, 0x04, 0xfb, 0x59, 0x09, 0x0e, 0xe7, 0xab, 0x94, 0xe1, 0x39, 0x14, 0x7e, 0x86, - 0x36, 0x93, 0x29, 0xdc, 0x92, 0xd4, 0xdb, 0x59, 0xd4, 0xa7, 0xe9, 0x04, 0x26, 0x95, 0x98, 0xa0, - 0xab, 0x21, 0x78, 0x84, 0x0b, 0x08, 0xc1, 0x6d, 0x00, 0x65, 0x7d, 0xae, 0x17, 0x24, 0xed, 0xf1, - 0x8a, 0x33, 0x6d, 0x9f, 0x2b, 0x57, 0x0e, 0x17, 0xb0, 0xb8, 0x8f, 0x76, 0x38, 0x7c, 0x1d, 0x00, - 0xed, 0x42, 0x18, 0xb7, 0xad, 0xe5, 0x90, 0x90, 0xeb, 0x48, 0xda, 0xd5, 0x32, 0xc7, 0xe2, 0x62, - 0xad, 0xb2, 0xba, 0x14, 0x8b, 0x1f, 0xa1, 0xdd, 0xe1, 0xc0, 0xa7, 0x10, 0x3a, 0x1d, 0x1f, 0xda, - 0x6e, 0xc8, 0xdb, 0x43, 0x08, 0x23, 0x22, 0xd7, 0x8b, 0xe5, 0xf5, 0xea, 0xb6, 0x7d, 0xfd, 0xec, - 0xba, 0x11, 0xf2, 0x8f, 0xea, 0xb2, 0xf2, 0x1a, 0x5d, 0xbb, 0xc4, 0x0a, 0xdf, 0x44, 0x85, 0xd4, - 0x46, 0x2e, 0x90, 0x82, 0x7d, 0xf6, 0x02, 0xdf, 0x40, 0xf9, 0x9e, 0xd4, 0xea, 0x6b, 0x65, 0xad, - 0xba, 0x61, 0xab, 0x53, 0xa5, 0x85, 0x76, 0x17, 0xb4, 0x09, 0xef, 0x21, 0xa4, 0x3e, 0xad, 0x4d, - 0xdc, 0x84, 0xa8, 0xde, 0x34, 0xdd, 0x88, 0xe8, 0xc6, 0x7f, 0x47, 0xb4, 0x62, 0x0a, 0xb6, 0x3a, - 0xd5, 0xdf, 0x9c, 0x4c, 0x0d, 0xed, 0x74, 0x6a, 0x68, 0xbf, 0xa7, 0x86, 0xf6, 0x6d, 0x66, 0xe4, - 0x4e, 0x67, 0x46, 0xee, 0xe7, 0xcc, 0xc8, 0x7d, 0x7a, 0xe8, 0x11, 0xd1, 0x1b, 0x74, 0xcc, 0x2e, - 0xeb, 0x2f, 0xda, 0xc2, 0xc3, 0x9a, 0x35, 0x4a, 0x57, 0xa5, 0x18, 0x07, 0xc0, 0x3b, 0x79, 0xb9, - 0x2d, 0x6b, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xfb, 0xd6, 0xd7, 0x55, 0x78, 0x06, 0x00, 0x00, + 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) { @@ -325,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 @@ -629,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 @@ -1065,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 { @@ -1100,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 @@ -1119,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/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_mark_vunerable_rollapps.go b/x/rollapp/types/message_mark_obsolete_rollapps.go similarity index 76% rename from x/rollapp/types/message_mark_vunerable_rollapps.go rename to x/rollapp/types/message_mark_obsolete_rollapps.go index 4b72afe85..104f70c0a 100644 --- a/x/rollapp/types/message_mark_vunerable_rollapps.go +++ b/x/rollapp/types/message_mark_obsolete_rollapps.go @@ -8,9 +8,9 @@ import ( "github.com/dymensionxyz/gerr-cosmos/gerrc" ) -var _ sdk.Msg = new(MsgMarkVulnerableRollapps) +var _ sdk.Msg = 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")) @@ -23,7 +23,7 @@ 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} } diff --git a/x/rollapp/types/tx.pb.go b/x/rollapp/types/tx.pb.go index 4df490549..e00ef5606 100644 --- a/x/rollapp/types/tx.pb.go +++ b/x/rollapp/types/tx.pb.go @@ -916,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) @@ -946,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) @@ -996,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") @@ -1023,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() { @@ -1033,73 +1033,73 @@ func init() { var fileDescriptor_1a86300fb8647ecb = []byte{ // 1062 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0x4f, 0x6f, 0x1b, 0x45, - 0x14, 0xcf, 0xda, 0x8e, 0x63, 0x3f, 0x3b, 0xa9, 0x33, 0x44, 0x61, 0x71, 0x8b, 0x71, 0x1d, 0x21, - 0x52, 0x5a, 0x6c, 0x92, 0x06, 0x04, 0x81, 0x4b, 0xd2, 0x48, 0x6d, 0x41, 0xa6, 0xb0, 0x0d, 0x39, - 0x70, 0xb1, 0x36, 0xde, 0xc9, 0x66, 0x55, 0xef, 0x8e, 0x99, 0x19, 0x3b, 0x31, 0xdc, 0x90, 0x10, - 0x07, 0x24, 0xc4, 0x89, 0x13, 0x1f, 0x82, 0x03, 0x57, 0xae, 0xa8, 0xc7, 0x1e, 0xe1, 0x82, 0x50, - 0x72, 0xe0, 0x6b, 0xa0, 0x99, 0x9d, 0x1d, 0x3b, 0xf1, 0x9f, 0xdd, 0x04, 0x4e, 0x3b, 0xf3, 0xe6, - 0xf7, 0xfe, 0xfd, 0xde, 0x9b, 0x37, 0x5a, 0x78, 0xc3, 0x19, 0xf8, 0x38, 0x60, 0x1e, 0x09, 0x4e, - 0x07, 0x5f, 0x35, 0xf4, 0xa6, 0x41, 0x49, 0xa7, 0x63, 0x77, 0xbb, 0x0d, 0x7e, 0x5a, 0xef, 0x52, - 0xc2, 0x09, 0xaa, 0x8c, 0x02, 0xeb, 0x7a, 0x53, 0x57, 0xc0, 0xf2, 0xcb, 0x6d, 0xc2, 0x7c, 0xc2, - 0x1a, 0x3e, 0x73, 0x1b, 0xfd, 0x0d, 0xf1, 0x09, 0x15, 0xcb, 0xef, 0xc4, 0x78, 0x38, 0xec, 0x90, - 0xf6, 0xb3, 0x96, 0x83, 0x59, 0x9b, 0x7a, 0x5d, 0x4e, 0xa8, 0x52, 0xbb, 0x17, 0xa3, 0xa6, 0xbe, - 0x0a, 0xfd, 0x56, 0x0c, 0xda, 0xc7, 0xdc, 0x76, 0x6c, 0x6e, 0x2b, 0xf8, 0x46, 0x0c, 0xdc, 0xc5, - 0x01, 0x66, 0x1e, 0x6b, 0x79, 0xc1, 0x11, 0x51, 0x2a, 0x2b, 0x2e, 0x71, 0x89, 0x5c, 0x36, 0xc4, - 0x2a, 0x94, 0xd6, 0x7e, 0x48, 0x43, 0xa9, 0xc9, 0xdc, 0x07, 0x14, 0xdb, 0x1c, 0x5b, 0xa1, 0x36, - 0x32, 0x61, 0xa1, 0x2d, 0x04, 0x84, 0x9a, 0x46, 0xd5, 0x58, 0xcf, 0x5b, 0xd1, 0x16, 0xbd, 0x0a, - 0xa0, 0x5c, 0xb4, 0x3c, 0xc7, 0x4c, 0xc9, 0xc3, 0xbc, 0x92, 0x3c, 0x76, 0xd0, 0x5d, 0x58, 0xf6, - 0x02, 0x8f, 0x7b, 0x76, 0xa7, 0xc5, 0xf0, 0x97, 0x3d, 0x1c, 0xb4, 0x31, 0x35, 0x0b, 0x12, 0x55, - 0x52, 0x07, 0x4f, 0x23, 0x39, 0x5a, 0x81, 0x79, 0xbb, 0xe3, 0xd9, 0xcc, 0x2c, 0x4a, 0x40, 0xb8, - 0x41, 0x1f, 0x43, 0x2e, 0xca, 0xd5, 0x5c, 0xac, 0x1a, 0xeb, 0x85, 0xcd, 0x46, 0x7d, 0x76, 0xe5, - 0xea, 0x2a, 0xec, 0xa6, 0x52, 0xb3, 0xb4, 0x01, 0xb4, 0x0f, 0xc5, 0x51, 0x26, 0xcc, 0x25, 0x69, - 0xf0, 0x6e, 0x9c, 0xc1, 0x87, 0xa1, 0xce, 0xe3, 0xe0, 0x88, 0xec, 0x66, 0x9e, 0xff, 0xf5, 0x9a, - 0x61, 0x15, 0xdc, 0xa1, 0x08, 0x3d, 0x84, 0x85, 0xbe, 0xdf, 0xe2, 0x83, 0x2e, 0x36, 0x6f, 0x54, - 0x8d, 0xf5, 0xa5, 0xcd, 0x7a, 0xc2, 0x08, 0xeb, 0x07, 0xcd, 0xfd, 0x41, 0x17, 0x5b, 0xd9, 0xbe, - 0x2f, 0xbe, 0xdb, 0xc5, 0x6f, 0xfe, 0xf9, 0xe5, 0xcd, 0x88, 0xdb, 0x8f, 0x32, 0xb9, 0x74, 0xa9, - 0x50, 0x2b, 0x83, 0x79, 0xb9, 0x1e, 0x16, 0x66, 0x5d, 0x12, 0x30, 0x5c, 0xfb, 0x35, 0x05, 0x37, - 0x9b, 0xcc, 0xfd, 0xbc, 0xeb, 0x0c, 0x0f, 0x45, 0x44, 0xd4, 0xb7, 0xb9, 0x47, 0x02, 0xc1, 0x28, - 0x39, 0x09, 0x70, 0x54, 0xb5, 0x70, 0x73, 0xad, 0x9a, 0xa5, 0xa7, 0xd4, 0xec, 0xb3, 0x91, 0xea, - 0xcc, 0x5f, 0xab, 0x3a, 0x8a, 0xd0, 0xe9, 0x35, 0xca, 0xfe, 0x1f, 0x35, 0xda, 0x06, 0x41, 0x6d, - 0x48, 0x40, 0xed, 0x75, 0x58, 0x9b, 0xc1, 0x9a, 0x66, 0xf7, 0xb7, 0x14, 0x2c, 0x69, 0xdc, 0x53, - 0x6e, 0x73, 0x3c, 0xe3, 0x22, 0xdc, 0x82, 0x21, 0x85, 0xe3, 0x9c, 0x56, 0xa1, 0xc0, 0xb8, 0x4d, - 0xf9, 0x23, 0xec, 0xb9, 0xc7, 0x5c, 0xb2, 0x99, 0xb1, 0x46, 0x45, 0x42, 0x3f, 0xe8, 0xf9, 0xbb, - 0x62, 0x74, 0x30, 0x33, 0x23, 0xcf, 0x87, 0x02, 0xb4, 0x0a, 0xd9, 0xbd, 0x9d, 0x4f, 0x6d, 0x7e, - 0x2c, 0x49, 0xce, 0x5b, 0x6a, 0x87, 0x1e, 0x41, 0x7a, 0x77, 0x8f, 0x99, 0x0b, 0x92, 0xa2, 0xb7, - 0xe3, 0x28, 0x92, 0xc6, 0xf6, 0xf4, 0x5c, 0x62, 0x92, 0xa7, 0x39, 0x4b, 0x98, 0x40, 0x08, 0x32, - 0x1d, 0x9b, 0x71, 0x33, 0x57, 0x35, 0xd6, 0x73, 0x96, 0x5c, 0xa3, 0x3b, 0x50, 0x8a, 0x1a, 0x85, - 0xe2, 0xbe, 0x27, 0x6c, 0x99, 0x79, 0x19, 0xda, 0x0d, 0x1a, 0x75, 0x62, 0x28, 0x1e, 0xeb, 0xdc, - 0x6c, 0x69, 0xa1, 0x66, 0xc2, 0xea, 0x45, 0xfa, 0x34, 0xb3, 0xdf, 0x1b, 0xb0, 0xd2, 0x64, 0xee, - 0x3e, 0xb5, 0x03, 0x76, 0x84, 0xe9, 0x13, 0x51, 0x15, 0x76, 0xec, 0x75, 0xd1, 0x1a, 0x2c, 0xb6, - 0x7b, 0x94, 0xe2, 0x80, 0xb7, 0x46, 0x1b, 0xb7, 0xa8, 0x84, 0x12, 0x88, 0x6e, 0x42, 0x3e, 0xc0, - 0x27, 0x0a, 0x10, 0x52, 0x9d, 0x0b, 0xf0, 0xc9, 0x93, 0x09, 0xcd, 0x9d, 0xbe, 0x54, 0x88, 0x6d, - 0x24, 0xe2, 0xbc, 0xe8, 0xa3, 0x56, 0x81, 0x5b, 0x93, 0x82, 0xd1, 0xd1, 0xfe, 0x6e, 0x40, 0xbe, - 0xc9, 0xdc, 0x1d, 0xc7, 0xd9, 0x99, 0x39, 0x0b, 0x11, 0x64, 0x02, 0xdb, 0xc7, 0x2a, 0x24, 0xb9, - 0x8e, 0x09, 0x47, 0xf4, 0x45, 0xf4, 0x4e, 0x08, 0x72, 0x33, 0xf2, 0x7c, 0x54, 0x24, 0xae, 0xb0, - 0xe7, 0xdb, 0x2e, 0x56, 0x85, 0x0f, 0x37, 0xa8, 0x04, 0xe9, 0x1e, 0xed, 0xc8, 0xab, 0x91, 0xb7, - 0xc4, 0x52, 0x5e, 0x75, 0xea, 0x60, 0x2a, 0x7b, 0x61, 0xde, 0x0a, 0x37, 0x17, 0xcb, 0x52, 0x7b, - 0x09, 0x96, 0x75, 0x1e, 0x3a, 0xbb, 0x3f, 0x0d, 0x28, 0xea, 0x32, 0xcd, 0x4e, 0x70, 0x09, 0x52, - 0x6a, 0x60, 0x64, 0xac, 0x94, 0xe7, 0xe8, 0x84, 0xd3, 0x53, 0x13, 0xce, 0xc4, 0x24, 0x3c, 0x3f, - 0x23, 0xe1, 0xec, 0x84, 0x84, 0x17, 0x26, 0x24, 0x9c, 0x9b, 0x9e, 0xf0, 0xaa, 0x6c, 0x33, 0x9d, - 0x9a, 0xce, 0x19, 0xcb, 0x94, 0x2d, 0xec, 0x93, 0xfe, 0x15, 0x53, 0x8e, 0x69, 0xaf, 0x49, 0xee, - 0xb5, 0x1b, 0xed, 0xbe, 0x03, 0xaf, 0x34, 0x99, 0xdb, 0xb4, 0xe9, 0xb3, 0x83, 0x5e, 0x27, 0xc0, - 0xd4, 0x3e, 0xec, 0x44, 0x73, 0x88, 0x89, 0x41, 0x60, 0xf7, 0xf8, 0x31, 0xa1, 0x1e, 0x1f, 0xa8, - 0x68, 0x86, 0x02, 0x74, 0x1b, 0x8a, 0x0e, 0x65, 0xad, 0x3e, 0xa6, 0xe2, 0xda, 0x31, 0x33, 0x55, - 0x4d, 0xaf, 0x2f, 0x5a, 0x05, 0x87, 0xb2, 0x03, 0x25, 0xda, 0x5e, 0x12, 0x31, 0x0c, 0x55, 0x6a, - 0x6b, 0x70, 0x7b, 0xaa, 0xb7, 0x28, 0xa4, 0xcd, 0x6f, 0x73, 0x90, 0x6e, 0x32, 0x17, 0x7d, 0x0d, - 0x8b, 0x17, 0x9f, 0xfe, 0xd8, 0xa1, 0x72, 0xf9, 0x71, 0x2a, 0xbf, 0x77, 0x55, 0x8d, 0x28, 0x08, - 0xf4, 0xb3, 0x01, 0xe6, 0xd4, 0xb7, 0xec, 0x83, 0x04, 0x66, 0xa7, 0x29, 0x97, 0x1f, 0xfc, 0x07, - 0x65, 0x1d, 0x5e, 0x0f, 0x0a, 0xa3, 0x6f, 0x41, 0x3d, 0xb1, 0x4d, 0x89, 0x2f, 0xbf, 0x7b, 0x35, - 0xbc, 0x76, 0xfb, 0x9d, 0x01, 0xcb, 0xe3, 0x93, 0x72, 0x2b, 0x81, 0xb5, 0x31, 0xad, 0xf2, 0x87, - 0xd7, 0xd1, 0xd2, 0x91, 0x1c, 0x41, 0x56, 0x0d, 0xc1, 0x3b, 0x09, 0xec, 0x84, 0xd0, 0xf2, 0x46, - 0x62, 0xa8, 0xf6, 0x43, 0x20, 0x3f, 0x1c, 0x47, 0xf7, 0x12, 0xd3, 0x26, 0xbc, 0x6d, 0x5d, 0x05, - 0x3d, 0xea, 0x70, 0x38, 0x0c, 0x92, 0x38, 0xd4, 0xe8, 0x44, 0x0e, 0xc7, 0x26, 0x00, 0xfa, 0xc9, - 0x80, 0xd5, 0x29, 0xf7, 0xff, 0xfd, 0x04, 0x06, 0x27, 0xab, 0x96, 0x77, 0xae, 0xad, 0x1a, 0x05, - 0xb6, 0xfb, 0xc9, 0xf3, 0xb3, 0x8a, 0xf1, 0xe2, 0xac, 0x62, 0xfc, 0x7d, 0x56, 0x31, 0x7e, 0x3c, - 0xaf, 0xcc, 0xbd, 0x38, 0xaf, 0xcc, 0xfd, 0x71, 0x5e, 0x99, 0xfb, 0x62, 0xcb, 0xf5, 0xf8, 0x71, - 0xef, 0xb0, 0xde, 0x26, 0x7e, 0x63, 0xca, 0xcf, 0x46, 0xff, 0x7e, 0xe3, 0x74, 0xf8, 0x9f, 0x35, - 0xe8, 0x62, 0x76, 0x98, 0x95, 0x7f, 0x15, 0xf7, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x86, 0xc5, - 0x24, 0x72, 0x96, 0x0d, 0x00, 0x00, + 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. @@ -1121,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 { @@ -1195,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 } @@ -1213,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. @@ -1241,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) { @@ -1375,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) } @@ -1426,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{}, @@ -2053,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]) @@ -2063,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 @@ -2101,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]) @@ -2111,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 @@ -2414,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 } @@ -2434,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 } @@ -4362,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 { @@ -4385,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: @@ -4520,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 { @@ -4543,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: From 4f5c5bd0cf9fd1f0c23b0874671945d9c59ae7e1 Mon Sep 17 00:00:00 2001 From: Daniel T <30197399+danwt@users.noreply.github.com> Date: Fri, 8 Nov 2024 11:17:27 +0000 Subject: [PATCH 42/68] Danwt/mtsitrin 937 rollapp hard fork hub side rewardee (#1441) --- .../dymension/rollapp/fraud_proposal.proto | 3 + x/rollapp/keeper/expected_keepers.go | 2 +- x/rollapp/keeper/fraud_proposal.go | 2 +- x/rollapp/keeper/liveness_test.go | 6 +- x/rollapp/types/fraud_proposal.pb.go | 103 +++++++++++++----- x/rollapp/types/message_fraud_proposal.go | 18 ++- x/sequencer/keeper/fraud.go | 16 +-- x/sequencer/keeper/fraud_test.go | 21 +++- 8 files changed, 131 insertions(+), 40 deletions(-) diff --git a/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto index 3c68c327a..49d9001e5 100644 --- a/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto +++ b/proto/dymensionxyz/dymension/rollapp/fraud_proposal.proto @@ -28,6 +28,9 @@ message MsgRollappFraudProposal { // sequencer address to punish. optional string punish_sequencer_address = 6; + + // rewardAddr is bech32 for sdk acc addr + string rewardee = 7; } message MsgRollappFraudProposalResponse { diff --git a/x/rollapp/keeper/expected_keepers.go b/x/rollapp/keeper/expected_keepers.go index 1da36d722..3195ba743 100644 --- a/x/rollapp/keeper/expected_keepers.go +++ b/x/rollapp/keeper/expected_keepers.go @@ -24,7 +24,7 @@ type ChannelKeeper interface { type SequencerKeeper interface { SlashLiveness(ctx sdk.Context, rollappID string) error - PunishSequencer(ctx sdk.Context, seqAddr 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_proposal.go b/x/rollapp/keeper/fraud_proposal.go index 51324ea6f..9eec3ea2b 100644 --- a/x/rollapp/keeper/fraud_proposal.go +++ b/x/rollapp/keeper/fraud_proposal.go @@ -51,7 +51,7 @@ func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappF // punish the sequencer if needed if msg.PunishSequencerAddress != "" { - err := k.sequencerKeeper.PunishSequencer(ctx, msg.PunishSequencerAddress) + err := k.sequencerKeeper.PunishSequencer(ctx, msg.PunishSequencerAddress, msg.MustRewardee()) if err != nil { return nil, errorsmod.Wrap(err, "jail sequencer") } diff --git a/x/rollapp/keeper/liveness_test.go b/x/rollapp/keeper/liveness_test.go index cfcc53419..cb2e1969d 100644 --- a/x/rollapp/keeper/liveness_test.go +++ b/x/rollapp/keeper/liveness_test.go @@ -180,9 +180,9 @@ type livenessMockSequencerKeeper struct { slashes map[string]int } -// PunishSequencer implements keeper.SequencerKeeper. -func (l livenessMockSequencerKeeper) PunishSequencer(ctx sdk.Context, seqAddr string) error { - panic("unimplemented") +func (l livenessMockSequencerKeeper) PunishSequencer(ctx sdk.Context, seqAddr string, rewardee *sdk.AccAddress) error { + //TODO implement me + panic("implement me") } // JailByAddr implements types.SequencerKeeper. diff --git a/x/rollapp/types/fraud_proposal.pb.go b/x/rollapp/types/fraud_proposal.pb.go index abdd3dc44..2a63ebe44 100644 --- a/x/rollapp/types/fraud_proposal.pb.go +++ b/x/rollapp/types/fraud_proposal.pb.go @@ -40,6 +40,8 @@ type MsgRollappFraudProposal struct { 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 sdk acc addr + Rewardee string `protobuf:"bytes,7,opt,name=rewardee,proto3" json:"rewardee,omitempty"` } func (m *MsgRollappFraudProposal) Reset() { *m = MsgRollappFraudProposal{} } @@ -110,6 +112,13 @@ func (m *MsgRollappFraudProposal) GetPunishSequencerAddress() string { return "" } +func (m *MsgRollappFraudProposal) GetRewardee() string { + if m != nil { + return m.Rewardee + } + return "" +} + type MsgRollappFraudProposalResponse struct { } @@ -156,31 +165,32 @@ func init() { } var fileDescriptor_120f0332aea0a45b = []byte{ - // 375 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xb1, 0x4e, 0xc2, 0x40, - 0x18, 0xc7, 0x39, 0x25, 0x24, 0x1c, 0x46, 0xcd, 0xc5, 0x48, 0x43, 0xb4, 0x02, 0x13, 0x3a, 0xf4, - 0xa2, 0x98, 0x68, 0x5c, 0x8c, 0x0e, 0x46, 0x07, 0x8c, 0x29, 0x9b, 0x4b, 0x53, 0xe8, 0xd9, 0x5e, - 0x42, 0x7b, 0xe7, 0x5d, 0x4b, 0xa8, 0xa3, 0x0f, 0x60, 0x7c, 0x02, 0x9f, 0xc1, 0xc7, 0x70, 0x64, - 0x74, 0x34, 0x30, 0xb8, 0xf9, 0x0c, 0xa6, 0xbd, 0x16, 0x58, 0x70, 0x70, 0x6a, 0xbf, 0xdf, 0xff, - 0xfb, 0xe7, 0xff, 0x7d, 0xb9, 0x0f, 0xb6, 0x9d, 0xd8, 0x27, 0x81, 0xa4, 0x2c, 0x18, 0xc5, 0x4f, - 0x78, 0x56, 0x60, 0xc1, 0x06, 0x03, 0x9b, 0x73, 0xfc, 0x20, 0xec, 0xc8, 0xb1, 0xb8, 0x60, 0x9c, - 0x49, 0x7b, 0x60, 0x70, 0xc1, 0x42, 0x86, 0xf4, 0x45, 0x93, 0x31, 0x2b, 0x8c, 0xcc, 0x54, 0xdb, - 0x72, 0x99, 0xcb, 0xd2, 0x56, 0x9c, 0xfc, 0x29, 0x57, 0xad, 0xda, 0x67, 0xd2, 0x67, 0x12, 0xfb, - 0xd2, 0xc5, 0xc3, 0xc3, 0xe4, 0xa3, 0x84, 0xe6, 0x0f, 0x80, 0xd5, 0x8e, 0x74, 0x4d, 0xe5, 0xbe, - 0x4a, 0x12, 0xef, 0xb2, 0x40, 0xb4, 0x03, 0xcb, 0x76, 0x14, 0x7a, 0x4c, 0xd0, 0x30, 0xd6, 0x40, - 0x1d, 0xb4, 0xca, 0xe6, 0x1c, 0xa0, 0x5d, 0x08, 0xb3, 0x4c, 0x8b, 0x3a, 0xda, 0x8a, 0x92, 0x33, - 0x72, 0xe3, 0xa0, 0x7d, 0xb8, 0x99, 0xcb, 0x82, 0x0c, 0x69, 0x32, 0xa3, 0xb6, 0x5a, 0x07, 0xad, - 0xa2, 0xb9, 0x91, 0x71, 0x33, 0xc3, 0xa8, 0x01, 0xd7, 0xd4, 0xaa, 0x1e, 0xa1, 0xae, 0x17, 0x6a, - 0xc5, 0xb4, 0xad, 0x92, 0xb2, 0xeb, 0x14, 0xa1, 0x53, 0xa8, 0xf1, 0x28, 0xa0, 0xd2, 0xb3, 0x24, - 0x79, 0x8c, 0x48, 0xd0, 0x27, 0xc2, 0xb2, 0x1d, 0x47, 0x10, 0x29, 0xb5, 0x52, 0x1a, 0xbd, 0xad, - 0xf4, 0x6e, 0x2e, 0x5f, 0x28, 0xf5, 0x6c, 0xfd, 0xf9, 0xfb, 0xfd, 0x60, 0x3e, 0x76, 0xb3, 0x01, - 0xf7, 0x96, 0xec, 0x6b, 0x12, 0xc9, 0x59, 0x20, 0xc9, 0xd1, 0x1b, 0x80, 0x95, 0x1c, 0x76, 0xa4, - 0x8b, 0x5e, 0x00, 0x44, 0xdd, 0xa8, 0xe7, 0xd3, 0x70, 0xd1, 0x86, 0x4e, 0x8c, 0xbf, 0x9f, 0xc2, - 0x58, 0x92, 0x53, 0x3b, 0xff, 0xa7, 0x31, 0x1f, 0xf0, 0xf2, 0xf6, 0x63, 0xa2, 0x83, 0xf1, 0x44, - 0x07, 0x5f, 0x13, 0x1d, 0xbc, 0x4e, 0xf5, 0xc2, 0x78, 0xaa, 0x17, 0x3e, 0xa7, 0x7a, 0xe1, 0xfe, - 0xd8, 0xa5, 0xa1, 0x17, 0xf5, 0x8c, 0x3e, 0xf3, 0xf1, 0x92, 0xeb, 0x1a, 0xb6, 0xf1, 0x68, 0x76, - 0x62, 0x61, 0xcc, 0x89, 0xec, 0x95, 0xd2, 0x5b, 0x68, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0xe3, - 0x76, 0x5c, 0xd6, 0x91, 0x02, 0x00, 0x00, + // 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. @@ -283,6 +293,13 @@ func (m *MsgRollappFraudProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = 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) @@ -375,6 +392,10 @@ func (m *MsgRollappFraudProposal) Size() (n int) { if l > 0 { n += 1 + l + sovFraudProposal(uint64(l)) } + l = len(m.Rewardee) + if l > 0 { + n += 1 + l + sovFraudProposal(uint64(l)) + } return n } @@ -556,6 +577,38 @@ func (m *MsgRollappFraudProposal) Unmarshal(dAtA []byte) error { } 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:]) diff --git a/x/rollapp/types/message_fraud_proposal.go b/x/rollapp/types/message_fraud_proposal.go index 14794f6be..906ae9587 100644 --- a/x/rollapp/types/message_fraud_proposal.go +++ b/x/rollapp/types/message_fraud_proposal.go @@ -4,7 +4,6 @@ import ( "errors" errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/dymensionxyz/gerr-cosmos/gerrc" ) @@ -20,10 +19,27 @@ func (m *MsgRollappFraudProposal) ValidateBasic() error { "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) diff --git a/x/sequencer/keeper/fraud.go b/x/sequencer/keeper/fraud.go index f37274103..2c7027424 100644 --- a/x/sequencer/keeper/fraud.go +++ b/x/sequencer/keeper/fraud.go @@ -69,21 +69,23 @@ func (k Keeper) SlashLiveness(ctx sdk.Context, rollappID string) error { return err } -func (k Keeper) PunishSequencer(ctx sdk.Context, seqAddr string) error { +// Takes an optional rewardee addr who will receive some bounty +func (k Keeper) PunishSequencer(ctx sdk.Context, seqAddr string, rewardee *sdk.AccAddress) error { seq, err := k.RealSequencer(ctx, seqAddr) if err != nil { return err } - err = k.slash(ctx, &seq, seq.TokensCoin(), sdk.ZeroDec(), nil) - if err != nil { - return errorsmod.Wrap(err, "slash") + 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) } - err = k.unbond(ctx, &seq) if err != nil { - return errorsmod.Wrap(err, "unbond") + return errorsmod.Wrap(err, "slash") } - + err = errorsmod.Wrap(k.unbond(ctx, &seq), "unbond") k.SetSequencer(ctx, seq) return nil } diff --git a/x/sequencer/keeper/fraud_test.go b/x/sequencer/keeper/fraud_test.go index 3852a8586..d109fd334 100644 --- a/x/sequencer/keeper/fraud_test.go +++ b/x/sequencer/keeper/fraud_test.go @@ -40,7 +40,7 @@ func (s *SequencerTestSuite) TestFraud() { seq := s.seq(alice) s.k().SetProposer(s.Ctx, ra.RollappId, seq.Address) - err := s.k().PunishSequencer(s.Ctx, seq.Address) + err := s.k().PunishSequencer(s.Ctx, seq.Address, nil) s.Require().NoError(err) seq = s.seq(alice) @@ -53,7 +53,7 @@ func (s *SequencerTestSuite) TestFraud() { seq := s.seq(bob) s.k().SetProposer(s.Ctx, ra.RollappId, seq.Address) - err := s.k().PunishSequencer(s.Ctx, seq.Address) + err := s.k().PunishSequencer(s.Ctx, seq.Address, nil) s.Require().NoError(err) seq = s.seq(bob) @@ -61,6 +61,23 @@ func (s *SequencerTestSuite) TestFraud() { s.Require().True(seq.TokensCoin().IsZero()) s.Require().True(mod.Equal(seq.TokensCoin())) }) + s.Run("with rewardee", func() { + s.createSequencerWithBond(s.Ctx, ra.RollappId, charlie, bond) + seq := s.seq(charlie) + rewardee := pkAcc(randomTMPubKey()) + rewardeeBalBefore := s.App.BankKeeper.GetAllBalances(s.Ctx, rewardee) + + s.k().SetProposer(s.Ctx, ra.RollappId, seq.Address) + err := s.k().PunishSequencer(s.Ctx, seq.Address, &rewardee) + s.Require().NoError(err) + + seq = s.seq(charlie) + mod := s.moduleBalance() + s.Require().True(seq.TokensCoin().IsZero()) + s.Require().True(mod.Equal(seq.TokensCoin())) + rewardeeBalAfter := s.App.BankKeeper.GetAllBalances(s.Ctx, rewardee) + s.Require().True(rewardeeBalAfter.IsAllGT(rewardeeBalBefore)) + }) } // a full flow 'e2e' to make sure things are sensible From c4b48a7938540f525b77b2d03d73ebd063eb9c39 Mon Sep 17 00:00:00 2001 From: Daniel T <30197399+danwt@users.noreply.github.com> Date: Fri, 8 Nov 2024 11:22:33 +0000 Subject: [PATCH 43/68] Danwt/fix upgrade conflicts (#1442) Co-authored-by: zale144 Co-authored-by: keruch <53012408+keruch@users.noreply.github.com> --- Contributing.md | 15 ++ app/app.go | 3 +- app/upgrades/v3/constants.go | 20 --- app/upgrades/v3/upgrade.go | 47 ------- app/upgrades/v3/upgrade_test.go | 130 ------------------ app/upgrades/v4/constants.go | 9 ++ app/upgrades/v4/delayedack_params.go | 18 +++ app/upgrades/v4/old_rollapps.go | 82 +++++++++++ app/upgrades/v4/rollapp_params.go | 17 +++ app/upgrades/v4/rollapp_registered_denoms.go | 23 ++++ app/upgrades/v4/sequencer_index.go | 35 +++++ app/upgrades/v4/sequencer_params.go | 15 ++ app/upgrades/v4/sequencer_sequencer.go | 14 ++ app/upgrades/v4/upgrade.go | 108 ++++++++------- app/upgrades/v4/upgrade_test.go | 17 +++ .../dymension/eibc/demand_order.proto | 6 +- x/eibc/types/demand_order.go | 2 +- x/eibc/types/demand_order.pb.go | 119 +++++++++++----- x/iro/types/plan.go | 6 +- x/rollapp/keeper/registered_denoms.go | 6 +- x/rollapp/types/message_update_state.go | 9 +- x/rollapp/types/message_update_state_test.go | 11 -- x/rollapp/types/params.go | 7 +- x/sequencer/client/cli/tx.go | 4 +- .../{migrations.go => params_migrations.go} | 0 ...ions_test.go => params_migrations_test.go} | 0 x/sequencer/types/keys.go | 4 + .../types/msg_update_whitelisted_relayers.go | 14 +- x/sequencer/types/params.go | 18 +-- x/sponsorship/types/params.go | 50 ------- 30 files changed, 420 insertions(+), 389 deletions(-) delete mode 100644 app/upgrades/v3/constants.go delete mode 100644 app/upgrades/v3/upgrade.go delete mode 100644 app/upgrades/v3/upgrade_test.go create mode 100644 app/upgrades/v4/delayedack_params.go create mode 100644 app/upgrades/v4/old_rollapps.go create mode 100644 app/upgrades/v4/rollapp_params.go create mode 100644 app/upgrades/v4/rollapp_registered_denoms.go create mode 100644 app/upgrades/v4/sequencer_index.go create mode 100644 app/upgrades/v4/sequencer_params.go create mode 100644 app/upgrades/v4/sequencer_sequencer.go rename x/sequencer/{migrations.go => params_migrations.go} (100%) rename x/sequencer/{migrations_test.go => params_migrations_test.go} (100%) diff --git a/Contributing.md b/Contributing.md index b57f412f2..4f9488fb2 100644 --- a/Contributing.md +++ b/Contributing.md @@ -185,6 +185,21 @@ It's encouraged to add golang and cosmos utilities and shared code to [dymension 2. Do not reuse protobuf field numbers when updating protos. When in doubt, reserve the old number and use a new one. +#### Docstrings + +Do not worry about making the first word of the docstring on a public object the same as the object. Feel free to disable any linters/highlighters that pick up on it. + +In other words, we are fine with the first version here: + +```go + +// bla bla +type Foo struct{ } + +// Foo bla bla +type Foo struct{ } +``` + ### References - https://github.com/dymensionxyz/sdk-utils : Dymension golang and SDK utils library diff --git a/app/app.go b/app/app.go index ac6638793..ee76247ea 100644 --- a/app/app.go +++ b/app/app.go @@ -18,7 +18,6 @@ import ( "github.com/dymensionxyz/dymension/v3/app/keepers" "github.com/dymensionxyz/dymension/v3/app/upgrades" - v3 "github.com/dymensionxyz/dymension/v3/app/upgrades/v3" v4 "github.com/dymensionxyz/dymension/v3/app/upgrades/v4" dbm "github.com/cometbft/cometbft-db" @@ -84,7 +83,7 @@ var ( DefaultNodeHome string // Upgrades contains the upgrade handlers for the application - Upgrades = []upgrades.Upgrade{v3.Upgrade, v4.Upgrade} + Upgrades = []upgrades.Upgrade{v4.Upgrade} ) func init() { diff --git a/app/upgrades/v3/constants.go b/app/upgrades/v3/constants.go deleted file mode 100644 index f53287a1b..000000000 --- a/app/upgrades/v3/constants.go +++ /dev/null @@ -1,20 +0,0 @@ -package v3 - -import ( - storetypes "github.com/cosmos/cosmos-sdk/store/types" - - "github.com/dymensionxyz/dymension/v3/app/upgrades" - eibctypes "github.com/dymensionxyz/dymension/v3/x/eibc/types" -) - -const ( - UpgradeName = "v3" -) - -var Upgrade = upgrades.Upgrade{ - Name: UpgradeName, - CreateHandler: CreateUpgradeHandler, - StoreUpgrades: storetypes.StoreUpgrades{ - Added: []string{eibctypes.ModuleName}, - }, -} diff --git a/app/upgrades/v3/upgrade.go b/app/upgrades/v3/upgrade.go deleted file mode 100644 index 7f4679b89..000000000 --- a/app/upgrades/v3/upgrade.go +++ /dev/null @@ -1,47 +0,0 @@ -package v3 - -import ( - "math/big" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - - "github.com/dymensionxyz/dymension/v3/app/keepers" - appparams "github.com/dymensionxyz/dymension/v3/app/params" - "github.com/dymensionxyz/dymension/v3/app/upgrades" - delayedacktypes "github.com/dymensionxyz/dymension/v3/x/delayedack/types" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - seqtypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" -) - -// CreateUpgradeHandler creates an SDK upgrade handler for v3 -func CreateUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - _ upgrades.BaseAppParamManager, - keepers *keepers.AppKeepers, -) upgradetypes.UpgradeHandler { - return func(ctx sdk.Context, _ upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { - logger := ctx.Logger().With("upgrade", UpgradeName) - - // overwrite params for delayedack module due to proto change - daParams := delayedacktypes.DefaultParams() - keepers.DelayedAckKeeper.SetParams(ctx, daParams) - - // overwrite params for rollapp module due to proto change - rollappParams := rollapptypes.DefaultParams() - rollappParams.DisputePeriodInBlocks = 120960 // 1 week - keepers.RollappKeeper.SetParams(ctx, rollappParams) - - // overwrite params for sequencer module due to proto change - seqParams := seqtypes.DefaultParams() - DYM := sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) - seqParams.MinBond = sdk.NewCoin(appparams.BaseDenom, DYM.Mul(sdk.NewInt(1000))) // 1000DYM - keepers.SequencerKeeper.SetParams(ctx, seqParams) - - // Start running the module migrations - logger.Debug("running module migrations ...") - return mm.RunMigrations(ctx, configurator, fromVM) - } -} diff --git a/app/upgrades/v3/upgrade_test.go b/app/upgrades/v3/upgrade_test.go deleted file mode 100644 index 5f152a474..000000000 --- a/app/upgrades/v3/upgrade_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package v3_test - -import ( - "fmt" - "math/big" - "testing" - "time" - - abci "github.com/cometbft/cometbft/abci/types" - cometbftproto "github.com/cometbft/cometbft/proto/tendermint/types" - sdk "github.com/cosmos/cosmos-sdk/types" - upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" - "github.com/stretchr/testify/suite" - - "github.com/dymensionxyz/dymension/v3/app" - "github.com/dymensionxyz/dymension/v3/app/apptesting" -) - -// UpgradeTestSuite defines the structure for the upgrade test suite -type UpgradeTestSuite struct { - suite.Suite - Ctx sdk.Context - App *app.App -} - -// SetupTest initializes the necessary items for each test -func (s *UpgradeTestSuite) SetupTestCustom(t *testing.T) { - s.App = apptesting.Setup(t, false) - s.Ctx = s.App.BaseApp.NewContext(false, cometbftproto.Header{Height: 1, ChainID: "dymension_100-1", Time: time.Now().UTC()}) -} - -// TestUpgradeTestSuite runs the suite of tests for the upgrade handler -func TestUpgradeTestSuite(t *testing.T) { - suite.Run(t, new(UpgradeTestSuite)) -} - -var ( - DYM = sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) - - // CreateGaugeFee is the fee required to create a new gauge. - // expectCreateGaugeFee = DYM.Mul(sdk.NewInt(10)) - // AddToGaugeFee is the fee required to add to gauge. - // expectAddToGaugeFee = sdk.ZeroInt() - - expectDelayedackEpochIdentifier = "hour" - expectDelayedackBridgingFee = sdk.NewDecWithPrec(1, 3) -) - -const ( - dummyUpgradeHeight = 5 - expectDisputePeriodInBlocks = 120960 - expectMinBond = "1000000000000000000000" -) - -// TestUpgrade is a method of UpgradeTestSuite to test the upgrade process. -func (s *UpgradeTestSuite) TestUpgrade() { - testCases := []struct { - msg string - upgrade func() - postUpgrade func() error - expPass bool - }{ - { - msg: "Test that upgrade does not panic and sets correct parameters", - - upgrade: func() { - // Run upgrade - s.Ctx = s.Ctx.WithBlockHeight(dummyUpgradeHeight - 1) - plan := upgradetypes.Plan{Name: "v3", Height: dummyUpgradeHeight} - err := s.App.UpgradeKeeper.ScheduleUpgrade(s.Ctx, plan) - s.Require().NoError(err) - _, exists := s.App.UpgradeKeeper.GetUpgradePlan(s.Ctx) - s.Require().True(exists) - - s.Ctx = s.Ctx.WithBlockHeight(dummyUpgradeHeight) - // simulate the upgrade process not panic. - s.Require().NotPanics(func() { - // simulate the upgrade process. - s.App.BeginBlocker(s.Ctx, abci.RequestBeginBlock{}) - }) - }, - postUpgrade: func() error { - // Post-update validation to ensure parameters are correctly set - - // Check Delayedack parameters - delayedackParams := s.App.DelayedAckKeeper.GetParams(s.Ctx) - if delayedackParams.EpochIdentifier != expectDelayedackEpochIdentifier || - !delayedackParams.BridgingFee.Equal(expectDelayedackBridgingFee) { - return fmt.Errorf("delayedack parameters not set correctly") - } - - // Check Rollapp parameters - rollappParams := s.App.RollappKeeper.GetParams(s.Ctx) - if rollappParams.DisputePeriodInBlocks != expectDisputePeriodInBlocks { - return fmt.Errorf("rollapp parameters not set correctly") - } - - // Check Sequencer parameters - seqParams := s.App.SequencerKeeper.GetParams(s.Ctx) - if seqParams.MinBond.Amount.String() != expectMinBond { - return fmt.Errorf("sequencer parameters not set correctly") - } - - // These fields are deleted in the v4 update. Intentionally leave the commented code - // here for historical reference. - // Check Incentives parameters - //if !incentivestypes.CreateGaugeFee.Equal(expectCreateGaugeFee) || !incentivestypes.AddToGaugeFee.Equal(expectAddToGaugeFee) { - // return fmt.Errorf("incentives parameters not set correctly") - //} - - return nil - }, - expPass: true, - }, - } - - for _, tc := range testCases { - s.Run(fmt.Sprintf("Case %s", tc.msg), func() { - s.SetupTestCustom(s.T()) // Reset for each case - - tc.upgrade() - err := tc.postUpgrade() - if tc.expPass { - s.Require().NoError(err) - } else { - s.Require().Error(err) - } - }) - } -} diff --git a/app/upgrades/v4/constants.go b/app/upgrades/v4/constants.go index 18cd32e53..5a6542de2 100644 --- a/app/upgrades/v4/constants.go +++ b/app/upgrades/v4/constants.go @@ -4,8 +4,13 @@ import ( storetypes "github.com/cosmos/cosmos-sdk/store/types" consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types" crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + grouptypes "github.com/cosmos/cosmos-sdk/x/group" + "github.com/dymensionxyz/dymension/v3/app/upgrades" + dymnstypes "github.com/dymensionxyz/dymension/v3/x/dymns/types" + irotypes "github.com/dymensionxyz/dymension/v3/x/iro/types" lightclienttypes "github.com/dymensionxyz/dymension/v3/x/lightclient/types" + sponsorshiptypes "github.com/dymensionxyz/dymension/v3/x/sponsorship/types" ) const ( @@ -20,6 +25,10 @@ var Upgrade = upgrades.Upgrade{ consensustypes.ModuleName, crisistypes.ModuleName, lightclienttypes.ModuleName, + sponsorshiptypes.ModuleName, + dymnstypes.ModuleName, + irotypes.ModuleName, + grouptypes.ModuleName, }, }, } diff --git a/app/upgrades/v4/delayedack_params.go b/app/upgrades/v4/delayedack_params.go new file mode 100644 index 000000000..81974ff55 --- /dev/null +++ b/app/upgrades/v4/delayedack_params.go @@ -0,0 +1,18 @@ +package v4 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + + delayedackkeeper "github.com/dymensionxyz/dymension/v3/x/delayedack/keeper" + delayedacktypes "github.com/dymensionxyz/dymension/v3/x/delayedack/types" +) + +func migrateDelayedAckParams(ctx sdk.Context, delayedAckKeeper delayedackkeeper.Keeper) { + // overwrite params for rollapp module due to proto change + params := delayedacktypes.DefaultParams() + + // EpochIdentifier is the only one that hasn't changed + params.EpochIdentifier = delayedAckKeeper.GetParams(ctx).EpochIdentifier + + delayedAckKeeper.SetParams(ctx, params) +} diff --git a/app/upgrades/v4/old_rollapps.go b/app/upgrades/v4/old_rollapps.go new file mode 100644 index 000000000..6cbae4653 --- /dev/null +++ b/app/upgrades/v4/old_rollapps.go @@ -0,0 +1,82 @@ +package v4 + +import ( + "cosmossdk.io/math" + + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +// Genesis info data is from https://www.notion.so/dymension/Rollapp-Specific-Migration-Data-136a4a51f86a8017be93d774a576d0ce. +// Rollapp IDs are from https://dym.fyi/rollapps. + +var ( + nimRollappID = "nim_1122-1" + nimGenesisInfo = rollapptypes.GenesisInfo{ + GenesisChecksum: "cbff2650625cb02240757e76b3c00a0f04ff9347e51ec69eaddbc2b40f2c2335", + Bech32Prefix: "nim", + NativeDenom: rollapptypes.DenomMetadata{ + Display: "NIM", + Base: "anim", + Exponent: 18, + }, + InitialSupply: math.NewIntWithDecimal(1, 27), // 1|000_000_000|000_000_000|000_000_000 + Sealed: true, + GenesisAccounts: nil, + } + nimDenoms = []string{ + "ibc/FF6C2E86490C1C4FBBD24F55032831D2415B9D7882F85C3CC9C2401D79362BEA", // STRD + "ibc/F46BA5EDCA6DAA5F7EFD3838430E03647CDC786BB1B89BC9FDD1CBE16B099645", // stTIA + "ibc/F428C5D24BEF8CA22EE74810A583422C12F02865ADAC185678C73015A88227B3", // milkTIA + "ibc/E3AB0DFDE9E782262B770C32DF94AC2A92B93DC4825376D6F6C874D3C877864E", // WETH + "ibc/D934516FBE457F3A98AFABD87E0EFF7F95A15325C191EA8CDD7763C702FDDEC2", // AXL + "ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9", // ATOM + "ibc/BEE9A8F835D60717548FFE9AC9E90F18AB8096574EB1211F88074CB3511B7860", // WBTC + "ibc/B72B5B3F7AD44783584921DC33354BCE07C8EB0A7F0349247C3DAD38C3B6E6A5", // USDT + "ibc/B3504E092456BA618CC28AC671A71FB08C6CA0FD0BE7C8A5B5A3E2DD933CC9E4", // USDC + "ibc/B22B4DD21586965DAEF42A7600BA371EA77C02E90FC8A7F2330BF9F9DE129B07", // KUJI + "ibc/AB30D2F9C131AE1EFA8449C74490326BD5ACC40EF69A2D8563994AA05CE0B258", // stDYM + "ibc/5C58CC109FB067073F1B80481EE9C3A8484330FECB35D2591B28E7E1A6FCF64C", // ARCH + "ibc/5A26C8DC8DA66F4DD94326E67F94510188F5F7AFE2DB3933A0C823670E56EABF", // MANDE + "ibc/5620289B0E1106C8A2421F212FEC4EB19E3CBA964662DB61754CCDE8FAAC29FF", // Dr.BE + "ibc/45D6B52CAD911A15BD9C2F5FFDA80E26AFCB05C7CD520070790ABC86D2B24229", // TIA + "ibc/2F2F132E47342479A8B7A8DB241F276609C53A1478CEB9A57411A910C9B061DB", // NTRN + "ibc/27A5DE18D796A595123D97078F9AB9EAEFC23540724384F219EACED2BD5511F5", // SCRT + "ibc/13B2C536BB057AC79D5616B8EA1B9540EC1F2170718CAFF6F0083C966FFFED0B", // OSMO + "ibc/04E01477A69DF1E5EE99F85C15B66D68D23292275357CAA44B2E0527310A405E", // EVMOS + } + + mandeRollappID = "mande_18071918-1" + mandeGenesisInfo = rollapptypes.GenesisInfo{ + GenesisChecksum: "7f64188a70c2b67230f6af826b33fe35f2a46c63c4838216c3ac50b8ab148632", + Bech32Prefix: "mande", + NativeDenom: rollapptypes.DenomMetadata{ + Display: "MANDE", + Base: "amand", + Exponent: 18, + }, + InitialSupply: math.NewIntWithDecimal(2, 25), // 20_000_000|000_000_000|000_000_000 + Sealed: true, + GenesisAccounts: nil, + } + mandeDenoms = []string{ + "ibc/FF6C2E86490C1C4FBBD24F55032831D2415B9D7882F85C3CC9C2401D79362BEA", // STRD + "ibc/FB53D1684F155CBB86D9CE917807E42B59209EBE3AD3A92E15EF66586C073942", // NIM + "ibc/F46BA5EDCA6DAA5F7EFD3838430E03647CDC786BB1B89BC9FDD1CBE16B099645", // stTIA + "ibc/F428C5D24BEF8CA22EE74810A583422C12F02865ADAC185678C73015A88227B3", // milkTIA + "ibc/E3AB0DFDE9E782262B770C32DF94AC2A92B93DC4825376D6F6C874D3C877864E", // WETH + "ibc/D934516FBE457F3A98AFABD87E0EFF7F95A15325C191EA8CDD7763C702FDDEC2", // AXL + "ibc/C4CFF46FD6DE35CA4CF4CE031E643C8FDC9BA4B99AE598E9B0ED98FE3A2319F9", // ATOM + "ibc/BEE9A8F835D60717548FFE9AC9E90F18AB8096574EB1211F88074CB3511B7860", // WBTC + "ibc/B72B5B3F7AD44783584921DC33354BCE07C8EB0A7F0349247C3DAD38C3B6E6A5", // USDT + "ibc/B3504E092456BA618CC28AC671A71FB08C6CA0FD0BE7C8A5B5A3E2DD933CC9E4", // USDC + "ibc/B22B4DD21586965DAEF42A7600BA371EA77C02E90FC8A7F2330BF9F9DE129B07", // KUJI + "ibc/AB30D2F9C131AE1EFA8449C74490326BD5ACC40EF69A2D8563994AA05CE0B258", // stDYM + "ibc/5C58CC109FB067073F1B80481EE9C3A8484330FECB35D2591B28E7E1A6FCF64C", // ARCH + "ibc/5620289B0E1106C8A2421F212FEC4EB19E3CBA964662DB61754CCDE8FAAC29FF", // Dr.BE + "ibc/45D6B52CAD911A15BD9C2F5FFDA80E26AFCB05C7CD520070790ABC86D2B24229", // TIA + "ibc/2F2F132E47342479A8B7A8DB241F276609C53A1478CEB9A57411A910C9B061DB", // NTRN + "ibc/27A5DE18D796A595123D97078F9AB9EAEFC23540724384F219EACED2BD5511F5", // SCRT + "ibc/13B2C536BB057AC79D5616B8EA1B9540EC1F2170718CAFF6F0083C966FFFED0B", // OSMO + "ibc/04E01477A69DF1E5EE99F85C15B66D68D23292275357CAA44B2E0527310A405E", // EVMOS + } +) diff --git a/app/upgrades/v4/rollapp_params.go b/app/upgrades/v4/rollapp_params.go new file mode 100644 index 000000000..1b677d052 --- /dev/null +++ b/app/upgrades/v4/rollapp_params.go @@ -0,0 +1,17 @@ +package v4 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" +) + +func migrateRollappParams(ctx sdk.Context, rollappkeeper *rollappkeeper.Keeper) { + // overwrite params for rollapp module due to proto change + params := rollapptypes.DefaultParams() + + // Dispute period is the only one that hasn't changed + params.DisputePeriodInBlocks = rollappkeeper.DisputePeriodInBlocks(ctx) + + rollappkeeper.SetParams(ctx, params) +} diff --git a/app/upgrades/v4/rollapp_registered_denoms.go b/app/upgrades/v4/rollapp_registered_denoms.go new file mode 100644 index 000000000..e852ba829 --- /dev/null +++ b/app/upgrades/v4/rollapp_registered_denoms.go @@ -0,0 +1,23 @@ +package v4 + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + + rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" +) + +func migrateRollappRegisteredDenoms(ctx sdk.Context, rk *rollappkeeper.Keeper) error { + for _, denom := range nimDenoms { + if err := rk.SetRegisteredDenom(ctx, nimRollappID, denom); err != nil { + return fmt.Errorf("set registered denom: %s: %w", nimRollappID, err) + } + } + for _, denom := range mandeDenoms { + if err := rk.SetRegisteredDenom(ctx, mandeRollappID, denom); err != nil { + return fmt.Errorf("set registered denom: %s: %w", mandeRollappID, err) + } + } + return nil +} diff --git a/app/upgrades/v4/sequencer_index.go b/app/upgrades/v4/sequencer_index.go new file mode 100644 index 000000000..7d09f9ffc --- /dev/null +++ b/app/upgrades/v4/sequencer_index.go @@ -0,0 +1,35 @@ +package v4 + +import ( + errorsmod "cosmossdk.io/errors" + sdk "github.com/cosmos/cosmos-sdk/types" + sequencerkeeper "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" +) + +func migrateSequencerIndices(ctx sdk.Context, k *sequencerkeeper.Keeper) error { + list := k.AllSequencers(ctx) + for _, oldSequencer := range list { + + // fill proposer index + if oldSequencer.Proposer { + k.SetProposer(ctx, oldSequencer.RollappId, oldSequencer.Address) + } + k.SetSuccessor(ctx, oldSequencer.RollappId, types.SentinelSeqAddr) + + // fill dymint proposer addr index + addr, err := oldSequencer.ProposerAddr() + if err != nil { + // This shouldn't happen, but it's not obvious how we can recover from it. + // It could lead to broken state for this rollapp, meaning that their IBC won't work properly. + return errorsmod.Wrapf(err, "get dymint proposer address, seq: %s", oldSequencer.Address) + } + if err = k.SetSequencerByDymintAddr(ctx, addr, oldSequencer.Address); err != nil { + return errorsmod.Wrapf(err, "set sequencer by dymint address: seq: %s", oldSequencer.Address) + } + + // NOTE: technically should delete the unbonding queue, but we make an assumption + // that the unbonding queue is empty at the time of upgrade. + } + return nil +} diff --git a/app/upgrades/v4/sequencer_params.go b/app/upgrades/v4/sequencer_params.go new file mode 100644 index 000000000..ce342def5 --- /dev/null +++ b/app/upgrades/v4/sequencer_params.go @@ -0,0 +1,15 @@ +package v4 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sequencerkeeper "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" + sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" +) + +func migrateSequencerParams(ctx sdk.Context, k *sequencerkeeper.Keeper) { + // overwrite params for rollapp module due to proto change + // (Note: all of them have changed, including min bond) + p := sequencertypes.DefaultParams() + + k.SetParams(ctx, p) +} diff --git a/app/upgrades/v4/sequencer_sequencer.go b/app/upgrades/v4/sequencer_sequencer.go new file mode 100644 index 000000000..bf497a053 --- /dev/null +++ b/app/upgrades/v4/sequencer_sequencer.go @@ -0,0 +1,14 @@ +package v4 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sequencerkeeper "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" +) + +func migrateSequencers(ctx sdk.Context, k *sequencerkeeper.Keeper) { + list := k.AllSequencers(ctx) + for _, oldSequencer := range list { + newSequencer := ConvertOldSequencerToNew(oldSequencer) + k.SetSequencer(ctx, newSequencer) + } +} diff --git a/app/upgrades/v4/upgrade.go b/app/upgrades/v4/upgrade.go index a316f17dd..27418deca 100644 --- a/app/upgrades/v4/upgrade.go +++ b/app/upgrades/v4/upgrade.go @@ -1,6 +1,7 @@ package v4 import ( + errorsmod "cosmossdk.io/errors" "github.com/cometbft/cometbft/crypto" "github.com/cosmos/cosmos-sdk/baseapp" @@ -33,7 +34,6 @@ import ( lightclientkeeper "github.com/dymensionxyz/dymension/v3/x/lightclient/keeper" rollappkeeper "github.com/dymensionxyz/dymension/v3/x/rollapp/keeper" rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - sequencerkeeper "github.com/dymensionxyz/dymension/v3/x/sequencer/keeper" sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" streamerkeeper "github.com/dymensionxyz/dymension/v3/x/streamer/keeper" streamertypes "github.com/dymensionxyz/dymension/v3/x/streamer/types" @@ -51,6 +51,14 @@ func CreateUpgradeHandler( LoadDeprecatedParamsSubspaces(keepers) + // Run migrations before applying any other state changes. + // NOTE: DO NOT PUT ANY STATE CHANGES BEFORE RunMigrations(). + // (This is how osmosis do it) + migrations, err := mm.RunMigrations(ctx, configurator, fromVM) + if err != nil { + return nil, err + } + migrateModuleParams(ctx, keepers) migrateDelayedAckParams(ctx, keepers.DelayedAckKeeper) migrateRollappParams(ctx, keepers.RollappKeeper) @@ -58,7 +66,12 @@ func CreateUpgradeHandler( return nil, err } + migrateSequencerParams(ctx, keepers.SequencerKeeper) + if err := migrateSequencerIndices(ctx, keepers.SequencerKeeper); err != nil { + return nil, errorsmod.Wrap(err, "migrate sequencer indices") + } migrateSequencers(ctx, keepers.SequencerKeeper) + migrateRollappLightClients(ctx, keepers.RollappKeeper, keepers.LightClientKeeper, keepers.IBCKeeper.ChannelKeeper) if err := migrateStreamer(ctx, keepers.StreamerKeeper, keepers.EpochsKeeper); err != nil { return nil, err @@ -73,9 +86,13 @@ func CreateUpgradeHandler( return nil, err } + if err := migrateRollappRegisteredDenoms(ctx, keepers.RollappKeeper); err != nil { + return nil, err + } + // Start running the module migrations logger.Debug("running module migrations ...") - return mm.RunMigrations(ctx, configurator, fromVM) + return migrations, nil } } @@ -131,19 +148,6 @@ func LoadDeprecatedParamsSubspaces(keepers *keepers.AppKeepers) { } } -func migrateDelayedAckParams(ctx sdk.Context, delayedAckKeeper delayedackkeeper.Keeper) { - // overwrite params for delayedack module due to added parameters - params := delayedacktypes.DefaultParams() - delayedAckKeeper.SetParams(ctx, params) -} - -func migrateRollappParams(ctx sdk.Context, rollappkeeper *rollappkeeper.Keeper) { - // overwrite params for rollapp module due to proto change - params := rollapptypes.DefaultParams() - params.DisputePeriodInBlocks = rollappkeeper.DisputePeriodInBlocks(ctx) - rollappkeeper.SetParams(ctx, params) -} - // migrateRollappGauges creates a gauge for each rollapp in the store func migrateRollappGauges(ctx sdk.Context, rollappkeeper *rollappkeeper.Keeper, incentivizeKeeper *incentiveskeeper.Keeper) error { rollapps := rollappkeeper.GetAllRollapps(ctx) @@ -157,6 +161,7 @@ func migrateRollappGauges(ctx sdk.Context, rollappkeeper *rollappkeeper.Keeper, } func migrateRollapps(ctx sdk.Context, rollappkeeper *rollappkeeper.Keeper) error { + // in theory, there should be only two rollapps in the store, but we iterate over all of them just in case list := rollappkeeper.GetAllRollapps(ctx) for _, oldRollapp := range list { newRollapp := ConvertOldRollappToNew(oldRollapp) @@ -168,18 +173,6 @@ func migrateRollapps(ctx sdk.Context, rollappkeeper *rollappkeeper.Keeper) error return nil } -func migrateSequencers(ctx sdk.Context, sequencerkeeper *sequencerkeeper.Keeper) { - list := sequencerkeeper.AllSequencers(ctx) - for _, oldSequencer := range list { - newSequencer := ConvertOldSequencerToNew(oldSequencer) - sequencerkeeper.SetSequencer(ctx, newSequencer) - - if oldSequencer.Proposer { - sequencerkeeper.SetProposer(ctx, oldSequencer.RollappId, oldSequencer.Address) - } - } -} - func migrateRollappLightClients(ctx sdk.Context, rollappkeeper *rollappkeeper.Keeper, lightClientKeeper lightclientkeeper.Keeper, ibcChannelKeeper ibcchannelkeeper.Keeper) { list := rollappkeeper.GetAllRollapps(ctx) for _, rollapp := range list { @@ -199,8 +192,14 @@ func migrateRollappLightClients(ctx sdk.Context, rollappkeeper *rollappkeeper.Ke } } -// migrateStreamer creates epoch pointers for all epoch infos. +// migrateStreamer creates epoch pointers for all epoch infos and updates module params func migrateStreamer(ctx sdk.Context, sk streamerkeeper.Keeper, ek *epochskeeper.Keeper) error { + // update module params + oldParams := sk.GetParams(ctx) + oldParams.MaxIterationsPerBlock = streamertypes.DefaultMaxIterationsPerBlock + sk.SetParams(ctx, oldParams) + + // create epoch pointers for all epoch infos for _, epoch := range ek.AllEpochInfos(ctx) { err := sk.SaveEpochPointer(ctx, streamertypes.NewEpochPointer(epoch.Identifier, epoch.Duration)) if err != nil { @@ -238,14 +237,33 @@ func migrateDelayedAckPacketIndex(ctx sdk.Context, dk delayedackkeeper.Keeper) e } func ConvertOldRollappToNew(oldRollapp rollapptypes.Rollapp) rollapptypes.Rollapp { + genesisInfo := rollapptypes.GenesisInfo{ + Bech32Prefix: oldRollapp.RollappId[:5], // placeholder data + GenesisChecksum: string(crypto.Sha256([]byte(oldRollapp.RollappId))), // placeholder data + NativeDenom: rollapptypes.DenomMetadata{ + Display: "DEN", // placeholder data + Base: "aden", // placeholder data + Exponent: 18, // placeholder data + }, + InitialSupply: sdk.NewInt(100000), // placeholder data + Sealed: true, + } + + // migrate existing rollapps + if oldRollapp.RollappId == nimRollappID { + genesisInfo = nimGenesisInfo + } + if oldRollapp.RollappId == mandeRollappID { + genesisInfo = mandeGenesisInfo + } + return rollapptypes.Rollapp{ RollappId: oldRollapp.RollappId, Owner: oldRollapp.Owner, GenesisState: oldRollapp.GenesisState, ChannelId: oldRollapp.ChannelId, - // TODO: regarding missing data - https://github.com/dymensionxyz/dymension/issues/986 - VmType: rollapptypes.Rollapp_EVM, // placeholder data - Metadata: &rollapptypes.RollappMetadata{ + Frozen: oldRollapp.Frozen, + Metadata: &rollapptypes.RollappMetadata{ // Can be updated in runtime Website: "", Description: "", LogoUrl: "", @@ -256,20 +274,14 @@ func ConvertOldRollappToNew(oldRollapp rollapptypes.Rollapp) rollapptypes.Rollap Tagline: "", FeeDenom: nil, }, - GenesisInfo: rollapptypes.GenesisInfo{ - Bech32Prefix: oldRollapp.RollappId[:5], // placeholder data - GenesisChecksum: string(crypto.Sha256([]byte(oldRollapp.RollappId))), // placeholder data - NativeDenom: rollapptypes.DenomMetadata{ - Display: "DEN", // placeholder data - Base: "aden", // placeholder data - Exponent: 18, // placeholder data - }, - InitialSupply: sdk.NewInt(100000), // placeholder data - Sealed: true, - }, - InitialSequencer: "*", - Launched: true, - RevisionNumber: 0, + GenesisInfo: genesisInfo, + InitialSequencer: "*", + VmType: rollapptypes.Rollapp_EVM, // EVM for existing rollapps + Launched: true, // Existing rollapps are already launched + 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, } } @@ -283,10 +295,10 @@ func ConvertOldSequencerToNew(old sequencertypes.Sequencer) sequencertypes.Seque RollappId: old.RollappId, Status: old.Status, Tokens: old.Tokens, + OptedIn: true, Metadata: sequencertypes.SequencerMetadata{ - Moniker: old.Metadata.Moniker, - Details: old.Metadata.Details, - // TODO: regarding missing data - https://github.com/dymensionxyz/dymension/issues/987 + Moniker: old.Metadata.Moniker, + Details: old.Metadata.Details, P2PSeeds: nil, Rpcs: nil, EvmRpcs: nil, diff --git a/app/upgrades/v4/upgrade_test.go b/app/upgrades/v4/upgrade_test.go index 34facd781..85ab853e5 100644 --- a/app/upgrades/v4/upgrade_test.go +++ b/app/upgrades/v4/upgrade_test.go @@ -49,6 +49,8 @@ const ( expectDelayedackDeletePacketsEpochLimit int32 = 1000_000 expectDelayedackEpochIdentifier = "hour" + expectLivenessSlashInterval = rollapptypes.DefaultLivenessSlashInterval + expectLivenessSlashBlock = rollapptypes.DefaultLivenessSlashBlocks expectDisputePeriodInBlocks = 3 ) @@ -198,7 +200,12 @@ func (s *UpgradeTestSuite) validateRollappsMigration(numRoll int) error { } } + s.Require().Equal(expectLivenessSlashBlock, s.App.RollappKeeper.GetParams(s.Ctx).LivenessSlashBlocks) + s.Require().Equal(expectLivenessSlashInterval, s.App.RollappKeeper.GetParams(s.Ctx).LivenessSlashInterval) + if !reflect.DeepEqual(rollapps, expectRollapps) { + s.T().Log("Expect rollapps", expectRollapps) + s.T().Log("Actual rollapps", rollapps) return fmt.Errorf("rollapps do not match") } return nil @@ -264,7 +271,12 @@ func (s *UpgradeTestSuite) validateSequencersMigration(numSeq int) error { seq := s.App.AppCodec().MustMarshalJSON(&sequencer) nSeq := s.App.AppCodec().MustMarshalJSON(&expectSequencers[i]) + s.Require().True(sequencer.OptedIn) s.Require().JSONEq(string(seq), string(nSeq)) + + byDymintAddr, err := s.App.SequencerKeeper.SequencerByDymintAddr(s.Ctx, expectSequencers[i].MustProposerAddr()) + s.Require().NoError(err) + s.Require().Equal(sequencer.Address, byDymintAddr.Address) } // check proposer @@ -272,6 +284,11 @@ func (s *UpgradeTestSuite) validateSequencersMigration(numSeq int) error { p := s.App.SequencerKeeper.GetProposer(s.Ctx, rollapp.RollappId) s.Require().False(p.Sentinel()) } + s.Require().Equal(sequencertypes.DefaultNoticePeriod, s.App.SequencerKeeper.GetParams(s.Ctx).NoticePeriod) + s.Require().Equal(sequencertypes.DefaultKickThreshold, s.App.SequencerKeeper.GetParams(s.Ctx).KickThreshold) + s.Require().Equal(sequencertypes.DefaultLivenessSlashMultiplier, s.App.SequencerKeeper.GetParams(s.Ctx).LivenessSlashMinMultiplier) + s.Require().Equal(sequencertypes.DefaultLivenessSlashMinAbsolute, s.App.SequencerKeeper.GetParams(s.Ctx).LivenessSlashMinAbsolute) + s.Require().Equal(sequencertypes.DefaultMinBond, s.App.SequencerKeeper.GetParams(s.Ctx).MinBond) return nil } diff --git a/proto/dymensionxyz/dymension/eibc/demand_order.proto b/proto/dymensionxyz/dymension/eibc/demand_order.proto index 6be352769..493deea6d 100644 --- a/proto/dymensionxyz/dymension/eibc/demand_order.proto +++ b/proto/dymensionxyz/dymension/eibc/demand_order.proto @@ -26,7 +26,11 @@ message DemandOrder { (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins" ]; string recipient = 5; - reserved 6; + + // Deprecated: use DemandOrder.IsFulfilled method instead. + // Only used for backwards compatibility. + bool deprecated_is_fulfilled = 6 [deprecated = true]; + dymensionxyz.dymension.common.Status tracking_packet_status = 8; string rollapp_id = 9; common.RollappPacket.Type type = 10; diff --git a/x/eibc/types/demand_order.go b/x/eibc/types/demand_order.go index 7978bdfc1..26c22ecf6 100644 --- a/x/eibc/types/demand_order.go +++ b/x/eibc/types/demand_order.go @@ -161,7 +161,7 @@ func (m *DemandOrder) ValidateOrderIsOutstanding() error { } func (m *DemandOrder) IsFulfilled() bool { - return m.FulfillerAddress != "" + return m.FulfillerAddress != "" || m.DeprecatedIsFulfilled } // BuildDemandIDFromPacketKey returns a unique demand order id from the packet key. diff --git a/x/eibc/types/demand_order.pb.go b/x/eibc/types/demand_order.pb.go index 01db852f6..58ba61131 100644 --- a/x/eibc/types/demand_order.pb.go +++ b/x/eibc/types/demand_order.pb.go @@ -36,11 +36,14 @@ type DemandOrder struct { // price is the amount that the fulfiller sends to original eibc transfer recipient Price github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,3,rep,name=price,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"price"` // fee is the effective profit made by the fulfiller because they pay price and receive fee + price - Fee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=fee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"fee"` - Recipient string `protobuf:"bytes,5,opt,name=recipient,proto3" json:"recipient,omitempty"` - TrackingPacketStatus types1.Status `protobuf:"varint,8,opt,name=tracking_packet_status,json=trackingPacketStatus,proto3,enum=dymensionxyz.dymension.common.Status" json:"tracking_packet_status,omitempty"` - RollappId string `protobuf:"bytes,9,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` - Type types1.RollappPacket_Type `protobuf:"varint,10,opt,name=type,proto3,enum=dymensionxyz.dymension.common.RollappPacket_Type" json:"type,omitempty"` + Fee github_com_cosmos_cosmos_sdk_types.Coins `protobuf:"bytes,4,rep,name=fee,proto3,castrepeated=github.com/cosmos/cosmos-sdk/types.Coins" json:"fee"` + Recipient string `protobuf:"bytes,5,opt,name=recipient,proto3" json:"recipient,omitempty"` + // Deprecated: use DemandOrder.IsFulfilled method instead. + // Only used for backwards compatibility. + DeprecatedIsFulfilled bool `protobuf:"varint,6,opt,name=deprecated_is_fulfilled,json=deprecatedIsFulfilled,proto3" json:"deprecated_is_fulfilled,omitempty"` // Deprecated: Do not use. + TrackingPacketStatus types1.Status `protobuf:"varint,8,opt,name=tracking_packet_status,json=trackingPacketStatus,proto3,enum=dymensionxyz.dymension.common.Status" json:"tracking_packet_status,omitempty"` + RollappId string `protobuf:"bytes,9,opt,name=rollapp_id,json=rollappId,proto3" json:"rollapp_id,omitempty"` + Type types1.RollappPacket_Type `protobuf:"varint,10,opt,name=type,proto3,enum=dymensionxyz.dymension.common.RollappPacket_Type" json:"type,omitempty"` // fulfiller_address is the bech32-encoded address of the account which fulfilled the order. FulfillerAddress string `protobuf:"bytes,11,opt,name=fulfiller_address,json=fulfillerAddress,proto3" json:"fulfiller_address,omitempty"` // creation_height is the height of the block when order was created. @@ -115,6 +118,14 @@ func (m *DemandOrder) GetRecipient() string { return "" } +// Deprecated: Do not use. +func (m *DemandOrder) GetDeprecatedIsFulfilled() bool { + if m != nil { + return m.DeprecatedIsFulfilled + } + return false +} + func (m *DemandOrder) GetTrackingPacketStatus() types1.Status { if m != nil { return m.TrackingPacketStatus @@ -159,38 +170,39 @@ func init() { } var fileDescriptor_2fc99140861fbacd = []byte{ - // 485 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xd1, 0x6e, 0xd3, 0x30, - 0x14, 0x6d, 0xda, 0x6e, 0xac, 0x2e, 0x2a, 0x9b, 0x99, 0x50, 0x18, 0x90, 0x55, 0x48, 0x88, 0x0a, - 0x84, 0x4d, 0xbb, 0x2f, 0x60, 0x80, 0x04, 0xec, 0x01, 0x14, 0x78, 0x02, 0xa1, 0xca, 0xb5, 0x6f, - 0x5b, 0xab, 0x49, 0x1c, 0xd9, 0xee, 0xb4, 0xf0, 0x15, 0x7c, 0x07, 0x5f, 0xb2, 0x07, 0x1e, 0xf6, - 0xc8, 0x13, 0xa0, 0xf6, 0x47, 0x50, 0xec, 0x74, 0x1b, 0x48, 0x85, 0x17, 0x9e, 0x92, 0x9c, 0x7b, - 0xce, 0x3d, 0xbe, 0x3e, 0x37, 0x88, 0x88, 0x22, 0x85, 0xcc, 0x48, 0x95, 0x9d, 0x14, 0x9f, 0xe8, - 0xf9, 0x07, 0x05, 0x39, 0xe2, 0x54, 0x40, 0xca, 0x32, 0x31, 0x54, 0x5a, 0x80, 0x26, 0xb9, 0x56, - 0x56, 0xe1, 0x5b, 0x97, 0xf9, 0x17, 0x62, 0x52, 0xf2, 0xf7, 0x76, 0x27, 0x6a, 0xa2, 0x1c, 0x8f, - 0x96, 0x6f, 0x5e, 0xb2, 0xf7, 0x60, 0x8d, 0x05, 0x57, 0x69, 0xaa, 0x32, 0x6a, 0x2c, 0xb3, 0x73, - 0x53, 0x71, 0x07, 0x7f, 0xe7, 0x6a, 0x95, 0x24, 0x2c, 0xcf, 0x87, 0x39, 0xe3, 0x33, 0xb0, 0x95, - 0x26, 0xe2, 0xca, 0xa4, 0xca, 0xd0, 0x11, 0x33, 0x40, 0x8f, 0xfb, 0x23, 0xb0, 0xac, 0x4f, 0xb9, - 0x92, 0x99, 0xaf, 0xdf, 0xfd, 0xda, 0x44, 0xed, 0x67, 0x6e, 0x92, 0xd7, 0xe5, 0x20, 0xb8, 0x83, - 0xea, 0x52, 0x84, 0x41, 0x37, 0xe8, 0xb5, 0xe2, 0xba, 0x14, 0x98, 0xa0, 0xeb, 0x56, 0x33, 0x3e, - 0x93, 0xd9, 0xa4, 0x6a, 0x3c, 0x9c, 0x41, 0x11, 0xd6, 0x1d, 0x61, 0x67, 0x55, 0x7a, 0xe3, 0x2a, - 0x47, 0x50, 0x60, 0x86, 0x36, 0x72, 0x2d, 0x39, 0x84, 0x8d, 0x6e, 0xa3, 0xd7, 0x1e, 0xdc, 0x24, - 0xde, 0x9f, 0x94, 0xfe, 0xa4, 0xf2, 0x27, 0x4f, 0x95, 0xcc, 0x0e, 0x1f, 0x9f, 0x7e, 0xdf, 0xaf, - 0x7d, 0xf9, 0xb1, 0xdf, 0x9b, 0x48, 0x3b, 0x9d, 0x8f, 0x08, 0x57, 0x29, 0xad, 0x0e, 0xeb, 0x1f, - 0x8f, 0x8c, 0x98, 0x51, 0x5b, 0xe4, 0x60, 0x9c, 0xc0, 0xc4, 0xbe, 0x33, 0xfe, 0x88, 0x1a, 0x63, - 0x80, 0xb0, 0xf9, 0xff, 0x0d, 0xca, 0xbe, 0xf8, 0x36, 0x6a, 0x69, 0xe0, 0x32, 0x97, 0x90, 0xd9, - 0x70, 0xc3, 0xcd, 0x79, 0x01, 0xe0, 0x0f, 0xe8, 0xc6, 0x9f, 0xf7, 0xe1, 0x33, 0x0a, 0xb7, 0xba, - 0x41, 0xaf, 0x33, 0xb8, 0x47, 0xd6, 0xec, 0x80, 0x0f, 0x89, 0xbc, 0x75, 0xe4, 0x78, 0xf7, 0xf7, - 0x9b, 0xf3, 0x28, 0xbe, 0x83, 0xd0, 0x2a, 0x44, 0x29, 0xc2, 0x56, 0xe5, 0xed, 0x91, 0x97, 0x02, - 0x3f, 0x47, 0xcd, 0xf2, 0xb4, 0x21, 0x72, 0x4e, 0xfd, 0x7f, 0x38, 0xc5, 0x5e, 0xe7, 0x0d, 0xc8, - 0xbb, 0x22, 0x87, 0xd8, 0xc9, 0xf1, 0x43, 0xb4, 0x33, 0x9e, 0x27, 0x63, 0x99, 0x24, 0xa0, 0x87, - 0x4c, 0x08, 0x0d, 0xc6, 0x84, 0x6d, 0x67, 0xb6, 0x7d, 0x5e, 0x78, 0xe2, 0x71, 0x7c, 0x1f, 0x5d, - 0xe3, 0x1a, 0x98, 0x95, 0x2a, 0x1b, 0x4e, 0x41, 0x4e, 0xa6, 0x36, 0xbc, 0xda, 0x0d, 0x7a, 0xcd, - 0xb8, 0xb3, 0x82, 0x5f, 0x38, 0xf4, 0x55, 0x73, 0x6b, 0x73, 0xfb, 0xca, 0xe1, 0xd1, 0xe9, 0x22, - 0x0a, 0xce, 0x16, 0x51, 0xf0, 0x73, 0x11, 0x05, 0x9f, 0x97, 0x51, 0xed, 0x6c, 0x19, 0xd5, 0xbe, - 0x2d, 0xa3, 0xda, 0xfb, 0xfe, 0xa5, 0x14, 0xd6, 0xec, 0xf1, 0xf1, 0x01, 0x3d, 0xf1, 0xff, 0x96, - 0x0b, 0x65, 0xb4, 0xe9, 0x56, 0xf4, 0xe0, 0x57, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x0c, 0xaf, - 0x6c, 0x87, 0x03, 0x00, 0x00, + // 512 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xcf, 0x6f, 0xd3, 0x30, + 0x14, 0x6e, 0xba, 0x75, 0x5a, 0x5d, 0x54, 0x98, 0x19, 0x60, 0x06, 0x64, 0x15, 0x12, 0x22, 0x02, + 0xe1, 0xd0, 0xee, 0xc6, 0x8d, 0xf2, 0x43, 0x4c, 0x3b, 0x80, 0x02, 0x27, 0x10, 0x8a, 0x52, 0xfb, + 0xb5, 0xb5, 0xda, 0xc4, 0x91, 0xed, 0x4e, 0x0b, 0x47, 0xfe, 0x02, 0xfe, 0x0e, 0xfe, 0x92, 0x1d, + 0x77, 0xe4, 0x04, 0xa8, 0xfd, 0x47, 0x50, 0xec, 0x74, 0x1d, 0x48, 0x85, 0x0b, 0xa7, 0x24, 0xdf, + 0xfb, 0xbe, 0xf7, 0xf9, 0xf3, 0x7b, 0x41, 0x94, 0x17, 0x29, 0x64, 0x5a, 0xc8, 0xec, 0xa4, 0xf8, + 0x14, 0x9e, 0x7f, 0x84, 0x20, 0x06, 0x2c, 0xe4, 0x90, 0x26, 0x19, 0x8f, 0xa5, 0xe2, 0xa0, 0x68, + 0xae, 0xa4, 0x91, 0xf8, 0xd6, 0x45, 0xfe, 0x4a, 0x4c, 0x4b, 0xfe, 0xde, 0xee, 0x48, 0x8e, 0xa4, + 0xe5, 0x85, 0xe5, 0x9b, 0x93, 0xec, 0x3d, 0x58, 0x63, 0xc1, 0x64, 0x9a, 0xca, 0x2c, 0xd4, 0x26, + 0x31, 0x33, 0x5d, 0x71, 0x7b, 0x7f, 0xe7, 0x2a, 0x39, 0x9d, 0x26, 0x79, 0x1e, 0xe7, 0x09, 0x9b, + 0x80, 0xa9, 0x34, 0x3e, 0x93, 0x3a, 0x95, 0x3a, 0x1c, 0x24, 0x1a, 0xc2, 0xe3, 0xee, 0x00, 0x4c, + 0xd2, 0x0d, 0x99, 0x14, 0x99, 0xab, 0xdf, 0xfd, 0xdc, 0x40, 0xad, 0xe7, 0x36, 0xc9, 0xeb, 0x32, + 0x08, 0x6e, 0xa3, 0xba, 0xe0, 0xc4, 0xeb, 0x78, 0x41, 0x33, 0xaa, 0x0b, 0x8e, 0x29, 0xba, 0x6a, + 0x54, 0xc2, 0x26, 0x22, 0x1b, 0x55, 0x8d, 0xe3, 0x09, 0x14, 0xa4, 0x6e, 0x09, 0x3b, 0xcb, 0xd2, + 0x1b, 0x5b, 0x39, 0x82, 0x02, 0x27, 0xa8, 0x91, 0x2b, 0xc1, 0x80, 0x6c, 0x74, 0x36, 0x82, 0x56, + 0xef, 0x26, 0x75, 0xfe, 0xb4, 0xf4, 0xa7, 0x95, 0x3f, 0x7d, 0x26, 0x45, 0xd6, 0x7f, 0x7c, 0xfa, + 0x7d, 0xbf, 0xf6, 0xf5, 0xc7, 0x7e, 0x30, 0x12, 0x66, 0x3c, 0x1b, 0x50, 0x26, 0xd3, 0xb0, 0x3a, + 0xac, 0x7b, 0x3c, 0xd2, 0x7c, 0x12, 0x9a, 0x22, 0x07, 0x6d, 0x05, 0x3a, 0x72, 0x9d, 0xf1, 0x47, + 0xb4, 0x31, 0x04, 0x20, 0x9b, 0xff, 0xdf, 0xa0, 0xec, 0x8b, 0x6f, 0xa3, 0xa6, 0x02, 0x26, 0x72, + 0x01, 0x99, 0x21, 0x0d, 0x9b, 0x73, 0x05, 0xe0, 0x27, 0xe8, 0x06, 0x87, 0x5c, 0x01, 0x4b, 0x0c, + 0xf0, 0x58, 0xe8, 0x78, 0x38, 0x9b, 0x0e, 0xc5, 0x74, 0x0a, 0x9c, 0x6c, 0x75, 0xbc, 0x60, 0xbb, + 0x5f, 0x27, 0x5e, 0x74, 0x6d, 0x45, 0x39, 0xd4, 0x2f, 0x97, 0x04, 0xfc, 0x01, 0x5d, 0xff, 0xf3, + 0x2e, 0xdd, 0x7c, 0xc9, 0x76, 0xc7, 0x0b, 0xda, 0xbd, 0x7b, 0x74, 0xcd, 0xfe, 0xb8, 0x01, 0xd3, + 0xb7, 0x96, 0x1c, 0xed, 0xfe, 0x7e, 0xeb, 0x0e, 0xc5, 0x77, 0x10, 0x5a, 0x2e, 0x80, 0xe0, 0xa4, + 0x59, 0x9d, 0xdb, 0x21, 0x87, 0x1c, 0xbf, 0x40, 0x9b, 0x65, 0x52, 0x82, 0xac, 0x53, 0xf7, 0x1f, + 0x4e, 0x91, 0xd3, 0x39, 0x03, 0xfa, 0xae, 0xc8, 0x21, 0xb2, 0x72, 0xfc, 0x10, 0xed, 0x2c, 0x03, + 0xab, 0x38, 0xe1, 0x5c, 0x81, 0xd6, 0xa4, 0x65, 0xcd, 0xae, 0x9c, 0x17, 0x9e, 0x3a, 0x1c, 0xdf, + 0x47, 0x97, 0x99, 0x82, 0xc4, 0x08, 0x99, 0xc5, 0x63, 0x10, 0xa3, 0xb1, 0x21, 0x97, 0x3a, 0x5e, + 0xb0, 0x19, 0xb5, 0x97, 0xf0, 0x2b, 0x8b, 0xf6, 0x8f, 0x4e, 0xe7, 0xbe, 0x77, 0x36, 0xf7, 0xbd, + 0x9f, 0x73, 0xdf, 0xfb, 0xb2, 0xf0, 0x6b, 0x67, 0x0b, 0xbf, 0xf6, 0x6d, 0xe1, 0xd7, 0xde, 0x77, + 0x2f, 0xcc, 0x6e, 0xcd, 0xf6, 0x1f, 0x1f, 0x84, 0x27, 0xee, 0x8f, 0xb4, 0xa3, 0x1c, 0x6c, 0xd9, + 0xc5, 0x3e, 0xf8, 0x15, 0x00, 0x00, 0xff, 0xff, 0x6c, 0x42, 0xcd, 0xcc, 0xbd, 0x03, 0x00, 0x00, } func (m *DemandOrder) Marshal() (dAtA []byte, err error) { @@ -242,6 +254,16 @@ func (m *DemandOrder) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x40 } + if m.DeprecatedIsFulfilled { + i-- + if m.DeprecatedIsFulfilled { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x30 + } if len(m.Recipient) > 0 { i -= len(m.Recipient) copy(dAtA[i:], m.Recipient) @@ -335,6 +357,9 @@ func (m *DemandOrder) Size() (n int) { if l > 0 { n += 1 + l + sovDemandOrder(uint64(l)) } + if m.DeprecatedIsFulfilled { + n += 2 + } if m.TrackingPacketStatus != 0 { n += 1 + sovDemandOrder(uint64(m.TrackingPacketStatus)) } @@ -554,6 +579,26 @@ func (m *DemandOrder) Unmarshal(dAtA []byte) error { } m.Recipient = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedIsFulfilled", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowDemandOrder + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.DeprecatedIsFulfilled = bool(v != 0) case 8: if wireType != 0 { return fmt.Errorf("proto: wrong wireType = %d for field TrackingPacketStatus", wireType) diff --git a/x/iro/types/plan.go b/x/iro/types/plan.go index ba8e1aed4..c7d393c2f 100644 --- a/x/iro/types/plan.go +++ b/x/iro/types/plan.go @@ -2,16 +2,16 @@ package types import ( "errors" - fmt "fmt" + "fmt" "strings" - time "time" + "time" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) -const IROTokenPrefix = "future_" +const IROTokenPrefix = "IRO/" func IRODenom(rollappID string) string { return fmt.Sprintf("%s%s", IROTokenPrefix, rollappID) diff --git a/x/rollapp/keeper/registered_denoms.go b/x/rollapp/keeper/registered_denoms.go index 34c84a9e1..339e8017a 100644 --- a/x/rollapp/keeper/registered_denoms.go +++ b/x/rollapp/keeper/registered_denoms.go @@ -8,11 +8,7 @@ import ( ) func (k Keeper) SetRegisteredDenom(ctx sdk.Context, rollappID, denom string) error { - key := collections.Join(rollappID, denom) - if err := k.registeredRollappDenoms.Set(ctx, key); err != nil { - return fmt.Errorf("set registered denom: %w", err) - } - return nil + return k.registeredRollappDenoms.Set(ctx, collections.Join(rollappID, denom)) } func (k Keeper) HasRegisteredDenom(ctx sdk.Context, rollappID, denom string) (bool, error) { diff --git a/x/rollapp/types/message_update_state.go b/x/rollapp/types/message_update_state.go index 4af9b939a..0372b4b54 100644 --- a/x/rollapp/types/message_update_state.go +++ b/x/rollapp/types/message_update_state.go @@ -74,11 +74,10 @@ func (msg *MsgUpdateState) ValidateBasic() error { // check that the blocks are sequential by height for bdIndex := uint64(0); bdIndex < msg.NumBlocks; bdIndex += 1 { - // TODO: by now DRS version can be empty, but it will be deprecated - // https://github.com/dymensionxyz/dymension/issues/1233 - if msg.BDs.BD[bdIndex].DrsVersion <= 0 { - return ErrInvalidDRSVersion - } + // Pre 3D rollapps will use zero DRS until they upgrade. Post 3D rollapps + // should use a non-zero version. We rely on other fraud mechanisms + // to catch that if it's wrong. So we don't check DRS. + if msg.BDs.BD[bdIndex].Height != msg.StartHeight+bdIndex { return ErrInvalidBlockSequence } diff --git a/x/rollapp/types/message_update_state_test.go b/x/rollapp/types/message_update_state_test.go index 8aa6d2bb2..02db63c44 100644 --- a/x/rollapp/types/message_update_state_test.go +++ b/x/rollapp/types/message_update_state_test.go @@ -234,17 +234,6 @@ func TestMsgUpdateState_ValidateBasic(t *testing.T) { }}, }, err: ErrInvalidStateRoot, - }, { - name: "illegal invalid drs version", - msg: MsgUpdateState{ - Creator: sample.AccAddress(), - StartHeight: 1, - NumBlocks: 1, - BDs: BlockDescriptors{BD: []BlockDescriptor{ - {Height: 1, StateRoot: hash32}, - }}, - }, - err: ErrInvalidDRSVersion, }, } for _, tt := range tests { diff --git a/x/rollapp/types/params.go b/x/rollapp/types/params.go index 5b1240f02..751a80b7e 100644 --- a/x/rollapp/types/params.go +++ b/x/rollapp/types/params.go @@ -28,7 +28,8 @@ var ( // DYM is 1dym DYM = sdk.NewIntFromBigInt(new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)) - DefaultAppRegistrationFee = sdk.NewCoin(params.BaseDenom, DYM) + OneDymCoin = sdk.NewCoin(params.BaseDenom, DYM) + DefaultAppRegistrationFee = OneDymCoin ) const ( @@ -36,8 +37,8 @@ const ( // MinDisputePeriodInBlocks is the minimum number of blocks for dispute period MinDisputePeriodInBlocks uint64 = 1 - DefaultLivenessSlashBlocks = uint64(7200) // 12 hours at 1 block per 6 seconds - DefaultLivenessSlashInterval = uint64(3600) // 1 hour at 1 block per 6 seconds + DefaultLivenessSlashBlocks = uint64(7200) // 12 hours worth of blocks at 1 block per 6 seconds + DefaultLivenessSlashInterval = uint64(600) // 1 hour worth of blocks at 1 block per 6 seconds ) // ParamKeyTable the param key table for launch module diff --git a/x/sequencer/client/cli/tx.go b/x/sequencer/client/cli/tx.go index 5c523f561..18f739bc6 100644 --- a/x/sequencer/client/cli/tx.go +++ b/x/sequencer/client/cli/tx.go @@ -159,7 +159,7 @@ func CmdUpdateRewardAddress() *cobra.Command { } msg := &types.MsgUpdateRewardAddress{ - Creator: sdk.ValAddress(ctx.GetFromAddress()).String(), + Creator: ctx.GetFromAddress().String(), RewardAddr: args[0], } @@ -186,7 +186,7 @@ func CmdUpdateWhitelistedRelayers() *cobra.Command { } msg := &types.MsgUpdateWhitelistedRelayers{ - Creator: sdk.ValAddress(ctx.GetFromAddress()).String(), + Creator: ctx.GetFromAddress().String(), Relayers: strings.Split(args[0], ","), } diff --git a/x/sequencer/migrations.go b/x/sequencer/params_migrations.go similarity index 100% rename from x/sequencer/migrations.go rename to x/sequencer/params_migrations.go diff --git a/x/sequencer/migrations_test.go b/x/sequencer/params_migrations_test.go similarity index 100% rename from x/sequencer/migrations_test.go rename to x/sequencer/params_migrations_test.go diff --git a/x/sequencer/types/keys.go b/x/sequencer/types/keys.go index 5de67a919..56679891b 100644 --- a/x/sequencer/types/keys.go +++ b/x/sequencer/types/keys.go @@ -54,6 +54,10 @@ var ( NoticePeriodQueueKey = []byte{0x42} // prefix for the timestamps in notice period queue DymintProposerAddrToAccAddrKeyPrefix = collections.NewPrefix([]byte{0x43}) + + // These keys were already used on mainnet. Don't reuse + _ = []byte{0xa3} + _ = []byte{0x41} ) /* --------------------- specific sequencer address keys -------------------- */ diff --git a/x/sequencer/types/msg_update_whitelisted_relayers.go b/x/sequencer/types/msg_update_whitelisted_relayers.go index a98cacde8..b4a68f03e 100644 --- a/x/sequencer/types/msg_update_whitelisted_relayers.go +++ b/x/sequencer/types/msg_update_whitelisted_relayers.go @@ -6,8 +6,8 @@ import ( errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/bech32" "github.com/dymensionxyz/gerr-cosmos/gerrc" + "github.com/dymensionxyz/sdk-utils/utils/uaddr" ) const maxWhitelistedRelayers = 10 @@ -37,7 +37,7 @@ func ValidateWhitelistedRelayers(wr []string) error { } relayers[r] = struct{}{} - relayer, err := Bech32ToAddr[sdk.AccAddress](r) + relayer, err := uaddr.FromBech32[sdk.AccAddress](r) if err != nil { return fmt.Errorf("convert bech32 to relayer address: %s: %w", r, err) } @@ -49,16 +49,6 @@ func ValidateWhitelistedRelayers(wr []string) error { return nil } -// Bech32ToAddr casts an arbitrary-prefixed bech32 string to either sdk.AccAddress or sdk.ValAddress. -// TODO: move to sdk-utils. -func Bech32ToAddr[T sdk.AccAddress | sdk.ValAddress](addr string) (T, error) { - _, bytes, err := bech32.DecodeAndConvert(addr) - if err != nil { - return nil, fmt.Errorf("decoding bech32 addr: %w", err) - } - return T(bytes), nil -} - func (m *MsgUpdateWhitelistedRelayers) GetSigners() []sdk.AccAddress { addr, _ := sdk.AccAddressFromBech32(m.Creator) return []sdk.AccAddress{addr} diff --git a/x/sequencer/types/params.go b/x/sequencer/types/params.go index 3e498e43a..1fc44efc4 100644 --- a/x/sequencer/types/params.go +++ b/x/sequencer/types/params.go @@ -5,21 +5,23 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" + "github.com/dymensionxyz/sdk-utils/utils/ucoin" "github.com/dymensionxyz/sdk-utils/utils/uparam" "gopkg.in/yaml.v2" ) var ( // DefaultMinBond is the minimum bond required to be a validator - DefaultMinBond uint64 = 1000000 + DefaultMinBond = ucoin.SimpleMul(rollapptypes.OneDymCoin, 100) // DefaultKickThreshold is the minimum bond required to be a validator - DefaultKickThreshold uint64 = 10 + DefaultKickThreshold = rollapptypes.OneDymCoin // DefaultNoticePeriod is the time duration for notice period DefaultNoticePeriod = time.Hour * 24 * 7 // 1 week // DefaultLivenessSlashMultiplier gives the amount of tokens to slash if the sequencer is liable for a liveness failure DefaultLivenessSlashMultiplier = sdk.MustNewDecFromStr("0.01") // DefaultLivenessSlashMinAbsolute will be slashed if the multiplier amount is too small - DefaultLivenessSlashMinAbsolute uint64 = 1 + DefaultLivenessSlashMinAbsolute = rollapptypes.OneDymCoin ) // NewParams creates a new Params instance @@ -35,16 +37,8 @@ func NewParams(minBond sdk.Coin, noticePeriod time.Duration, livenessSlashMul sd // DefaultParams returns a default set of parameters func DefaultParams() Params { - denom, err := sdk.GetBaseDenom() - if err != nil { - panic(err) - } - minBond := sdk.NewCoin(denom, sdk.NewIntFromUint64(DefaultMinBond)) - kick := sdk.NewCoin(denom, sdk.NewIntFromUint64(DefaultKickThreshold)) - slashAbs := sdk.NewCoin(denom, sdk.NewIntFromUint64(DefaultLivenessSlashMinAbsolute)) return NewParams( - minBond, DefaultNoticePeriod, DefaultLivenessSlashMultiplier, slashAbs, - kick, + DefaultMinBond, DefaultNoticePeriod, DefaultLivenessSlashMultiplier, DefaultLivenessSlashMinAbsolute, DefaultKickThreshold, ) } diff --git a/x/sponsorship/types/params.go b/x/sponsorship/types/params.go index 27099b04f..1109e58e0 100644 --- a/x/sponsorship/types/params.go +++ b/x/sponsorship/types/params.go @@ -1,12 +1,5 @@ package types -import ( - "fmt" - - sdk "github.com/cosmos/cosmos-sdk/types" - paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" -) - var ( KeyMinAllocationWeight = []byte("MinAllocationWeight") KeyMinVotingPower = []byte("MinVotingPower") @@ -31,46 +24,3 @@ func (p Params) Validate() error { } return nil } - -// ParamKeyTable for the x/sponsorship module. -func ParamKeyTable() paramtypes.KeyTable { - return paramtypes.NewKeyTable().RegisterParamSet(&Params{}) -} - -// ParamSetPairs implements params.ParamSet. Params must have a pointer receiver since it is registered as -// a pointer in the ParamKeyTable method. -func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { - return paramtypes.ParamSetPairs{ - paramtypes.NewParamSetPair(KeyMinAllocationWeight, &p.MinAllocationWeight, validateMinAllocationWeight), - paramtypes.NewParamSetPair(KeyMinVotingPower, &p.MinVotingPower, validateMinVotingPower), - } -} - -func validateMinAllocationWeight(i interface{}) error { - value, ok := i.(sdk.Int) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - if value.IsNegative() { - return ErrInvalidParams.Wrapf("MinAllocationWeight must be >= 0, got %s", value) - } - if value.GT(MaxAllocationWeight) { - return ErrInvalidParams.Wrapf("MinAllocationWeight must be <= 100 * 10^18, got %s", value) - } - - return nil -} - -func validateMinVotingPower(i interface{}) error { - value, ok := i.(sdk.Int) - if !ok { - return fmt.Errorf("invalid parameter type: %T", i) - } - - if value.IsNegative() { - return ErrInvalidParams.Wrapf("MinVotingPower must be >= 0, got %s", value) - } - - return nil -} From 5c42bf802dd3ade82b8b5fdefa806c35f29d8c5e Mon Sep 17 00:00:00 2001 From: danwt <30197399+danwt@users.noreply.github.com> Date: Fri, 8 Nov 2024 18:08:28 +0000 Subject: [PATCH 44/68] fix frozen --- app/upgrades/v4/upgrade.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/upgrades/v4/upgrade.go b/app/upgrades/v4/upgrade.go index 27418deca..0d9bd684c 100644 --- a/app/upgrades/v4/upgrade.go +++ b/app/upgrades/v4/upgrade.go @@ -262,7 +262,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: "", @@ -281,8 +280,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, + RevisionNumber: 0, + RevisionStartHeight: 0, } } From 94f52ecc13d9489d648e551f6c62e480672dfae8 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sat, 9 Nov 2024 22:27:43 +0200 Subject: [PATCH 45/68] refactored to use Finalaization queue by rollappId --- app/upgrades/v4/upgrade.go | 1 - proto/dymensionxyz/dymension/rollapp/tx.proto | 2 +- x/common/types/key_rollapp_packet.go | 3 ++ x/eibc/keeper/msg_server_test.go | 2 +- x/eibc/types/keys.go | 2 + x/lightclient/ante/ibc_msg_update_client.go | 2 +- x/lightclient/keeper/canonical_client.go | 2 +- x/lightclient/keeper/hook_listener.go | 1 - x/rollapp/genesis.go | 7 --- .../grpc_query_obsolete_drs_versions.go | 2 +- .../grpc_query_obsolete_drs_versions_test.go | 4 +- x/rollapp/keeper/hard_fork.go | 50 +++++-------------- x/rollapp/keeper/hard_fork_test.go | 8 +-- x/rollapp/keeper/liveness_test.go | 5 -- x/rollapp/keeper/msg_server_update_state.go | 4 +- 15 files changed, 32 insertions(+), 63 deletions(-) diff --git a/app/upgrades/v4/upgrade.go b/app/upgrades/v4/upgrade.go index 15d29e54c..4dabee8b7 100644 --- a/app/upgrades/v4/upgrade.go +++ b/app/upgrades/v4/upgrade.go @@ -323,7 +323,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: "", diff --git a/proto/dymensionxyz/dymension/rollapp/tx.proto b/proto/dymensionxyz/dymension/rollapp/tx.proto index 56ef6e574..763a7896c 100644 --- a/proto/dymensionxyz/dymension/rollapp/tx.proto +++ b/proto/dymensionxyz/dymension/rollapp/tx.proto @@ -89,7 +89,7 @@ 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 + // rollapp_revision is the revision of the rollapp chain. increases after hard fork uint64 rollapp_revision = 9; } diff --git a/x/common/types/key_rollapp_packet.go b/x/common/types/key_rollapp_packet.go index 9566d4303..9de033283 100644 --- a/x/common/types/key_rollapp_packet.go +++ b/x/common/types/key_rollapp_packet.go @@ -18,6 +18,9 @@ var ( PendingRollappPacketKeyPrefix = []byte{0x00, 0x01} // FinalizedRollappPacketKeyPrefix is the prefix for finalized rollapp packets FinalizedRollappPacketKeyPrefix = []byte{0x00, 0x02} + + _ = []byte{0x00, 0x03} // deprecated key + // keySeparatorBytes is used to separate the rollapp packet key parts keySeparatorBytes = []byte("/") ) diff --git a/x/eibc/keeper/msg_server_test.go b/x/eibc/keeper/msg_server_test.go index b463cb5b0..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.UpdateRollappPacketAfterFinalization(suite.Ctx, *rollappPacket) + _, err = suite.App.DelayedAckKeeper.UpdateRollappPacketAfterFinalization(suite.Ctx, rPacket) suite.Require().NoError(err, tc.name) } diff --git a/x/eibc/types/keys.go b/x/eibc/types/keys.go index e44e789b7..84a29422f 100644 --- a/x/eibc/types/keys.go +++ b/x/eibc/types/keys.go @@ -34,6 +34,8 @@ var ( PendingDemandOrderKeyPrefix = []byte{0x00, 0x01} // FinalizedDemandOrderKeyPrefix is the prefix for finalized demand orders FinalizedDemandOrderKeyPrefix = []byte{0x00, 0x02} + + _ = []byte{0x00, 0x03} // deprecated key ) // GetDemandOrderKey constructs a key for a specific DemandOrder. diff --git a/x/lightclient/ante/ibc_msg_update_client.go b/x/lightclient/ante/ibc_msg_update_client.go index b8029676a..719151279 100644 --- a/x/lightclient/ante/ibc_msg_update_client.go +++ b/x/lightclient/ante/ibc_msg_update_client.go @@ -62,7 +62,7 @@ func (i IBCMessagesDecorator) HandleMsgUpdateClient(ctx sdk.Context, msg *ibccli return gerrc.ErrInternal.Wrapf("get rollapp from sequencer: rollapp: %s", seq.RollappId) } - // cannot update the LC unless fork is resolved (after receiving state updates of HF height +1 & HF height +2 + // 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 } diff --git a/x/lightclient/keeper/canonical_client.go b/x/lightclient/keeper/canonical_client.go index ba8b25862..c5a0880ad 100644 --- a/x/lightclient/keeper/canonical_client.go +++ b/x/lightclient/keeper/canonical_client.go @@ -83,7 +83,7 @@ func (k Keeper) validClient(ctx sdk.Context, clientID string, cs exported.Client return errorsmod.Wrap(err, "params") } - // FIXME: No need to get all consensus states. should iterate over the consensus states in reverse order + // 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/hook_listener.go b/x/lightclient/keeper/hook_listener.go index 606951b3f..4b12bc286 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -110,7 +110,6 @@ func (hook rollappHook) validateOptimisticUpdate( } err = types.CheckCompatibility(*got, expect) if err != nil { - // return gerrc.ErrFault return errors.Join(gerrc.ErrFault, err) } diff --git a/x/rollapp/genesis.go b/x/rollapp/genesis.go index e4d3e0945..9880dcc32 100644 --- a/x/rollapp/genesis.go +++ b/x/rollapp/genesis.go @@ -59,13 +59,6 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, genState types.GenesisState) } } - for _, elem := range genState.SequencerHeightPairs { - err := k.SaveSequencerHeight(ctx, elem.Sequencer, elem.Height) - if err != nil { - panic(err) - } - } - k.SetParams(ctx, genState.Params) } 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/hard_fork.go b/x/rollapp/keeper/hard_fork.go index 8170c5721..cefaaf814 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -44,11 +44,11 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) return nil } -// removes state updates until the one specified and included +// 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, fraudHeight uint64) (uint64, error) { // find the affected state info index - // skip if not found (fraud height is not committed yet) + // use latest state info for future height stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, fraudHeight) if errorsmod.IsOf(err, gerrc.ErrNotFound) { s, ok := k.GetLatestStateInfo(ctx, rollappID) @@ -73,7 +73,7 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig return 0, errorsmod.Wrap(err, "update last state info") } - // clear pending states post the fraud height + // clear states updates post the fraud height revertedStatesCount := 0 // Counter for reverted state updates uniqueProposers := make(map[string]struct{}) // Map to manage unique proposers @@ -93,45 +93,21 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig }) // remove all the pending states from the finalization queue - // we iterate over the queue, - // - skipping the states that are not related to the rollapp - // - skipping the states that are less than the rollback index - queuePerHeight := k.GetAllBlockHeightToFinalizationQueue(ctx) // FIXME (#631): Prefix store by rollappID for efficient querying - for _, queue := range queuePerHeight { - leftPendingStates := []types.StateInfoIndex{} - for _, stateInfoIndex := range queue.FinalizationQueue { - // keep pending packets not related to this rollapp in the queue - if stateInfoIndex.RollappId != rollappID { - leftPendingStates = append(leftPendingStates, stateInfoIndex) - continue - } + queuePerHeight, err := k.GetFinalizationQueueByRollapp(ctx, rollappID) + if err != nil { + return 0, fmt.Errorf("get finalization queue by rollapp: %s: %w", rollappID, err) + } - // keep state info indexes with index less than the rollback index - if stateInfoIndex.Index <= lastStateIdxToKeep { - leftPendingStates = append(leftPendingStates, stateInfoIndex) - continue + for _, queue := range queuePerHeight { + if queue.FinalizationQueue[0].Index > lastStateIdxToKeep { + err = k.RemoveFinalizationQueue(ctx, queue.CreationHeight, queue.RollappId) + if err != nil { + return 0, fmt.Errorf("remove finalization queue: %w", err) } } - - // no change in the queue - if len(leftPendingStates) == len(queue.FinalizationQueue) { - continue - } - - // remove the queue if no pending states left - if len(leftPendingStates) == 0 { - k.RemoveBlockHeightToFinalizationQueue(ctx, queue.CreationHeight) - continue - } - - // update the queue after removing the reverted states - k.SetBlockHeightToFinalizationQueue(ctx, types.BlockHeightToFinalizationQueue{ - CreationHeight: queue.CreationHeight, - FinalizationQueue: leftPendingStates, - }) } - // remove the sequencer heights + // remove the sequencers heights lastStateInfo := k.MustGetStateInfo(ctx, rollappID, lastStateIdxToKeep) err = k.PruneSequencerHeights(ctx, mapKeysToSlice(uniqueProposers), lastStateInfo.GetLatestHeight()) if err != nil { diff --git a/x/rollapp/keeper/hard_fork_test.go b/x/rollapp/keeper/hard_fork_test.go index 22bc6d0fc..0ad8dce9a 100644 --- a/x/rollapp/keeper/hard_fork_test.go +++ b/x/rollapp/keeper/hard_fork_test.go @@ -69,8 +69,9 @@ func (suite *RollappTestSuite) TestHardFork() { // Assert initial stats (revision 0, states pending) suite.assertNotForked(rollappId) - queue := suite.App.RollappKeeper.GetAllFinalizationQueueUntilHeightInclusive(suite.Ctx, initialHeight+numOfStates+suite.App.RollappKeeper.DisputePeriodInBlocks(suite.Ctx)) - suite.Require().Len(queue, int(numOfStates)) + 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))) @@ -146,7 +147,8 @@ func (suite *RollappTestSuite) assertFraudHandled(rollappId string, height uint6 suite.Require().True(ok) // check queue - queue := suite.App.RollappKeeper.GetAllBlockHeightToFinalizationQueue(suite.Ctx) + 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 { diff --git a/x/rollapp/keeper/liveness_test.go b/x/rollapp/keeper/liveness_test.go index cb2e1969d..ea20a7277 100644 --- a/x/rollapp/keeper/liveness_test.go +++ b/x/rollapp/keeper/liveness_test.go @@ -185,11 +185,6 @@ func (l livenessMockSequencerKeeper) PunishSequencer(ctx sdk.Context, seqAddr st panic("implement me") } -// JailByAddr implements types.SequencerKeeper. -func (l livenessMockSequencerKeeper) JailByAddr(ctx sdk.Context, seqAddr string) error { - panic("unimplemented") -} - func newLivenessMockSequencerKeeper() livenessMockSequencerKeeper { return livenessMockSequencerKeeper{ make(map[string]int), diff --git a/x/rollapp/keeper/msg_server_update_state.go b/x/rollapp/keeper/msg_server_update_state.go index 2386801bd..00f38ebe8 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -103,10 +103,10 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) if k.IsStateUpdateObsolete(ctx, stateInfo) { err := k.HardForkToLatest(ctx, msg.RollappId) if err != nil { - return nil, fmt.Errorf("mark rollapp obsolete: %w", err) + return nil, fmt.Errorf("hard fork due to obsolete version: %w", err) } k.Logger(ctx).With("rollapp_id", msg.RollappId, "drs_version", stateInfo.GetLatestBlockDescriptor().DrsVersion). - Info("rollapp tried to submit MsgUpdateState with the obsolete DRS version, mark the rollapp as obsolete") + Info("rollapp tried to submit MsgUpdateState with an obsolete DRS version,forked") // we must return non-error if we want the changes to be saved return &types.MsgUpdateStateResponse{}, nil From 40b3557830845248f1691ce71da26fc0fefea612 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 09:44:19 +0200 Subject: [PATCH 46/68] fixed pruning of finalization queue --- x/rollapp/keeper/hard_fork.go | 46 ++++++++++++++++++++++++++-------- x/sequencer/keeper/proposer.go | 7 +----- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index cefaaf814..d247ea084 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -93,18 +93,9 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig }) // remove all the pending states from the finalization queue - queuePerHeight, err := k.GetFinalizationQueueByRollapp(ctx, rollappID) + err = k.pruneFinalizationsAbove(ctx, rollappID, lastStateIdxToKeep) if err != nil { - return 0, fmt.Errorf("get finalization queue by rollapp: %s: %w", rollappID, err) - } - - for _, queue := range queuePerHeight { - if queue.FinalizationQueue[0].Index > lastStateIdxToKeep { - err = k.RemoveFinalizationQueue(ctx, queue.CreationHeight, queue.RollappId) - if err != nil { - return 0, fmt.Errorf("remove finalization queue: %w", err) - } - } + return 0, fmt.Errorf("remove finalization queue: %w", err) } // remove the sequencers heights @@ -164,3 +155,36 @@ func mapKeysToSlice(m map[string]struct{}) []string { 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/sequencer/keeper/proposer.go b/x/sequencer/keeper/proposer.go index 155f97d59..2cafa571a 100644 --- a/x/sequencer/keeper/proposer.go +++ b/x/sequencer/keeper/proposer.go @@ -34,7 +34,6 @@ func (k Keeper) RollappPotentialProposers(ctx sdk.Context, rollappId string) []t seqs = slices.DeleteFunc(seqs, func(seq types.Sequencer) bool { return !seq.IsPotentialProposer() }) - // FIXME: sentinel can be added only if no sequencers are bonded return append(seqs, k.SentinelSequencer(ctx)) } @@ -85,11 +84,7 @@ func (k Keeper) chooseSuccessor(ctx sdk.Context, rollapp string) error { // a valid successor is already set so there's no need to do anything return nil } - // FIXME: why this check needed? - proposer := k.GetProposer(ctx, rollapp) - if proposer.Sentinel() { - return nil - } + seqs := k.RollappPotentialProposers(ctx, rollapp) successor, err := ProposerChoiceAlgo(seqs) if err != nil { From 29bd020fe9c2c7427d8ca22f22285ce19ad1cbf3 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 10:04:35 +0200 Subject: [PATCH 47/68] cleared unused expected methods --- app/keepers/keepers.go | 2 -- app/keepers/modules.go | 2 +- testutil/keeper/dymns.go | 2 +- testutil/keeper/rollapp.go | 2 +- x/delayedack/types/expected_keepers.go | 4 ---- x/dymns/keeper/keeper_suite_test.go | 3 ++- x/eibc/types/expected_keepers.go | 1 - x/lightclient/types/expected_keepers.go | 2 -- x/rollapp/keeper/expected_keepers.go | 9 --------- x/rollapp/keeper/keeper.go | 6 ------ x/sequencer/module.go | 7 +++---- x/sequencer/simulation/create_sequencer.go | 5 +---- x/sequencer/types/expected_keepers.go | 1 - 13 files changed, 9 insertions(+), 37 deletions(-) diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index c78ca6eec..33e9c4f0d 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -355,9 +355,7 @@ func (a *AppKeepers) InitKeepers( appCodec, a.keys[rollappmoduletypes.StoreKey], a.GetSubspace(rollappmoduletypes.ModuleName), - a.AccountKeeper, a.IBCKeeper.ChannelKeeper, - a.IBCKeeper.ClientKeeper, nil, a.BankKeeper, a.TransferKeeper, diff --git a/app/keepers/modules.go b/app/keepers/modules.go index f70b5cb9e..7eb6c2f5c 100644 --- a/app/keepers/modules.go +++ b/app/keepers/modules.go @@ -203,7 +203,7 @@ func (a *AppKeepers) SetupModules( ibctransfer.NewAppModule(a.TransferKeeper), rollappmodule.NewAppModule(appCodec, a.RollappKeeper, a.AccountKeeper, a.BankKeeper), iro.NewAppModule(appCodec, *a.IROKeeper), - sequencermodule.NewAppModule(appCodec, a.SequencerKeeper, a.AccountKeeper, a.BankKeeper, a.GetSubspace(sequencertypes.ModuleName)), + sequencermodule.NewAppModule(appCodec, a.SequencerKeeper, a.BankKeeper, a.GetSubspace(sequencertypes.ModuleName)), sponsorship.NewAppModule(a.SponsorshipKeeper), streamermodule.NewAppModule(a.StreamerKeeper, a.AccountKeeper, a.BankKeeper, a.EpochsKeeper), delayedackmodule.NewAppModule(appCodec, a.DelayedAckKeeper, a.delayedAckMiddleware), 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/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/delayedack/types/expected_keepers.go b/x/delayedack/types/expected_keepers.go index e5607934e..327d08cd3 100644 --- a/x/delayedack/types/expected_keepers.go +++ b/x/delayedack/types/expected_keepers.go @@ -13,15 +13,11 @@ import ( // ChannelKeeper defines the expected IBC channel keeper type ChannelKeeper interface { LookupModuleByChannel(ctx sdk.Context, portID, channelID string) (string, *capabilitytypes.Capability, error) - SetPacketReceipt(ctx sdk.Context, portID, channelID string, sequence uint64) 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/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/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/lightclient/types/expected_keepers.go b/x/lightclient/types/expected_keepers.go index 65dc146c4..59999b6d1 100644 --- a/x/lightclient/types/expected_keepers.go +++ b/x/lightclient/types/expected_keepers.go @@ -20,10 +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) - GetStateInfo(ctx sdk.Context, rollappId string, index uint64) (val rollapptypes.StateInfo, found bool) GetLatestStateInfo(ctx sdk.Context, rollappId string) (rollapptypes.StateInfo, bool) SetRollapp(ctx sdk.Context, rollapp rollapptypes.Rollapp) - HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error } type IBCClientKeeperExpected interface { diff --git a/x/rollapp/keeper/expected_keepers.go b/x/rollapp/keeper/expected_keepers.go index 3195ba743..46c5dbabf 100644 --- a/x/rollapp/keeper/expected_keepers.go +++ b/x/rollapp/keeper/expected_keepers.go @@ -9,15 +9,6 @@ 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) } diff --git a/x/rollapp/keeper/keeper.go b/x/rollapp/keeper/keeper.go index 2b9753cff..0950c226f 100644 --- a/x/rollapp/keeper/keeper.go +++ b/x/rollapp/keeper/keeper.go @@ -34,8 +34,6 @@ 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 @@ -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,8 +82,6 @@ func NewKeeper( hooks: nil, channelKeeper: channelKeeper, authority: authority, - accKeeper: ak, - ibcClientKeeper: ibcclientKeeper, sequencerKeeper: sequencerKeeper, bankKeeper: bankKeeper, transferKeeper: transferKeeper, diff --git a/x/sequencer/module.go b/x/sequencer/module.go index 171755e03..7d3c9989e 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,8 +100,8 @@ type AppModule struct { AppModuleBasic keeper *keeper.Keeper - accountKeeper types.AccountKeeper - bankKeeper types.BankKeeper + accountKeeper simulationtypes.AccountKeeper + bankKeeper simulationtypes.BankKeeper // legacySubspace is used solely for migration of x/params managed parameters legacySubspace Subspace @@ -109,14 +110,12 @@ type AppModule struct { func NewAppModule( cdc codec.Codec, keeper *keeper.Keeper, - accountKeeper types.AccountKeeper, bankKeeper types.BankKeeper, ss Subspace, ) AppModule { return AppModule{ AppModuleBasic: NewAppModuleBasic(cdc), keeper: keeper, - accountKeeper: accountKeeper, bankKeeper: bankKeeper, legacySubspace: ss, } 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..66b6a1bf5 100644 --- a/x/sequencer/types/expected_keepers.go +++ b/x/sequencer/types/expected_keepers.go @@ -13,7 +13,6 @@ 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 } // AccountKeeper defines the expected account keeper used for simulations (noalias) From 44eccc450ff6b55bb5e77f363d623642cc2a12b6 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 10:04:45 +0200 Subject: [PATCH 48/68] linter --- x/rollapp/keeper/hard_fork.go | 6 +++--- x/sequencer/keeper/fraud.go | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index d247ea084..2985fa75e 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -20,18 +20,18 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) return gerrc.ErrNotFound } - lastCommittedHeight, err := k.RevertPendingStates(ctx, rollappID, fraudHeight) + lastValidHeight, err := k.RevertPendingStates(ctx, rollappID, fraudHeight) if err != nil { return errorsmod.Wrap(err, "revert pending states") } // update revision number rollapp.RevisionNumber += 1 - rollapp.RevisionStartHeight = lastCommittedHeight + 1 + rollapp.RevisionStartHeight = lastValidHeight + 1 k.SetRollapp(ctx, rollapp) // handle the sequencers, clean delayed packets, handle light client - k.hooks.OnHardFork(ctx, rollappID, lastCommittedHeight+1) + k.hooks.OnHardFork(ctx, rollappID, lastValidHeight+1) ctx.EventManager().EmitEvent( sdk.NewEvent( diff --git a/x/sequencer/keeper/fraud.go b/x/sequencer/keeper/fraud.go index 2c7027424..2bf168197 100644 --- a/x/sequencer/keeper/fraud.go +++ b/x/sequencer/keeper/fraud.go @@ -85,7 +85,12 @@ func (k Keeper) PunishSequencer(ctx sdk.Context, seqAddr string, rewardee *sdk.A if err != nil { return errorsmod.Wrap(err, "slash") } - err = errorsmod.Wrap(k.unbond(ctx, &seq), "unbond") + + err = k.unbond(ctx, &seq) + if err != nil { + return errorsmod.Wrap(err, "unbond") + } + k.SetSequencer(ctx, seq) return nil } From f44f36c85d3b9dc8f20a44b619dfa70025ec24ae Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 10:14:28 +0200 Subject: [PATCH 49/68] more cleanup --- x/lightclient/keeper/rollback.go | 15 --------------- x/lightclient/types/errors.go | 4 ++-- x/rollapp/keeper/fraud_proposal.go | 4 ++-- x/rollapp/keeper/grpc_query_state_info.go | 2 +- x/rollapp/keeper/hard_fork.go | 3 +-- x/rollapp/keeper/liveness_test.go | 2 +- 6 files changed, 7 insertions(+), 23 deletions(-) diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index f67181077..045ddd141 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -1,8 +1,6 @@ package keeper import ( - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v7/modules/core/exported" @@ -102,19 +100,6 @@ func (k Keeper) resetClientToValidState(clientStore sdk.KVStore, height uint64) setClientState(clientStore, k.cdc, tmClientState) } -func GetPreviousConsensusStateHeight(clientStore sdk.KVStore, cdc codec.BinaryCodec, height exported.Height) (exported.Height, bool) { - iterateStore := prefix.NewStore(clientStore, []byte(ibctm.KeyIterateConsensusStatePrefix)) - iterator := iterateStore.ReverseIterator(nil, bigEndianHeightBytes(height)) - defer iterator.Close() // nolint: errcheck - - if !iterator.Valid() { - return nil, false - } - - prevHeight := ibctm.GetHeightFromIterationKey(iterator.Key()) - return prevHeight, true -} - // 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)) { diff --git a/x/lightclient/types/errors.go b/x/lightclient/types/errors.go index bc8db3724..c4f3b1517 100644 --- a/x/lightclient/types/errors.go +++ b/x/lightclient/types/errors.go @@ -9,8 +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 not found") + 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, "cannot update light client until forking is finished") + ErrorHardForkInProgress = errorsmod.Wrap(gerrc.ErrFailedPrecondition, "update light client until forking is finished") ) diff --git a/x/rollapp/keeper/fraud_proposal.go b/x/rollapp/keeper/fraud_proposal.go index 9eec3ea2b..5817c74fe 100644 --- a/x/rollapp/keeper/fraud_proposal.go +++ b/x/rollapp/keeper/fraud_proposal.go @@ -10,7 +10,7 @@ import ( "github.com/dymensionxyz/gerr-cosmos/gerrc" ) -// FraudProposalHandler handles the submission of a fraud proposal +// SubmitRollappFraud handles the submission of a fraud proposal // The fraud proposal can be submitted by the gov module func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappFraudProposal) (*types.MsgRollappFraudProposalResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -43,7 +43,7 @@ func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappF return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "no state info found") } - // check wether the fraud height is already finalized + // check whether the fraud height is already finalized sinfo, found = k.GetLatestFinalizedStateInfo(ctx, msg.RollappId) if found && sinfo.GetLatestHeight() >= msg.FraudHeight { return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height already finalized") diff --git a/x/rollapp/keeper/grpc_query_state_info.go b/x/rollapp/keeper/grpc_query_state_info.go index 81143488e..441814a38 100644 --- a/x/rollapp/keeper/grpc_query_state_info.go +++ b/x/rollapp/keeper/grpc_query_state_info.go @@ -77,7 +77,7 @@ func (k Keeper) FindStateInfoByHeight(ctx sdk.Context, rollappId string, height } // initial interval to search in - startInfoIndex := uint64(1) // TODO: startInfo should start at least with last unpruned hight (https://github.com/dymensionxyz/dymension/issues/1307) + 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 diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index 2985fa75e..3d11835ef 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -113,7 +113,7 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig // It returns the index of the last state info to keep. func (k Keeper) UpdateLastStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) (uint64, error) { if fraudHeight < stateInfo.StartHeight { - return 0, errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "state info start height is greater than fraud height") + return 0, errorsmod.Wrapf(gerrc.ErrInternal, "state info start height is greater than fraud height") } if stateInfo.StartHeight == fraudHeight { @@ -164,7 +164,6 @@ func (k Keeper) pruneFinalizationsAbove(ctx sdk.Context, rollappID string, lastS 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) diff --git a/x/rollapp/keeper/liveness_test.go b/x/rollapp/keeper/liveness_test.go index ea20a7277..272acebfc 100644 --- a/x/rollapp/keeper/liveness_test.go +++ b/x/rollapp/keeper/liveness_test.go @@ -181,7 +181,7 @@ type livenessMockSequencerKeeper struct { } func (l livenessMockSequencerKeeper) PunishSequencer(ctx sdk.Context, seqAddr string, rewardee *sdk.AccAddress) error { - //TODO implement me + // TODO implement me panic("implement me") } From 9c436399a94fdcb98c870ae730c5463a5c2e43b6 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 12:17:54 +0200 Subject: [PATCH 50/68] comments --- x/delayedack/keeper/fraud.go | 6 +----- x/lightclient/keeper/client_store.go | 9 --------- x/rollapp/keeper/msg_server_create_rollapp.go | 3 ++- x/sequencer/keeper/proposer.go | 2 +- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 9d13b04ae..96e62eb5b 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -52,11 +52,7 @@ func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64 } // delete the pending packet - err = k.DeletePendingPacketByAddress(ctx, pendingAddr, rollappPacket.RollappPacketKey()) - if err != nil { - logger.Error("failed to delete reverted PacketByAddress", append(logContext, "error", err.Error())...) - continue - } + k.MustDeletePendingPacketByAddress(ctx, pendingAddr, rollappPacket.RollappPacketKey()) logger.Debug("reverted IBC rollapp packet", logContext...) } diff --git a/x/lightclient/keeper/client_store.go b/x/lightclient/keeper/client_store.go index 0fc1f760a..d3665004b 100644 --- a/x/lightclient/keeper/client_store.go +++ b/x/lightclient/keeper/client_store.go @@ -1,8 +1,6 @@ package keeper import ( - "encoding/binary" - "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" @@ -67,10 +65,3 @@ func deleteIterationKey(clientStore sdk.KVStore, height exported.Height) { key := ibctm.IterationKey(height) clientStore.Delete(key) } - -func bigEndianHeightBytes(height exported.Height) []byte { - heightBytes := make([]byte, 16) - binary.BigEndian.PutUint64(heightBytes, height.GetRevisionNumber()) - binary.BigEndian.PutUint64(heightBytes[8:], height.GetRevisionHeight()) - return heightBytes -} diff --git a/x/rollapp/keeper/msg_server_create_rollapp.go b/x/rollapp/keeper/msg_server_create_rollapp.go index ab25d3e05..a7eb980da 100644 --- a/x/rollapp/keeper/msg_server_create_rollapp.go +++ b/x/rollapp/keeper/msg_server_create_rollapp.go @@ -17,7 +17,8 @@ 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 revision number should always be 1 + // 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 if rollappId.GetRevisionNumber() != 1 { return nil, errorsmod.Wrapf(types.ErrInvalidRollappID, "revision number should be 1, got: %d", rollappId.GetRevisionNumber()) } diff --git a/x/sequencer/keeper/proposer.go b/x/sequencer/keeper/proposer.go index 2cafa571a..6528f15d4 100644 --- a/x/sequencer/keeper/proposer.go +++ b/x/sequencer/keeper/proposer.go @@ -77,7 +77,7 @@ func (k Keeper) UpdateProposerIfNeeded(ctx sdk.Context, rollapp string) error { } // ChooseSuccessor will assign a successor. It won't replace an existing one. -// It will prioritise non sentinel +// It will prioritize non sentinel func (k Keeper) chooseSuccessor(ctx sdk.Context, rollapp string) error { successor := k.GetSuccessor(ctx, rollapp) if !successor.Sentinel() { From e3570f5858ebb12f399d627235a4b52cbcfb8e4e Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 13:22:22 +0200 Subject: [PATCH 51/68] fixed packet commitment and lightclient comments --- ibctesting/light_client_test.go | 4 ++-- x/common/types/rollapp_packet.go | 9 +++------ x/delayedack/keeper/finalize.go | 5 +---- x/delayedack/keeper/fraud.go | 3 ++- x/lightclient/keeper/hook_listener.go | 16 +++------------- x/lightclient/keeper/keeper.go | 6 +----- x/lightclient/keeper/rollback.go | 20 ++++++++++++-------- 7 files changed, 24 insertions(+), 39 deletions(-) diff --git a/ibctesting/light_client_test.go b/ibctesting/light_client_test.go index 6f30fef60..4776a1984 100644 --- a/ibctesting/light_client_test.go +++ b/ibctesting/light_client_test.go @@ -457,8 +457,8 @@ func (s *lightClientSuite) TestAfterUpdateState_Rollback() { 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 last block descriptor - s.Require().Equal(bds.BD[len(bds.BD)-1].Height, clientState.GetLatestHeight().GetRevisionHeight()) + // 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) 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/delayedack/keeper/finalize.go b/x/delayedack/keeper/finalize.go index d3b7dfdf9..06abc050c 100644 --- a/x/delayedack/keeper/finalize.go +++ b/x/delayedack/keeper/finalize.go @@ -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 } diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 96e62eb5b..5b3e33d2b 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -34,7 +34,8 @@ func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64 if rollappPacket.Type == commontypes.RollappPacket_ON_ACK || rollappPacket.Type == commontypes.RollappPacket_ON_TIMEOUT { // for sent packets, we restore the packet commitment // the packet will be handled over the new rollapp revision - commitment := channeltypes.CommitPacket(k.cdc, rollappPacket.Packet) + // 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) pendingAddr = transfer.Sender } else { diff --git a/x/lightclient/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index 4b12bc286..c953a7644 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -65,8 +65,10 @@ func (hook rollappHook) AfterUpdateState( return errorsmod.Wrap(err, "validate optimistic update") } } + // 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 if err := hook.k.PruneSignersBelow(ctx, rollappId, stateInfo.GetLatestHeight()); err != nil { return errorsmod.Wrap(err, "prune signers") } @@ -95,19 +97,7 @@ func (hook rollappHook) validateOptimisticUpdate( BlockDescriptor: expectBD, NextBlockSequencer: nextSequencer, } - signerAddr, err := hook.k.GetSigner(ctx, client, h) - if err != nil { - return gerrc.ErrInternal.Wrapf("got cons state but no signer addr: client: %s: h: %d", client, h) - } - signer, err := hook.k.SeqK.RealSequencer(ctx, signerAddr) - if err != nil { - return gerrc.ErrInternal.Wrapf("got cons state but no signer seq: client: %s: h: %d: signer addr: %s", client, h, signerAddr) - } - // remove to allow unbond - err = hook.k.RemoveSigner(ctx, signer.Address, client, h) - if err != nil { - return errorsmod.Wrap(err, "remove signer") - } + err = types.CheckCompatibility(*got, expect) if err != nil { return errors.Join(gerrc.ErrFault, err) diff --git a/x/lightclient/keeper/keeper.go b/x/lightclient/keeper/keeper.go index fdd3479b5..2a3b2338e 100644 --- a/x/lightclient/keeper/keeper.go +++ b/x/lightclient/keeper/keeper.go @@ -101,11 +101,7 @@ func (k Keeper) CanUnbond(ctx sdk.Context, seq sequencertypes.Sequencer) error { 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 -`) + return gerrc.ErrInternal } rng := collections.NewPrefixedPairRange[string, uint64](client).StartExclusive(h) diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index 045ddd141..5699775fe 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -50,16 +50,19 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraud k.freezeClient(cs, fraudHeight) } -// set latest IBC consensus state nextValHash to the current proposing sequencer. -func (k Keeper) ResolveHardFork(ctx sdk.Context, rollappID string) { - client, _ := k.GetCanonicalClient(ctx, rollappID) +// 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) - height := stateinfo.GetLatestHeight() - bd := stateinfo.GetLatestBlockDescriptor() + 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() @@ -73,9 +76,8 @@ func (k Keeper) ResolveHardFork(ctx sdk.Context, rollappID string) { } setConsensusState(clientStore, k.cdc, clienttypes.NewHeight(1, height), &cs) - _ = k.SaveSigner(ctx, proposer.Address, client, height) - k.setHardForkResolved(ctx, rollappID) + return nil } // freezeClient freezes the client by setting the frozen height to the current height @@ -85,6 +87,8 @@ func (k Keeper) freezeClient(clientStore sdk.KVStore, height uint64) { // freeze the client tmClientState.FrozenHeight = clienttypes.NewHeight(1, height) + tmClientState.LatestHeight = clienttypes.NewHeight(1, height) + setClientState(clientStore, k.cdc, tmClientState) } From 9cbc795b631058657dc3ffd70965a993ec515c6a Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 14:29:54 +0200 Subject: [PATCH 52/68] return err on HardFork hooks --- app/apptesting/test_suite.go | 4 +-- ibctesting/light_client_test.go | 25 ++++++++++++++++++- ibctesting/utils_test.go | 2 +- x/delayedack/keeper/fraud.go | 8 +++--- x/delayedack/keeper/fraud_test.go | 3 ++- x/dymns/keeper/hooks.go | 2 +- x/incentives/client/cli/query_test.go | 2 +- x/incentives/keeper/suite_test.go | 4 +-- x/lightclient/keeper/hook_listener.go | 7 ++++-- x/lightclient/keeper/keeper.go | 20 +++------------ x/lightclient/keeper/keeper_test.go | 4 +-- x/lightclient/keeper/rollback.go | 15 ++++++----- x/rollapp/keeper/hard_fork.go | 5 +++- x/rollapp/keeper/hard_fork_test.go | 1 + x/rollapp/keeper/keeper.go | 3 --- x/rollapp/keeper/msg_server.go | 4 +-- .../msg_server_mark_obsolete_rollapps_test.go | 1 + x/rollapp/keeper/rollapp_suite_test.go | 2 +- x/rollapp/module.go | 2 +- x/rollapp/types/hooks.go | 12 ++++++--- x/sequencer/keeper/fraud_test.go | 3 ++- x/sequencer/keeper/hook_listener.go | 6 +++-- 22 files changed, 82 insertions(+), 53 deletions(-) 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/ibctesting/light_client_test.go b/ibctesting/light_client_test.go index 4776a1984..2d703fe96 100644 --- a/ibctesting/light_client_test.go +++ b/ibctesting/light_client_test.go @@ -366,6 +366,10 @@ func (s *lightClientSuite) TestAfterUpdateState_Rollback() { s.coordinator.CreateChannels(s.path) bds := rollapptypes.BlockDescriptors{} + signerHeights := struct { + Name string + Heights []int64 + }{} for i := 0; i < 20; i++ { s.coordinator.CommitBlock(s.hubChain(), s.rollappChain()) @@ -374,7 +378,7 @@ func (s *lightClientSuite) TestAfterUpdateState_Rollback() { bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} bds.BD = append(bds.BD, bd) - if i%5 == 0 { + 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( @@ -384,6 +388,12 @@ func (s *lightClientSuite) TestAfterUpdateState_Rollback() { s.NoError(err) _, err = s.path.EndpointA.Chain.SendMsgs(msg) s.NoError(err) + + // save signers + signer, err := s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) + s.NoError(err) + signerHeights.Name = signer + signerHeights.Heights = append(signerHeights.Heights, header.Header.Height) } } @@ -416,6 +426,19 @@ func (s *lightClientSuite) TestAfterUpdateState_Rollback() { } } + // validate signers are removed + cnt := 0 + for _, height := range signerHeights.Heights { + _, 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.Heights), "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) diff --git a/ibctesting/utils_test.go b/ibctesting/utils_test.go index 6d31ae3ab..9037ca812 100644 --- a/ibctesting/utils_test.go +++ b/ibctesting/utils_test.go @@ -105,7 +105,7 @@ 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. diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 5b3e33d2b..b0b0ee0eb 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -1,6 +1,7 @@ package keeper import ( + errorsmod "cosmossdk.io/errors" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -13,7 +14,7 @@ import ( var _ rollapptypes.RollappHooks = &Keeper{} -func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) { +func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error { logger := ctx.Logger().With("module", "DelayedAckMiddleware") // Get all the pending packets from fork height inclusive @@ -48,8 +49,7 @@ func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64 // delete the packet err := k.DeleteRollappPacket(ctx, &rollappPacket) if err != nil { - logger.Error("failed to delete reverted packet", append(logContext, "error", err.Error())...) - continue + return errorsmod.Wrap(err, "delete rollapp packet") } // delete the pending packet @@ -59,6 +59,8 @@ func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64 } logger.Info("reverting IBC rollapp packets", "rollappID", rollappID, "numPackets", len(rollappPendingPackets)) + + return nil } // DeleteRollappPacket deletes a packet receipt from the store diff --git a/x/delayedack/keeper/fraud_test.go b/x/delayedack/keeper/fraud_test.go index 6ad6dcafb..2495f41b1 100644 --- a/x/delayedack/keeper/fraud_test.go +++ b/x/delayedack/keeper/fraud_test.go @@ -35,7 +35,8 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { suite.Require().Nil(err) // call fraud on the 4 packet - keeper.OnHardFork(ctx, rollappId, 4) + err = keeper.OnHardFork(ctx, rollappId, 4) + suite.Require().NoError(err) // expected result: // rollappId: diff --git a/x/dymns/keeper/hooks.go b/x/dymns/keeper/hooks.go index 91c53ebc5..1f23ef165 100644 --- a/x/dymns/keeper/hooks.go +++ b/x/dymns/keeper/hooks.go @@ -73,7 +73,7 @@ func (h rollappHooks) AfterStateFinalized(_ sdk.Context, _ string, _ *rollapptyp return nil } -func (h rollappHooks) OnHardFork(_ sdk.Context, _ string, _ uint64) {} +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/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/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index c953a7644..e18832f1b 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -50,7 +50,10 @@ func (hook rollappHook) AfterUpdateState( // first state after hardfork, should reset the client to active state if hook.k.IsHardForkingInProgress(ctx, rollappId) { - hook.k.ResolveHardFork(ctx, rollappId) + err := hook.k.ResolveHardFork(ctx, rollappId) + if err != nil { + return errorsmod.Wrap(err, "resolve hard fork") + } return nil } @@ -69,7 +72,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 - 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 2a3b2338e..826c0ff01 100644 --- a/x/lightclient/keeper/keeper.go +++ b/x/lightclient/keeper/keeper.go @@ -96,13 +96,9 @@ 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 -func (k Keeper) PruneSignersAbove(ctx sdk.Context, rollapp string, h uint64) error { - client, ok := k.GetCanonicalClient(ctx, rollapp) - if !ok { - return gerrc.ErrInternal - } +func (k Keeper) PruneSignersAbove(ctx sdk.Context, client string, h uint64) error { rng := collections.NewPrefixedPairRange[string, uint64](client).StartExclusive(h) seqs := make([]string, 0) @@ -125,17 +121,9 @@ func (k Keeper) PruneSignersAbove(ctx sdk.Context, rollapp string, h uint64) err return nil } -// 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 -`) - } +func (k Keeper) PruneSignersBelow(ctx sdk.Context, client string, h uint64) error { rng := collections.NewPrefixedPairRange[string, uint64](client).EndExclusive(h) seqs := make([]string, 0) 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 index 5699775fe..9bed120c2 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -1,8 +1,10 @@ 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" @@ -10,15 +12,14 @@ import ( ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ) -func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappId string, fraudHeight uint64) { - hook.k.RollbackCanonicalClient(ctx, rollappId, fraudHeight) +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappId string, fraudHeight uint64) error { + return hook.k.RollbackCanonicalClient(ctx, rollappId, fraudHeight) } -func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraudHeight uint64) { +func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraudHeight uint64) error { client, found := k.GetCanonicalClient(ctx, rollappId) if !found { - k.Logger(ctx).Error("Canonical client not found", "rollappId", rollappId) - return + return gerrc.ErrFailedPrecondition.Wrap("canonical client not found") } cs := k.ibcClientKeeper.ClientStore(ctx, client) @@ -39,7 +40,7 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraud // clean the optimistic updates valset err := k.PruneSignersAbove(ctx, client, fraudHeight-1) if err != nil { - k.Logger(ctx).Error("Failed to prune signers", "err", err) + return errorsmod.Wrap(err, "prune signers above") } // marks that hard fork is in progress @@ -48,6 +49,8 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraud // freeze the client // it will be released after the hardfork is resolved (on the next state update) k.freezeClient(cs, fraudHeight) + + return nil } // ResolveHardFork resolves the hard fork by resetting the client to the valid state diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index 3d11835ef..5af58c9f1 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -31,7 +31,10 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) k.SetRollapp(ctx, rollapp) // handle the sequencers, clean delayed packets, handle light client - k.hooks.OnHardFork(ctx, rollappID, lastValidHeight+1) + err = k.hooks.OnHardFork(ctx, rollappID, lastValidHeight+1) + if err != nil { + return errorsmod.Wrap(err, "hard fork callback") + } ctx.EventManager().EmitEvent( sdk.NewEvent( diff --git a/x/rollapp/keeper/hard_fork_test.go b/x/rollapp/keeper/hard_fork_test.go index 0ad8dce9a..44ec81b7f 100644 --- a/x/rollapp/keeper/hard_fork_test.go +++ b/x/rollapp/keeper/hard_fork_test.go @@ -37,6 +37,7 @@ func (suite *RollappTestSuite) TestHardFork() { 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)) diff --git a/x/rollapp/keeper/keeper.go b/x/rollapp/keeper/keeper.go index 0950c226f..03ed5a5e9 100644 --- a/x/rollapp/keeper/keeper.go +++ b/x/rollapp/keeper/keeper.go @@ -146,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/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_mark_obsolete_rollapps_test.go b/x/rollapp/keeper/msg_server_mark_obsolete_rollapps_test.go index 6e5668e37..2d1c9a81f 100644 --- a/x/rollapp/keeper/msg_server_mark_obsolete_rollapps_test.go +++ b/x/rollapp/keeper/msg_server_mark_obsolete_rollapps_test.go @@ -108,6 +108,7 @@ func (s *RollappTestSuite) TestMarkObsoleteRollapps() { for _, tc := range tests { s.Run(tc.name, func() { s.SetupTest() + s.App.RollappKeeper.SetHooks(nil) // disable hooks // prepare test data obsoleteVersions := uslice.ToKeySet(tc.obsoleteVersions) diff --git a/x/rollapp/keeper/rollapp_suite_test.go b/x/rollapp/keeper/rollapp_suite_test.go index b2422effa..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 diff --git a/x/rollapp/module.go b/x/rollapp/module.go index d686b75cb..5136d16ed 100644 --- a/x/rollapp/module.go +++ b/x/rollapp/module.go @@ -128,7 +128,7 @@ func (am AppModule) Name() string { // module-specific GRPC queries. func (am AppModule) RegisterServices(cfg module.Configurator) { types.RegisterProposalMsgServer(cfg.MsgServer(), am.keeper) - types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(*am.keeper)) + types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) } diff --git a/x/rollapp/types/hooks.go b/x/rollapp/types/hooks.go index 8f862967a..220c6f844 100644 --- a/x/rollapp/types/hooks.go +++ b/x/rollapp/types/hooks.go @@ -17,7 +17,7 @@ type RollappHooks interface { 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) + OnHardFork(ctx sdk.Context, rollappID string, height uint64) error } var _ RollappHooks = MultiRollappHooks{} @@ -60,10 +60,14 @@ func (h MultiRollappHooks) AfterStateFinalized(ctx sdk.Context, rollappID string return nil } -func (h MultiRollappHooks) OnHardFork(ctx sdk.Context, rollappID string, height uint64) { +func (h MultiRollappHooks) OnHardFork(ctx sdk.Context, rollappID string, height uint64) error { for i := range h { - h[i].OnHardFork(ctx, rollappID, height) + err := h[i].OnHardFork(ctx, rollappID, height) + if err != nil { + return err + } } + return nil } // RollappCreated implements RollappHooks. @@ -99,7 +103,7 @@ func (StubRollappCreatedHooks) BeforeUpdateState(sdk.Context, string, string, bo func (StubRollappCreatedHooks) AfterUpdateState(sdk.Context, string, *StateInfo) error { return nil } -func (StubRollappCreatedHooks) OnHardFork(sdk.Context, string, uint64) {} +func (StubRollappCreatedHooks) OnHardFork(sdk.Context, string, uint64) error { return nil } func (StubRollappCreatedHooks) AfterStateFinalized(sdk.Context, string, *StateInfo) error { return nil } diff --git a/x/sequencer/keeper/fraud_test.go b/x/sequencer/keeper/fraud_test.go index d109fd334..113427199 100644 --- a/x/sequencer/keeper/fraud_test.go +++ b/x/sequencer/keeper/fraud_test.go @@ -110,7 +110,8 @@ func (s *SequencerTestSuite) TestFraudFullFlowDuringRotation() { s.Require().True(s.k().IsSuccessor(s.Ctx, s.seq(bob))) // instead of submitting last, proposer does a fraud - s.k().RollappHooks().OnHardFork(s.Ctx, ra.RollappId, 0) + 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))) diff --git a/x/sequencer/keeper/hook_listener.go b/x/sequencer/keeper/hook_listener.go index 7c2cb2476..4dc208ddb 100644 --- a/x/sequencer/keeper/hook_listener.go +++ b/x/sequencer/keeper/hook_listener.go @@ -37,13 +37,15 @@ func (hook rollappHook) BeforeUpdateState(ctx sdk.Context, seqAddr, rollappId st // 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) { +func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappID string, _ uint64) error { err := hook.k.optOutAllSequencers(ctx, rollappID) if err != nil { - hook.k.Logger(ctx).Error("failed to opt out all sequencers", "error", err) + 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 } From 44b14e27f7e6d409dc14b8763a119a7b0ad10c97 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 14:30:29 +0200 Subject: [PATCH 53/68] not forking on state update with obsolete DRS --- x/rollapp/keeper/msg_server_update_state.go | 15 ++++----------- x/rollapp/keeper/msg_server_update_state_test.go | 8 +------- 2 files changed, 5 insertions(+), 18 deletions(-) diff --git a/x/rollapp/keeper/msg_server_update_state.go b/x/rollapp/keeper/msg_server_update_state.go index 00f38ebe8..198355997 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -2,11 +2,12 @@ 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" ) @@ -99,17 +100,9 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) // 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 - // Rollapp is using a obsolete DRS version, hard fork it if k.IsStateUpdateObsolete(ctx, stateInfo) { - err := k.HardForkToLatest(ctx, msg.RollappId) - if err != nil { - return nil, fmt.Errorf("hard fork due to obsolete version: %w", err) - } - k.Logger(ctx).With("rollapp_id", msg.RollappId, "drs_version", stateInfo.GetLatestBlockDescriptor().DrsVersion). - Info("rollapp tried to submit MsgUpdateState with an obsolete DRS version,forked") - - // we must return non-error if we want the changes to be saved - return &types.MsgUpdateStateResponse{}, nil + 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 diff --git a/x/rollapp/keeper/msg_server_update_state_test.go b/x/rollapp/keeper/msg_server_update_state_test.go index 3dda7fb18..c478408f1 100644 --- a/x/rollapp/keeper/msg_server_update_state_test.go +++ b/x/rollapp/keeper/msg_server_update_state_test.go @@ -125,13 +125,7 @@ func (s *RollappTestSuite) TestUpdateStateObsoleteRollapp() { // create a new update using the obsolete version _, err = s.PostStateUpdateWithDRSVersion(s.Ctx, raName, proposer, expectedNextHeight, uint64(3), obsoleteVersion) - s.Require().NoError(err) - - s.assertFraudHandled(raName, expectedNextHeight) - - // the rollapp state is not updated - actualLastHeight = s.GetRollappLastHeight(raName) - s.Require().Equal(expectedNextHeight-1, actualLastHeight) + s.Require().Error(err) } func (suite *RollappTestSuite) TestUpdateStateUnknownRollappId() { From 7e51835e18e2f8610d36f614e74604a97d14d205 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 14:37:24 +0200 Subject: [PATCH 54/68] linter --- ibctesting/delayed_ack_test.go | 3 ++- ibctesting/light_client_test.go | 17 +++++++---------- x/delayedack/keeper/invariants_test.go | 3 ++- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/ibctesting/delayed_ack_test.go b/ibctesting/delayed_ack_test.go index 51496543d..95e7d9969 100644 --- a/ibctesting/delayed_ack_test.go +++ b/ibctesting/delayed_ack_test.go @@ -308,7 +308,8 @@ func (s *delayedAckSuite) TestHardFork_HubToRollapp() { s.Require().NotEqual(balanceBefore.String(), balanceAfter.String()) // hard fork - s.hubApp().DelayedAckKeeper.OnHardFork(s.hubCtx(), s.rollappCtx().ChainID(), 5) + 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()) diff --git a/ibctesting/light_client_test.go b/ibctesting/light_client_test.go index 2d703fe96..1b129b3a1 100644 --- a/ibctesting/light_client_test.go +++ b/ibctesting/light_client_test.go @@ -366,10 +366,7 @@ func (s *lightClientSuite) TestAfterUpdateState_Rollback() { s.coordinator.CreateChannels(s.path) bds := rollapptypes.BlockDescriptors{} - signerHeights := struct { - Name string - Heights []int64 - }{} + signerHeights := []int64{} for i := 0; i < 20; i++ { s.coordinator.CommitBlock(s.hubChain(), s.rollappChain()) @@ -390,10 +387,9 @@ func (s *lightClientSuite) TestAfterUpdateState_Rollback() { s.NoError(err) // save signers - signer, err := s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) + _, err = s.hubApp().LightClientKeeper.GetSigner(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) s.NoError(err) - signerHeights.Name = signer - signerHeights.Heights = append(signerHeights.Heights, header.Header.Height) + signerHeights = append(signerHeights, header.Header.Height) } } @@ -403,7 +399,8 @@ func (s *lightClientSuite) TestAfterUpdateState_Rollback() { // Trigger rollback rollbackHeight := uint64(s.rollappChain().LastHeader.Header.Height) - 5 - s.hubApp().LightClientKeeper.RollbackCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, rollbackHeight) + 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) @@ -428,7 +425,7 @@ func (s *lightClientSuite) TestAfterUpdateState_Rollback() { // validate signers are removed cnt := 0 - for _, height := range signerHeights.Heights { + 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) @@ -437,7 +434,7 @@ func (s *lightClientSuite) TestAfterUpdateState_Rollback() { cnt++ } } - s.Require().Less(cnt, len(signerHeights.Heights), "Signers should be removed after rollback") + 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) diff --git a/x/delayedack/keeper/invariants_test.go b/x/delayedack/keeper/invariants_test.go index ba7c24afc..81f0cb129 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -78,7 +78,8 @@ func (suite *DelayedAckTestSuite) TestInvariants() { // test fraud for rollapp := range seqPerRollapp { - suite.App.DelayedAckKeeper.OnHardFork(suite.Ctx, rollapp, uint64(suite.Ctx.BlockHeight())) + err := suite.App.DelayedAckKeeper.OnHardFork(suite.Ctx, rollapp, uint64(suite.Ctx.BlockHeight())) + suite.Require().NoError(err) } // check invariant From 5f6c7f69d2e0070f463445720c90f8c77b1763f6 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 15:09:19 +0200 Subject: [PATCH 55/68] renamed fraudHeight --- x/delayedack/keeper/fraud.go | 4 ++-- x/lightclient/keeper/rollback.go | 12 ++++++------ x/rollapp/keeper/hard_fork.go | 19 ++++++++++--------- x/rollapp/types/hooks.go | 4 ++-- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index b0b0ee0eb..11ccba7ae 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -14,11 +14,11 @@ import ( var _ rollapptypes.RollappHooks = &Keeper{} -func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error { +func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, newRevisionHeight uint64) error { logger := ctx.Logger().With("module", "DelayedAckMiddleware") // Get all the pending packets from fork height inclusive - rollappPendingPackets := k.ListRollappPackets(ctx, types.PendingByRollappIDFromHeight(rollappID, fraudHeight)) + rollappPendingPackets := k.ListRollappPackets(ctx, types.PendingByRollappIDFromHeight(rollappID, newRevisionHeight)) // Iterate over all the pending packets and revert them for _, rollappPacket := range rollappPendingPackets { diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index 9bed120c2..ae1fc270a 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -12,11 +12,11 @@ import ( ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" ) -func (hook rollappHook) OnHardFork(ctx sdk.Context, rollappId string, fraudHeight uint64) error { - return hook.k.RollbackCanonicalClient(ctx, rollappId, fraudHeight) +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, fraudHeight uint64) error { +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") @@ -26,7 +26,7 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraud // iterate over all consensus states and metadata in the client store IterateConsensusStateDescending(cs, func(h exported.Height) bool { // iterate until we pass the fraud height - if h.GetRevisionHeight() < fraudHeight { + if h.GetRevisionHeight() < newRevisionHeight { return true } @@ -38,7 +38,7 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraud }) // clean the optimistic updates valset - err := k.PruneSignersAbove(ctx, client, fraudHeight-1) + err := k.PruneSignersAbove(ctx, client, newRevisionHeight-1) if err != nil { return errorsmod.Wrap(err, "prune signers above") } @@ -48,7 +48,7 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, fraud // freeze the client // it will be released after the hardfork is resolved (on the next state update) - k.freezeClient(cs, fraudHeight) + k.freezeClient(cs, newRevisionHeight) return nil } diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index 5af58c9f1..19f47b8a8 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -14,24 +14,25 @@ import ( ) // HardFork handles the fraud evidence submitted by the user. -func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) error { +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, fraudHeight) + 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 = lastValidHeight + 1 + rollapp.RevisionStartHeight = newRevisionHeight k.SetRollapp(ctx, rollapp) // handle the sequencers, clean delayed packets, handle light client - err = k.hooks.OnHardFork(ctx, rollappID, lastValidHeight+1) + err = k.hooks.OnHardFork(ctx, rollappID, newRevisionHeight) if err != nil { return errorsmod.Wrap(err, "hard fork callback") } @@ -40,7 +41,7 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) sdk.NewEvent( types.EventTypeFraud, sdk.NewAttribute(types.AttributeKeyRollappId, rollappID), - sdk.NewAttribute(types.AttributeKeyFraudHeight, fmt.Sprint(fraudHeight)), + sdk.NewAttribute(types.AttributeKeyFraudHeight, fmt.Sprint(newRevisionHeight)), ), ) @@ -49,10 +50,10 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, fraudHeight uint64) // 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, fraudHeight uint64) (uint64, error) { +func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, newRevisionHeight uint64) (uint64, error) { // find the affected state info index // use latest state info for future height - stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, fraudHeight) + stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, newRevisionHeight) if errorsmod.IsOf(err, gerrc.ErrNotFound) { s, ok := k.GetLatestStateInfo(ctx, rollappID) if !ok { @@ -65,13 +66,13 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, fraudHeig // check height is not finalized if stateInfo.Status == common.Status_FINALIZED { - return 0, errorsmod.Wrapf(types.ErrDisputeAlreadyFinalized, "state info for height %d is already finalized", fraudHeight) + return 0, errorsmod.Wrapf(types.ErrDisputeAlreadyFinalized, "state info for height %d is already finalized", newRevisionHeight) } // 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 - lastStateIdxToKeep, err := k.UpdateLastStateInfo(ctx, stateInfo, fraudHeight) + lastStateIdxToKeep, err := k.UpdateLastStateInfo(ctx, stateInfo, newRevisionHeight) if err != nil { return 0, errorsmod.Wrap(err, "update last state info") } diff --git a/x/rollapp/types/hooks.go b/x/rollapp/types/hooks.go index 220c6f844..8893b5fd3 100644 --- a/x/rollapp/types/hooks.go +++ b/x/rollapp/types/hooks.go @@ -60,9 +60,9 @@ func (h MultiRollappHooks) AfterStateFinalized(ctx sdk.Context, rollappID string return nil } -func (h MultiRollappHooks) OnHardFork(ctx sdk.Context, rollappID string, height uint64) error { +func (h MultiRollappHooks) OnHardFork(ctx sdk.Context, rollappID string, newRevisionHeight uint64) error { for i := range h { - err := h[i].OnHardFork(ctx, rollappID, height) + err := h[i].OnHardFork(ctx, rollappID, newRevisionHeight) if err != nil { return err } From 9a482ba033e990ff0d430590489898eb7bf039ee Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 15:16:11 +0200 Subject: [PATCH 56/68] add error to kickProposer flow --- x/rollapp/keeper/sequencer_hooks.go | 6 ++++-- x/sequencer/keeper/fraud.go | 5 ++++- x/sequencer/types/hooks.go | 13 +++++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/x/rollapp/keeper/sequencer_hooks.go b/x/rollapp/keeper/sequencer_hooks.go index 619a37588..149fac43c 100644 --- a/x/rollapp/keeper/sequencer_hooks.go +++ b/x/rollapp/keeper/sequencer_hooks.go @@ -1,6 +1,7 @@ package keeper import ( + errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" ) @@ -32,9 +33,10 @@ func (h SequencerHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, } } -func (h SequencerHooks) AfterKickProposer(ctx sdk.Context, kicked sequencertypes.Sequencer) { +func (h SequencerHooks) AfterKickProposer(ctx sdk.Context, kicked sequencertypes.Sequencer) error { err := h.Keeper.HardForkToLatest(ctx, kicked.RollappId) if err != nil { - h.Keeper.Logger(ctx).Error("hard fork after kick proposer", "error", err) + return errorsmod.Wrap(err, "hard fork to latest") } + return nil } diff --git a/x/sequencer/keeper/fraud.go b/x/sequencer/keeper/fraud.go index 2bf168197..3c8290c98 100644 --- a/x/sequencer/keeper/fraud.go +++ b/x/sequencer/keeper/fraud.go @@ -26,7 +26,10 @@ func (k Keeper) TryKickProposer(ctx sdk.Context, kicker types.Sequencer) error { k.SetSequencer(ctx, proposer) // This will call hard fork on the rollapp, which will also optOut all sequencers - k.hooks.AfterKickProposer(ctx, proposer) + 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 { diff --git a/x/sequencer/types/hooks.go b/x/sequencer/types/hooks.go index 7a139eb10..57e87b77e 100644 --- a/x/sequencer/types/hooks.go +++ b/x/sequencer/types/hooks.go @@ -4,7 +4,7 @@ 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) + AfterKickProposer(ctx sdk.Context, kicked Sequencer) error } var _ Hooks = NoOpHooks{} @@ -14,7 +14,8 @@ type NoOpHooks struct{} func (n NoOpHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, before, after Sequencer) { } -func (n NoOpHooks) AfterKickProposer(ctx sdk.Context, kicked Sequencer) { +func (n NoOpHooks) AfterKickProposer(ctx sdk.Context, kicked Sequencer) error { + return nil } var _ Hooks = MultiHooks{} @@ -31,8 +32,12 @@ func (m MultiHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, befo } } -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 } From c25d2bcbc2d0e90e807b64255dc4d7d5923719f9 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 17:26:46 +0200 Subject: [PATCH 57/68] fixed UT --- x/sequencer/keeper/msg_server_kick_proposer_test.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/x/sequencer/keeper/msg_server_kick_proposer_test.go b/x/sequencer/keeper/msg_server_kick_proposer_test.go index b753fdb00..0a904cbe3 100644 --- a/x/sequencer/keeper/msg_server_kick_proposer_test.go +++ b/x/sequencer/keeper/msg_server_kick_proposer_test.go @@ -7,13 +7,17 @@ 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) + _, err = s.msgServer.KickProposer(s.Ctx, m) utest.IsErr(s.Require(), err, gerrc.ErrFailedPrecondition) // bob creates a sequencer From 3a876f4af5927a588432d84091468a47a8ab2733 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 19:37:03 +0200 Subject: [PATCH 58/68] deleteBySender moved to DeletePacket --- x/delayedack/keeper/fraud.go | 7 ------- x/delayedack/keeper/rollapp_packet.go | 11 +++++++++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/x/delayedack/keeper/fraud.go b/x/delayedack/keeper/fraud.go index 11ccba7ae..45ded3ef1 100644 --- a/x/delayedack/keeper/fraud.go +++ b/x/delayedack/keeper/fraud.go @@ -30,20 +30,16 @@ func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, newRevisionHeight "sequence", rollappPacket.Packet.Sequence, } - pendingAddr := "" - transfer := rollappPacket.MustGetTransferPacketData() if rollappPacket.Type == commontypes.RollappPacket_ON_ACK || rollappPacket.Type == commontypes.RollappPacket_ON_TIMEOUT { // 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) - pendingAddr = transfer.Sender } else { // for incoming packets, we need to reset the packet receipt ibcPacket := rollappPacket.Packet k.deletePacketReceipt(ctx, ibcPacket.GetDestPort(), ibcPacket.GetDestChannel(), ibcPacket.GetSequence()) - pendingAddr = transfer.Receiver } // delete the packet @@ -52,9 +48,6 @@ func (k Keeper) OnHardFork(ctx sdk.Context, rollappID string, newRevisionHeight return errorsmod.Wrap(err, "delete rollapp packet") } - // delete the pending packet - k.MustDeletePendingPacketByAddress(ctx, pendingAddr, rollappPacket.RollappPacketKey()) - logger.Debug("reverted IBC rollapp packet", logContext...) } diff --git a/x/delayedack/keeper/rollapp_packet.go b/x/delayedack/keeper/rollapp_packet.go index 745d06ea2..6071229a4 100644 --- a/x/delayedack/keeper/rollapp_packet.go +++ b/x/delayedack/keeper/rollapp_packet.go @@ -251,6 +251,17 @@ func (k Keeper) DeleteRollappPacket(ctx sdk.Context, rollappPacket *commontypes. 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) From 5f69b7fe4b366fcd580f93fae271d46a32959192 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Sun, 10 Nov 2024 19:42:45 +0200 Subject: [PATCH 59/68] fixed surprise linter --- x/eibc/client/cli/authz.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/x/eibc/client/cli/authz.go b/x/eibc/client/cli/authz.go index 10c023a1a..6f4c285a5 100644 --- a/x/eibc/client/cli/authz.go +++ b/x/eibc/client/cli/authz.go @@ -107,10 +107,6 @@ Examples: if err != nil { return fmt.Errorf("failed to parse spend limit: %w", err) } - spendLimit, err := sdk.ParseCoinsNormalized(limit) - if err != nil { - return fmt.Errorf("failed to parse spend limit: %w", err) - } if !spendLimit.IsAllPositive() { return fmt.Errorf("spend-limit should be greater than zero") From 73636ee5ae8d01bc56f99c98dea535980cf7a0d7 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Mon, 11 Nov 2024 10:29:01 +0200 Subject: [PATCH 60/68] DRY pruneSigners code --- x/lightclient/keeper/keeper.go | 70 +++++++++++++++------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/x/lightclient/keeper/keeper.go b/x/lightclient/keeper/keeper.go index 826c0ff01..681d96b90 100644 --- a/x/lightclient/keeper/keeper.go +++ b/x/lightclient/keeper/keeper.go @@ -99,51 +99,13 @@ func (k Keeper) CanUnbond(ctx sdk.Context, seq sequencertypes.Sequencer) error { // PruneSignersAbove removes bookkeeping for all heights ABOVE h for given client // This should only be called after canonical client set func (k Keeper) PruneSignersAbove(ctx sdk.Context, client string, h uint64) error { - 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 + return k.pruneSigner(ctx, client, h, true) } // 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, client string, h uint64) error { - 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 + return k.pruneSigner(ctx, client, h, false) } // GetSigner returns the sequencer address who signed the header in the update @@ -203,3 +165,31 @@ func (k Keeper) setHardForkResolved(ctx sdk.Context, rollappID string) { func (k Keeper) IsHardForkingInProgress(ctx sdk.Context, rollappID string) bool { return ctx.KVStore(k.storeKey).Has(types.HardForkKey(rollappID)) } + +func (k Keeper) pruneSigner(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 +} From 93a59c8f5e340e33ed9e89ddbad64e876e356d11 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Tue, 12 Nov 2024 13:29:27 +0200 Subject: [PATCH 61/68] feat(sequencer): hardforking when rotating to sentinel (#1455) Co-authored-by: danwt <30197399+danwt@users.noreply.github.com> --- app/keepers/keepers.go | 10 +-- x/denommetadata/ibc_middleware.go | 1 + x/denommetadata/ibc_middleware_test.go | 6 ++ x/denommetadata/keeper/keeper.go | 4 +- x/denommetadata/keeper/rollback.go | 22 ++++++ x/denommetadata/types/expected_keepers.go | 1 + x/rollapp/keeper/registered_denoms.go | 5 ++ x/rollapp/keeper/sequencer_hooks.go | 22 +++--- x/sequencer/keeper/bond.go | 16 +---- x/sequencer/keeper/fraud.go | 42 ++++++----- x/sequencer/keeper/fraud_test.go | 14 ++-- x/sequencer/keeper/msg_server_create.go | 7 +- x/sequencer/keeper/msg_server_update.go | 8 ++- x/sequencer/keeper/proposer.go | 87 ++++++----------------- x/sequencer/keeper/rotation.go | 50 ++++++++++++- x/sequencer/keeper/rotation_test.go | 4 ++ x/sequencer/types/expected_keepers.go | 1 + x/sequencer/types/hooks.go | 13 ++-- 18 files changed, 186 insertions(+), 127 deletions(-) create mode 100644 x/denommetadata/keeper/rollback.go diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 33e9c4f0d..a3f5be78b 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -347,10 +347,6 @@ func (a *AppKeepers) InitKeepers( a.ScopedIBCKeeper, ) - a.DenomMetadataKeeper = denommetadatamodulekeeper.NewKeeper( - a.BankKeeper, - ) - a.RollappKeeper = rollappmodulekeeper.NewKeeper( appCodec, a.keys[rollappmoduletypes.StoreKey], @@ -400,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), @@ -630,6 +631,7 @@ func (a *AppKeepers) SetupHooks() { a.DymNSKeeper.GetRollAppHooks(), a.LightClientKeeper.RollappHooks(), a.IROKeeper, + a.DenomMetadataKeeper.RollappHooks(), )) } 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/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/sequencer_hooks.go b/x/rollapp/keeper/sequencer_hooks.go index 149fac43c..eb0ae22d3 100644 --- a/x/rollapp/keeper/sequencer_hooks.go +++ b/x/rollapp/keeper/sequencer_hooks.go @@ -12,27 +12,31 @@ type SequencerHooks struct { *Keeper } -func (h SequencerHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, before, after sequencertypes.Sequencer) { +// 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) - if !after.Sentinel() { - h.Keeper.ScheduleLivenessEvent(ctx, &ra) - } + h.Keeper.ScheduleLivenessEvent(ctx, &ra) h.Keeper.SetRollapp(ctx, ra) - // recover from halt // if the rollapp has a state info, set the next proposer to this sequencer - if before.Sentinel() && !after.Sentinel() { - sInfo, _ := h.Keeper.GetLatestStateInfo(ctx, rollapp) - sInfo.NextProposer = after.Address - h.Keeper.SetStateInfo(ctx, sInfo) + 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 { diff --git a/x/sequencer/keeper/bond.go b/x/sequencer/keeper/bond.go index e8731f757..640bf5b3d 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,14 @@ 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) } + k.SetSequencer(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 +56,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 3c8290c98..447f04f73 100644 --- a/x/sequencer/keeper/fraud.go +++ b/x/sequencer/keeper/fraud.go @@ -19,14 +19,18 @@ func (k Keeper) TryKickProposer(ctx sdk.Context, kicker types.Sequencer) error { if !k.Kickable(ctx, proposer) { return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "not kickable") } - // FIXME: slash remaining funds if any? - if err := k.unbond(ctx, &proposer); err != nil { - return errorsmod.Wrap(err, "unbond") + + // clear the proposer + k.SetProposer(ctx, ra, types.SentinelSeqAddr) + + err := k.TryUnbond(ctx, &proposer, proposer.TokensCoin()) + if err != nil { + return errorsmod.Wrap(err, "try unbond") } k.SetSequencer(ctx, proposer) // This will call hard fork on the rollapp, which will also optOut all sequencers - err := k.hooks.AfterKickProposer(ctx, proposer) + err = k.hooks.AfterKickProposer(ctx, proposer) if err != nil { return errorsmod.Wrap(err, "kick proposer callbacks") } @@ -37,6 +41,12 @@ func (k Keeper) TryKickProposer(ctx sdk.Context, kicker types.Sequencer) error { } 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.RecoverFromHalt(ctx, ra); err != nil { + return errorsmod.Wrap(err, "choose proposer") + } + if err := uevent.EmitTypedEvent(ctx, &types.EventKickedProposer{ Rollapp: ra, Kicker: kicker.Address, @@ -45,12 +55,6 @@ func (k Keeper) TryKickProposer(ctx sdk.Context, kicker types.Sequencer) error { return err } - // this will choose kicker as next proposer, since he is the only opted in and bonded - // sequencer remaining. - if err := k.UpdateProposerIfNeeded(ctx, ra); err != nil { - return errorsmod.Wrap(err, "choose proposer") - } - return nil } @@ -74,24 +78,24 @@ func (k Keeper) SlashLiveness(ctx sdk.Context, rollappID string) 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) - } - if err != nil { - return errorsmod.Wrap(err, "slash") + rewardMul = sdk.MustNewDecFromStr("0.5") // TODO: parameterise + addr = *rewardee } - err = k.unbond(ctx, &seq) + err = k.slash(ctx, &seq, seq.TokensCoin(), rewardMul, addr) if err != nil { - return errorsmod.Wrap(err, "unbond") + return errorsmod.Wrap(err, "slash") } k.SetSequencer(ctx, seq) diff --git a/x/sequencer/keeper/fraud_test.go b/x/sequencer/keeper/fraud_test.go index 113427199..62009bfde 100644 --- a/x/sequencer/keeper/fraud_test.go +++ b/x/sequencer/keeper/fraud_test.go @@ -31,22 +31,24 @@ 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) + 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) diff --git a/x/sequencer/keeper/msg_server_create.go b/x/sequencer/keeper/msg_server_create.go index 88cd766df..94628c05b 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.UpdateProposerIfNeeded(ctx, msg.RollappId); err != nil { - return nil, err + proposer := k.GetProposer(ctx, msg.RollappId) + if proposer.Sentinel() { + if err := k.RecoverFromHalt(ctx, msg.RollappId); err != nil { + return nil, err + } } ctx.EventManager().EmitEvent( diff --git a/x/sequencer/keeper/msg_server_update.go b/x/sequencer/keeper/msg_server_update.go index d01061d7a..7f00bf9a2 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.UpdateProposerIfNeeded(ctx, seq.RollappId); err != nil { - return nil, errorsmod.Wrap(err, "choose proposer") + proposer := k.GetProposer(ctx, seq.RollappId) + if proposer.Sentinel() { + if err := k.RecoverFromHalt(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 6528f15d4..c49ac82a1 100644 --- a/x/sequencer/keeper/proposer.go +++ b/x/sequencer/keeper/proposer.go @@ -37,84 +37,43 @@ func (k Keeper) RollappPotentialProposers(ctx sdk.Context, rollappId string) []t return append(seqs, k.SentinelSequencer(ctx)) } -// UpdateProposerIfNeeded 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) UpdateProposerIfNeeded(ctx sdk.Context, rollapp string) error { +// RecoverFromHalt will assign a new proposer to the rollapp. +// It will choose a new proposer from the list of potential proposers. +// The rollapp must +func (k Keeper) RecoverFromHalt(ctx sdk.Context, rollapp string) error { proposer := k.GetProposer(ctx, rollapp) - before := proposer // a valid proposer is already set so there's no need to do anything if !proposer.Sentinel() { - 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 nil -} - -// ChooseSuccessor will assign a successor. It won't replace an existing one. -// It will prioritize 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 + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "proposer is not sentinel") } + before := proposer seqs := k.RollappPotentialProposers(ctx, rollapp) successor, err := ProposerChoiceAlgo(seqs) 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") + } -// 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") + k.SetProposer(ctx, rollapp, successor.Address) + k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) // clear successor + + err = k.hooks.AfterRecoveryFromHalt(ctx, rollapp, before, successor) + if err != nil { + return errorsmod.Wrap(err, "recovery from halt callbacks") + } + if err := uevent.EmitTypedEvent(ctx, &types.EventProposerChange{ + Rollapp: rollapp, + Before: before.Address, + 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 05bd320e5..99880a244 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) @@ -84,7 +85,16 @@ func (k Keeper) OnProposerLastBlock(ctx sdk.Context, proposer types.Sequencer) e successor := k.GetSuccessor(ctx, rollapp) k.SetProposer(ctx, rollapp, successor.Address) - k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) + + k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) // clear successor + + // 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") + } + } ctx.EventManager().EmitEvent( sdk.NewEvent( @@ -95,3 +105,39 @@ func (k Keeper) OnProposerLastBlock(ctx sdk.Context, proposer types.Sequencer) e ) 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/types/expected_keepers.go b/x/sequencer/types/expected_keepers.go index 66b6a1bf5..cf304c8a2 100644 --- a/x/sequencer/types/expected_keepers.go +++ b/x/sequencer/types/expected_keepers.go @@ -13,6 +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 + 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 57e87b77e..fdc3f4cef 100644 --- a/x/sequencer/types/hooks.go +++ b/x/sequencer/types/hooks.go @@ -3,7 +3,7 @@ package types import sdk "github.com/cosmos/cosmos-sdk/types" type Hooks interface { - AfterChooseNewProposer(ctx sdk.Context, rollapp string, before, after Sequencer) + AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, before, after Sequencer) error AfterKickProposer(ctx sdk.Context, kicked Sequencer) error } @@ -11,7 +11,8 @@ 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, before, after Sequencer) error { + return nil } func (n NoOpHooks) AfterKickProposer(ctx sdk.Context, kicked Sequencer) error { @@ -26,10 +27,14 @@ 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, before, after Sequencer) error { for _, h := range m { - h.AfterChooseNewProposer(ctx, rollapp, before, after) + err := h.AfterRecoveryFromHalt(ctx, rollapp, before, after) + if err != nil { + return err + } } + return nil } func (m MultiHooks) AfterKickProposer(ctx sdk.Context, kicked Sequencer) error { From 14a5e8533d1a2f149e1a167e9594ffcb6b818098 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Tue, 12 Nov 2024 09:42:43 +0200 Subject: [PATCH 62/68] PR comments --- x/rollapp/keeper/fraud_proposal.go | 16 ++++------------ x/rollapp/keeper/hard_fork.go | 13 +++++++------ x/rollapp/keeper/msg_server_create_rollapp.go | 3 ++- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/x/rollapp/keeper/fraud_proposal.go b/x/rollapp/keeper/fraud_proposal.go index 5817c74fe..3d3fe7439 100644 --- a/x/rollapp/keeper/fraud_proposal.go +++ b/x/rollapp/keeper/fraud_proposal.go @@ -37,18 +37,6 @@ func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappF return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "rollapp is not past genesis bridge phase") } - // validate we have state infos committed - sinfo, found := k.GetLatestStateInfo(ctx, msg.RollappId) - if !found { - return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "no state info found") - } - - // check whether the fraud height is already finalized - sinfo, found = k.GetLatestFinalizedStateInfo(ctx, msg.RollappId) - if found && sinfo.GetLatestHeight() >= msg.FraudHeight { - return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "fraud height already finalized") - } - // punish the sequencer if needed if msg.PunishSequencerAddress != "" { err := k.sequencerKeeper.PunishSequencer(ctx, msg.PunishSequencerAddress, msg.MustRewardee()) @@ -57,6 +45,10 @@ func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappF } } + // 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 { return nil, errorsmod.Wrap(err, "hard fork") diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index 19f47b8a8..0a7eeacc4 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -72,10 +72,11 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, newRevisi // 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 - lastStateIdxToKeep, err := k.UpdateLastStateInfo(ctx, stateInfo, newRevisionHeight) + 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 @@ -114,10 +115,10 @@ func (k Keeper) RevertPendingStates(ctx sdk.Context, rollappID string, newRevisi } // UpdateLastStateInfo truncates the state info to the last valid block before the fraud height. -// It returns the index of the last state info to keep. -func (k Keeper) UpdateLastStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, fraudHeight uint64) (uint64, error) { +// 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 0, errorsmod.Wrapf(gerrc.ErrInternal, "state info start height is greater than fraud height") + return nil, errorsmod.Wrapf(gerrc.ErrInternal, "state info start height is greater than fraud height") } if stateInfo.StartHeight == fraudHeight { @@ -125,7 +126,7 @@ func (k Keeper) UpdateLastStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, var ok bool *stateInfo, ok = k.GetStateInfo(ctx, stateInfo.StateInfoIndex.RollappId, stateInfo.StateInfoIndex.Index-1) if !ok { - return 0, errorsmod.Wrapf(gerrc.ErrFailedPrecondition, "no state info found for rollapp: %s", stateInfo.StateInfoIndex.RollappId) + 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 @@ -139,7 +140,7 @@ func (k Keeper) UpdateLastStateInfo(ctx sdk.Context, stateInfo *types.StateInfo, // Update the state info in the keeper stateInfo.NextProposer = "" k.SetStateInfo(ctx, *stateInfo) - return stateInfo.StateInfoIndex.Index, nil + return stateInfo, nil } func (k Keeper) HardForkToLatest(ctx sdk.Context, rollappID string) error { diff --git a/x/rollapp/keeper/msg_server_create_rollapp.go b/x/rollapp/keeper/msg_server_create_rollapp.go index a7eb980da..423cf5408 100644 --- a/x/rollapp/keeper/msg_server_create_rollapp.go +++ b/x/rollapp/keeper/msg_server_create_rollapp.go @@ -18,7 +18,8 @@ func (k msgServer) CreateRollapp(goCtx context.Context, msg *types.MsgCreateRoll 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 + // 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()) } From 9f8b3ce17900d95c9d95468ce69ddb538957af90 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Tue, 12 Nov 2024 16:22:00 +0200 Subject: [PATCH 63/68] AfterRecoveryFromHalt hook cleanup --- x/rollapp/keeper/sequencer_hooks.go | 2 +- x/sequencer/keeper/bond.go | 1 - x/sequencer/keeper/msg_server_bond.go | 14 +++++--------- x/sequencer/keeper/proposer.go | 13 ++++--------- x/sequencer/keeper/rotation.go | 7 ++++--- x/sequencer/types/hooks.go | 8 ++++---- 6 files changed, 18 insertions(+), 27 deletions(-) diff --git a/x/rollapp/keeper/sequencer_hooks.go b/x/rollapp/keeper/sequencer_hooks.go index eb0ae22d3..e21a78582 100644 --- a/x/rollapp/keeper/sequencer_hooks.go +++ b/x/rollapp/keeper/sequencer_hooks.go @@ -14,7 +14,7 @@ type SequencerHooks struct { // 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 { +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 diff --git a/x/sequencer/keeper/bond.go b/x/sequencer/keeper/bond.go index 640bf5b3d..8c7c3b96d 100644 --- a/x/sequencer/keeper/bond.go +++ b/x/sequencer/keeper/bond.go @@ -42,7 +42,6 @@ func (k Keeper) TryUnbond(ctx sdk.Context, seq *types.Sequencer, amt sdk.Coin) e if seq.Tokens.IsZero() { k.unbond(ctx, seq) } - k.SetSequencer(ctx, *seq) return nil } diff --git a/x/sequencer/keeper/msg_server_bond.go b/x/sequencer/keeper/msg_server_bond.go index 936c3bfc3..ef6e31445 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,9 +60,6 @@ func (k msgServer) Unbond(goCtx context.Context, msg *types.MsgUnbond) (*types.M if err != nil { return nil, err } - defer func() { - k.SetSequencer(ctx, seq) - }() // ensures they will not get chosen as their own successor! if err := seq.SetOptedIn(ctx, false); err != nil { @@ -94,5 +88,7 @@ func (k msgServer) Unbond(goCtx context.Context, msg *types.MsgUnbond) (*types.M return nil, errorsmod.Wrap(err, "try unbond") } + k.SetSequencer(ctx, seq) + return &types.MsgUnbondResponse{}, nil } diff --git a/x/sequencer/keeper/proposer.go b/x/sequencer/keeper/proposer.go index c49ac82a1..b4e8482b9 100644 --- a/x/sequencer/keeper/proposer.go +++ b/x/sequencer/keeper/proposer.go @@ -39,35 +39,30 @@ func (k Keeper) RollappPotentialProposers(ctx sdk.Context, rollappId string) []t // RecoverFromHalt will assign a new proposer to the rollapp. // It will choose a new proposer from the list of potential proposers. -// The rollapp must +// The rollapp must be halted and with potential proposer available. func (k Keeper) RecoverFromHalt(ctx sdk.Context, rollapp string) error { proposer := k.GetProposer(ctx, rollapp) - // a valid proposer is already set so there's no need to do anything if !proposer.Sentinel() { return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "proposer is not sentinel") } - before := proposer - seqs := k.RollappPotentialProposers(ctx, rollapp) - successor, err := ProposerChoiceAlgo(seqs) + successor, err := ProposerChoiceAlgo(k.RollappPotentialProposers(ctx, rollapp)) if err != nil { return err } if successor.Sentinel() { return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "no valid proposer found") } - k.SetProposer(ctx, rollapp, successor.Address) - k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) // clear successor - err = k.hooks.AfterRecoveryFromHalt(ctx, rollapp, before, successor) + 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: before.Address, + Before: types.SentinelSeqAddr, After: successor.Address, }); err != nil { return err diff --git a/x/sequencer/keeper/rotation.go b/x/sequencer/keeper/rotation.go index 99880a244..6d5d44fd7 100644 --- a/x/sequencer/keeper/rotation.go +++ b/x/sequencer/keeper/rotation.go @@ -84,9 +84,6 @@ func (k Keeper) OnProposerLastBlock(ctx sdk.Context, proposer types.Sequencer) e rollapp := proposer.RollappId successor := k.GetSuccessor(ctx, rollapp) - k.SetProposer(ctx, rollapp, successor.Address) - - k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) // clear successor // if proposer is sentinel, prepare new revision for the rollapp if successor.Sentinel() { @@ -94,8 +91,12 @@ func (k Keeper) OnProposerLastBlock(ctx sdk.Context, proposer types.Sequencer) e if err != nil { return errorsmod.Wrap(err, "hard fork to latest") } + return nil } + k.SetProposer(ctx, rollapp, successor.Address) + k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) // clear successor + ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeProposerRotated, diff --git a/x/sequencer/types/hooks.go b/x/sequencer/types/hooks.go index fdc3f4cef..f4e616dda 100644 --- a/x/sequencer/types/hooks.go +++ b/x/sequencer/types/hooks.go @@ -3,7 +3,7 @@ package types import sdk "github.com/cosmos/cosmos-sdk/types" type Hooks interface { - AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, before, after Sequencer) error + AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, newProposer Sequencer) error AfterKickProposer(ctx sdk.Context, kicked Sequencer) error } @@ -11,7 +11,7 @@ var _ Hooks = NoOpHooks{} type NoOpHooks struct{} -func (n NoOpHooks) AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, before, after Sequencer) error { +func (n NoOpHooks) AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, newProposer Sequencer) error { return nil } @@ -27,9 +27,9 @@ func NewMultiHooks(hooks ...Hooks) MultiHooks { return MultiHooks(hooks) } -func (m MultiHooks) AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, before, after Sequencer) error { +func (m MultiHooks) AfterRecoveryFromHalt(ctx sdk.Context, rollapp string, newProposer Sequencer) error { for _, h := range m { - err := h.AfterRecoveryFromHalt(ctx, rollapp, before, after) + err := h.AfterRecoveryFromHalt(ctx, rollapp, newProposer) if err != nil { return err } From d0fb6c8e382c9b87144345e973b657cfa9a06892 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 13 Nov 2024 12:20:59 +0200 Subject: [PATCH 64/68] fixed missing setConsensusMetadata. fixed kicked proposer unbond --- x/lightclient/keeper/client_store.go | 19 +++++++++++++++++ x/lightclient/keeper/rollback.go | 4 +++- x/rollapp/keeper/fraud_proposal.go | 32 +++++++++++++++++++++------- x/sequencer/keeper/fraud.go | 8 +++---- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/x/lightclient/keeper/client_store.go b/x/lightclient/keeper/client_store.go index d3665004b..5e91401b8 100644 --- a/x/lightclient/keeper/client_store.go +++ b/x/lightclient/keeper/client_store.go @@ -35,6 +35,25 @@ func setConsensusState(clientStore sdk.KVStore, cdc codec.BinaryCodec, height ex 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) diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index ae1fc270a..588dbdd22 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -25,7 +25,7 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, newRe // iterate over all consensus states and metadata in the client store IterateConsensusStateDescending(cs, func(h exported.Height) bool { - // iterate until we pass the fraud height + // iterate until we pass the new revision height if h.GetRevisionHeight() < newRevisionHeight { return true } @@ -79,6 +79,8 @@ func (k Keeper) ResolveHardFork(ctx sdk.Context, rollappID string) error { } setConsensusState(clientStore, k.cdc, clienttypes.NewHeight(1, height), &cs) + setConsensusMetadata(ctx, clientStore, clienttypes.NewHeight(1, height)) + k.setHardForkResolved(ctx, rollappID) return nil } diff --git a/x/rollapp/keeper/fraud_proposal.go b/x/rollapp/keeper/fraud_proposal.go index 3d3fe7439..00187be7c 100644 --- a/x/rollapp/keeper/fraud_proposal.go +++ b/x/rollapp/keeper/fraud_proposal.go @@ -12,36 +12,50 @@ import ( // 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 { - return nil, errorsmod.Wrap(gerrc.ErrUnauthenticated, "only the gov module can submit fraud proposals") + 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 { - return nil, errorsmod.Wrap(gerrc.ErrInvalidArgument, "invalid msg") + err = errorsmod.Wrap(gerrc.ErrInvalidArgument, "invalid msg") + ctx.Logger().Error(err.Error()) + return nil, err } rollapp, found := k.GetRollapp(ctx, msg.RollappId) if !found { - return nil, errorsmod.Wrap(gerrc.ErrNotFound, "rollapp not 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 { - return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "revision number mismatch") + err := errorsmod.Wrap(gerrc.ErrFailedPrecondition, "revision number mismatch") + ctx.Logger().Error(err.Error()) + return nil, err } - // validate the rollapp is past it's genesis bridge phase + // validate the rollapp is past its genesis bridge phase if !rollapp.IsTransferEnabled() { - return nil, errorsmod.Wrap(gerrc.ErrFailedPrecondition, "rollapp is not past genesis bridge phase") + 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 { - return nil, errorsmod.Wrap(err, "jail sequencer") + err = errorsmod.Wrap(err, "jail sequencer") + ctx.Logger().Error(err.Error()) + return nil, err } } @@ -51,7 +65,9 @@ func (k Keeper) SubmitRollappFraud(goCtx context.Context, msg *types.MsgRollappF // will fail if state already finalized err := k.HardFork(ctx, msg.RollappId, msg.FraudHeight) if err != nil { - return nil, errorsmod.Wrap(err, "hard fork") + err = errorsmod.Wrap(err, "hard fork") + ctx.Logger().Error(err.Error()) + return nil, err } return &types.MsgRollappFraudProposalResponse{}, nil diff --git a/x/sequencer/keeper/fraud.go b/x/sequencer/keeper/fraud.go index 447f04f73..7d860f422 100644 --- a/x/sequencer/keeper/fraud.go +++ b/x/sequencer/keeper/fraud.go @@ -23,14 +23,12 @@ func (k Keeper) TryKickProposer(ctx sdk.Context, kicker types.Sequencer) error { // clear the proposer k.SetProposer(ctx, ra, types.SentinelSeqAddr) - err := k.TryUnbond(ctx, &proposer, proposer.TokensCoin()) - if err != nil { - return errorsmod.Wrap(err, "try unbond") - } + // 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) + err := k.hooks.AfterKickProposer(ctx, proposer) if err != nil { return errorsmod.Wrap(err, "kick proposer callbacks") } From 49188346269fefdc010a10ed7424d8ec5b0cad38 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 13 Nov 2024 13:16:43 +0200 Subject: [PATCH 65/68] fixed unbond store --- x/sequencer/keeper/msg_server_bond.go | 32 ++++++++++++++++----------- x/sequencer/keeper/rotation.go | 6 ++--- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/x/sequencer/keeper/msg_server_bond.go b/x/sequencer/keeper/msg_server_bond.go index ef6e31445..d718f14c4 100644 --- a/x/sequencer/keeper/msg_server_bond.go +++ b/x/sequencer/keeper/msg_server_bond.go @@ -61,33 +61,39 @@ func (k msgServer) Unbond(goCtx context.Context, msg *types.MsgUnbond) (*types.M return nil, err } + // 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/rotation.go b/x/sequencer/keeper/rotation.go index 6d5d44fd7..07fc3061f 100644 --- a/x/sequencer/keeper/rotation.go +++ b/x/sequencer/keeper/rotation.go @@ -84,6 +84,8 @@ func (k Keeper) OnProposerLastBlock(ctx sdk.Context, proposer types.Sequencer) e 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() { @@ -91,12 +93,8 @@ func (k Keeper) OnProposerLastBlock(ctx sdk.Context, proposer types.Sequencer) e if err != nil { return errorsmod.Wrap(err, "hard fork to latest") } - return nil } - k.SetProposer(ctx, rollapp, successor.Address) - k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) // clear successor - ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeProposerRotated, From b4547dddd971df97d78e4129ae8c3a7107a93b00 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 13 Nov 2024 16:34:10 +0200 Subject: [PATCH 66/68] func renames for clarity --- x/lightclient/keeper/keeper.go | 6 +++--- x/sequencer/keeper/fraud.go | 2 +- x/sequencer/keeper/msg_server_create.go | 2 +- x/sequencer/keeper/msg_server_update.go | 2 +- x/sequencer/keeper/proposer.go | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/x/lightclient/keeper/keeper.go b/x/lightclient/keeper/keeper.go index 681d96b90..f99780d20 100644 --- a/x/lightclient/keeper/keeper.go +++ b/x/lightclient/keeper/keeper.go @@ -99,13 +99,13 @@ func (k Keeper) CanUnbond(ctx sdk.Context, seq sequencertypes.Sequencer) error { // PruneSignersAbove removes bookkeeping for all heights ABOVE h for given client // This should only be called after canonical client set func (k Keeper) PruneSignersAbove(ctx sdk.Context, client string, h uint64) error { - return k.pruneSigner(ctx, client, h, true) + return k.pruneSigners(ctx, client, h, true) } // 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, client string, h uint64) error { - return k.pruneSigner(ctx, client, h, false) + return k.pruneSigners(ctx, client, h, false) } // GetSigner returns the sequencer address who signed the header in the update @@ -166,7 +166,7 @@ func (k Keeper) IsHardForkingInProgress(ctx sdk.Context, rollappID string) bool return ctx.KVStore(k.storeKey).Has(types.HardForkKey(rollappID)) } -func (k Keeper) pruneSigner(ctx sdk.Context, client string, h uint64, isAbove bool) error { +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) diff --git a/x/sequencer/keeper/fraud.go b/x/sequencer/keeper/fraud.go index 7d860f422..2cfd7d258 100644 --- a/x/sequencer/keeper/fraud.go +++ b/x/sequencer/keeper/fraud.go @@ -41,7 +41,7 @@ func (k Keeper) TryKickProposer(ctx sdk.Context, kicker types.Sequencer) error { // this will choose kicker as next proposer, since he is the only opted in and bonded // sequencer remaining. - if err := k.RecoverFromHalt(ctx, ra); err != nil { + if err := k.RecoverFromSentinel(ctx, ra); err != nil { return errorsmod.Wrap(err, "choose proposer") } diff --git a/x/sequencer/keeper/msg_server_create.go b/x/sequencer/keeper/msg_server_create.go index 94628c05b..b9a3c5ec6 100644 --- a/x/sequencer/keeper/msg_server_create.go +++ b/x/sequencer/keeper/msg_server_create.go @@ -108,7 +108,7 @@ func (k msgServer) CreateSequencer(goCtx context.Context, msg *types.MsgCreateSe proposer := k.GetProposer(ctx, msg.RollappId) if proposer.Sentinel() { - if err := k.RecoverFromHalt(ctx, msg.RollappId); err != nil { + if err := k.RecoverFromSentinel(ctx, msg.RollappId); err != nil { return nil, err } } diff --git a/x/sequencer/keeper/msg_server_update.go b/x/sequencer/keeper/msg_server_update.go index 7f00bf9a2..6c2cb2a5c 100644 --- a/x/sequencer/keeper/msg_server_update.go +++ b/x/sequencer/keeper/msg_server_update.go @@ -57,7 +57,7 @@ func (k msgServer) UpdateOptInStatus(goCtx context.Context, // maybe set as proposer if one is needed proposer := k.GetProposer(ctx, seq.RollappId) if proposer.Sentinel() { - if err := k.RecoverFromHalt(ctx, seq.RollappId); err != nil { + if err := k.RecoverFromSentinel(ctx, seq.RollappId); err != nil { return nil, err } } diff --git a/x/sequencer/keeper/proposer.go b/x/sequencer/keeper/proposer.go index b4e8482b9..d561fe0d9 100644 --- a/x/sequencer/keeper/proposer.go +++ b/x/sequencer/keeper/proposer.go @@ -37,10 +37,10 @@ func (k Keeper) RollappPotentialProposers(ctx sdk.Context, rollappId string) []t return append(seqs, k.SentinelSequencer(ctx)) } -// RecoverFromHalt will assign a new proposer to the rollapp. +// 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) RecoverFromHalt(ctx sdk.Context, rollapp string) error { +func (k Keeper) RecoverFromSentinel(ctx sdk.Context, rollapp string) error { proposer := k.GetProposer(ctx, rollapp) if !proposer.Sentinel() { From 7bad2d06ec60e27b041eef4108f1a804d2c421c3 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin Date: Wed, 13 Nov 2024 16:34:43 +0200 Subject: [PATCH 67/68] inc case of future height fork, allow finalized last state --- x/rollapp/keeper/hard_fork.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/x/rollapp/keeper/hard_fork.go b/x/rollapp/keeper/hard_fork.go index 0a7eeacc4..c15b4c644 100644 --- a/x/rollapp/keeper/hard_fork.go +++ b/x/rollapp/keeper/hard_fork.go @@ -52,23 +52,24 @@ func (k Keeper) HardFork(ctx sdk.Context, rollappID string, newRevisionHeight ui // 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 - // use latest state info for future height stateInfo, err := k.FindStateInfoByHeight(ctx, rollappID, newRevisionHeight) - if errorsmod.IsOf(err, gerrc.ErrNotFound) { + 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 if err != nil { + } else { return 0, err } - // check height is not finalized - if stateInfo.Status == common.Status_FINALIZED { - return 0, errorsmod.Wrapf(types.ErrDisputeAlreadyFinalized, "state info for height %d is already finalized", newRevisionHeight) - } - // 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 From 6b75606221d4a9616ee36000776b2bcf81f50cdb Mon Sep 17 00:00:00 2001 From: zale144 Date: Thu, 14 Nov 2024 14:20:05 +0100 Subject: [PATCH 68/68] feat(lightclient): export hard fork keys to genesis (#1470) --- .../dymension/lightclient/genesis.proto | 1 + x/lightclient/keeper/canonical_client.go | 5 +- x/lightclient/keeper/genesis.go | 6 + x/lightclient/keeper/genesis_test.go | 14 ++- x/lightclient/keeper/keeper.go | 22 +++- x/lightclient/keeper/rollback.go | 2 +- x/lightclient/types/genesis.go | 2 +- x/lightclient/types/genesis.pb.go | 105 ++++++++++++++---- x/lightclient/types/keys.go | 4 +- x/rollapp/client/cli/query_latest_height.go | 4 +- x/rollapp/types/fraud_proposal.pb.go | 2 +- x/rollapp/types/tx.pb.go | 2 +- 12 files changed, 128 insertions(+), 41 deletions(-) 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/x/lightclient/keeper/canonical_client.go b/x/lightclient/keeper/canonical_client.go index c5a0880ad..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,7 +78,7 @@ 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") 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/keeper.go b/x/lightclient/keeper/keeper.go index f99780d20..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 { @@ -142,9 +144,8 @@ 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") @@ -152,7 +153,7 @@ func (k Keeper) ExpectedClientState(goCtx context.Context, req *types.QueryExpec return &types.QueryExpectedClientStateResponse{ClientState: anyClient}, nil } -func (k Keeper) setHardForkInProgress(ctx sdk.Context, rollappID string) { +func (k Keeper) SetHardForkInProgress(ctx sdk.Context, rollappID string) { ctx.KVStore(k.storeKey).Set(types.HardForkKey(rollappID), []byte{0x01}) } @@ -166,6 +167,17 @@ 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 { diff --git a/x/lightclient/keeper/rollback.go b/x/lightclient/keeper/rollback.go index 588dbdd22..b5fbfae71 100644 --- a/x/lightclient/keeper/rollback.go +++ b/x/lightclient/keeper/rollback.go @@ -44,7 +44,7 @@ func (k Keeper) RollbackCanonicalClient(ctx sdk.Context, rollappId string, newRe } // marks that hard fork is in progress - k.setHardForkInProgress(ctx, rollappId) + k.SetHardForkInProgress(ctx, rollappId) // freeze the client // it will be released after the hardfork is resolved (on the next state update) 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 7cde722ff..fe49e6e16 100644 --- a/x/lightclient/types/keys.go +++ b/x/lightclient/types/keys.go @@ -13,7 +13,7 @@ const ( var ( RollappClientKey = []byte{0x01} canonicalClientKey = []byte{0x04} - hardForkKey = []byte{0x05} + HardForkPrefix = []byte{0x05} HeaderSignersPrefixKey = collections.NewPrefix("headerSigners/") ClientHeightToSigner = collections.NewPrefix("clientHeightToSigner/") ) @@ -31,7 +31,7 @@ func CanonicalClientKey(clientID string) []byte { } func HardForkKey(rollappID string) []byte { - key := hardForkKey + 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/types/fraud_proposal.pb.go b/x/rollapp/types/fraud_proposal.pb.go index 2a63ebe44..861064106 100644 --- a/x/rollapp/types/fraud_proposal.pb.go +++ b/x/rollapp/types/fraud_proposal.pb.go @@ -40,7 +40,7 @@ type MsgRollappFraudProposal struct { 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 sdk acc addr + // rewardAddr is bech32 for sdk acc addr Rewardee string `protobuf:"bytes,7,opt,name=rewardee,proto3" json:"rewardee,omitempty"` } diff --git a/x/rollapp/types/tx.pb.go b/x/rollapp/types/tx.pb.go index e00ef5606..0d578e088 100644 --- a/x/rollapp/types/tx.pb.go +++ b/x/rollapp/types/tx.pb.go @@ -306,7 +306,7 @@ 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 + // 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"` }