From d577982f5d915d6184449603ec7b0e1f2f34aad5 Mon Sep 17 00:00:00 2001 From: keruch <53012408+keruch@users.noreply.github.com> Date: Mon, 4 Nov 2024 20:15:31 +0300 Subject: [PATCH 01/13] feat(delayedack): added efficient query for pending packets by addr (#1385) --- app/apptesting/delayedack.go | 53 ++ app/apptesting/test_suite.go | 9 +- app/upgrades/v4/upgrade.go | 24 +- app/upgrades/v4/upgrade_test.go | 24 + ibctesting/bridging_fee_test.go | 2 +- ibctesting/delayed_ack_test.go | 4 +- ibctesting/eibc_test.go | 6 +- ibctesting/utils_test.go | 11 +- .../dymension/delayedack/events.proto | 25 - .../dymension/delayedack/query.proto | 13 +- x/common/types/rollapp_packet.go | 8 + x/delayedack/client/cli/query.go | 15 +- x/delayedack/genesis.go | 11 + x/delayedack/ibc_middleware.go | 9 + x/delayedack/keeper/finalize.go | 24 - x/delayedack/keeper/finalize_test.go | 8 +- x/delayedack/keeper/fraud_test.go | 32 +- x/delayedack/keeper/grpc_query.go | 25 +- x/delayedack/keeper/hooks_test.go | 3 +- x/delayedack/keeper/invariants_test.go | 57 +- x/delayedack/keeper/keeper.go | 21 +- 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/events.pb.go | 692 +----------------- x/delayedack/types/keys.go | 4 +- x/delayedack/types/query.pb.go | 281 +++---- x/delayedack/types/query.pb.gw.go | 72 +- 28 files changed, 595 insertions(+), 1096 deletions(-) create mode 100644 app/apptesting/delayedack.go diff --git a/app/apptesting/delayedack.go b/app/apptesting/delayedack.go new file mode 100644 index 000000000..943728a23 --- /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(0); 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..f541cb0ee 100644 --- a/app/apptesting/test_suite.go +++ b/app/apptesting/test_suite.go @@ -183,13 +183,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/upgrades/v4/upgrade.go b/app/upgrades/v4/upgrade.go index f2adaa0cf..ee94afefd 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) @@ -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..aa5dca060 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 @@ -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/ibctesting/bridging_fee_test.go b/ibctesting/bridging_fee_test.go index dcc031414..65cf64692 100644 --- a/ibctesting/bridging_fee_test.go +++ b/ibctesting/bridging_fee_test.go @@ -97,7 +97,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) diff --git a/ibctesting/delayed_ack_test.go b/ibctesting/delayed_ack_test.go index 1eb90a508..90116a539 100644 --- a/ibctesting/delayed_ack_test.go +++ b/ibctesting/delayed_ack_test.go @@ -174,7 +174,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()) @@ -230,7 +230,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..cd02d7caf 100644 --- a/ibctesting/eibc_test.go +++ b/ibctesting/eibc_test.go @@ -262,7 +262,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 +346,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 +509,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/utils_test.go b/ibctesting/utils_test.go index 484db77bb..b5efb0694 100644 --- a/ibctesting/utils_test.go +++ b/ibctesting/utils_test.go @@ -373,16 +373,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/x/common/types/rollapp_packet.go b/x/common/types/rollapp_packet.go index dbdfa94ba..832ccbe2e 100644 --- a/x/common/types/rollapp_packet.go +++ b/x/common/types/rollapp_packet.go @@ -91,6 +91,14 @@ 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 { diff --git a/x/delayedack/client/cli/query.go b/x/delayedack/client/cli/query.go index aac99e140..1451de912 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..58b8034c9 100644 --- a/x/delayedack/ibc_middleware.go +++ b/x/delayedack/ibc_middleware.go @@ -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.go b/x/delayedack/keeper/finalize.go index 3026f28d3..42629c4f2 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. @@ -152,26 +151,3 @@ func (k Keeper) VerifyHeightFinalized(ctx sdk.Context, rollappID string, height } 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..a2f134fbd 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 ae3555a28..dd844c0f4 100644 --- a/x/delayedack/keeper/fraud_test.go +++ b/x/delayedack/keeper/fraud_test.go @@ -2,8 +2,8 @@ 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" + "github.com/dymensionxyz/dymension/v3/app/apptesting" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" damodule "github.com/dymensionxyz/dymension/v3/x/delayedack" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" @@ -18,9 +18,9 @@ func (suite *DelayedAckTestSuite) TestHandleFraud() { ) rollappId := "testRollappId" - pkts := generatePackets(rollappId, 5) + pkts := apptesting.GenerateRollappPackets(suite.T(), rollappId, 5) rollappId2 := "testRollappId2" - pkts2 := generatePackets(rollappId2, 5) + pkts2 := apptesting.GenerateRollappPackets(suite.T(), rollappId2, 5) prefixPending1 := types.ByRollappIDByStatus(rollappId, commontypes.Status_PENDING) prefixPending2 := types.ByRollappIDByStatus(rollappId2, commontypes.Status_PENDING) prefixReverted := types.ByRollappIDByStatus(rollappId, commontypes.Status_REVERTED) @@ -59,9 +59,9 @@ func (suite *DelayedAckTestSuite) TestDeletionOfRevertedPackets() { ) rollappId := "testRollappId" - pkts := generatePackets(rollappId, 5) + pkts := apptesting.GenerateRollappPackets(suite.T(), rollappId, 5) rollappId2 := "testRollappId2" - pkts2 := generatePackets(rollappId2, 5) + pkts2 := apptesting.GenerateRollappPackets(suite.T(), rollappId2, 5) for _, pkt := range append(pkts, pkts2...) { keeper.SetRollappPacket(ctx, pkt) @@ -81,25 +81,3 @@ func (suite *DelayedAckTestSuite) TestDeletionOfRevertedPackets() { } // TODO: test refunds of pending packets - -/* ---------------------------------- utils --------------------------------- */ - -func generatePackets(rollappId string, num uint64) []commontypes.RollappPacket { - var packets []commontypes.RollappPacket - for i := uint64(0); 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 70d558627..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.GetPendingPacketsUntilLatestHeight(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 3b5c63abf..83a2de635 100644 --- a/x/delayedack/keeper/invariants_test.go +++ b/x/delayedack/keeper/invariants_test.go @@ -3,9 +3,8 @@ 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" + "github.com/dymensionxyz/dymension/v3/app/apptesting" commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" damodule "github.com/dymensionxyz/dymension/v3/x/delayedack" "github.com/dymensionxyz/dymension/v3/x/rollapp/types" @@ -53,11 +52,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++ } @@ -75,10 +76,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 { @@ -115,13 +119,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, }, @@ -134,13 +138,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_REVERTED, ProofHeight: 15, - Packet: suite.getNewTestPacket(2), + Packet: apptesting.GenerateTestPacket(suite.T(), 2), }, false, }, @@ -153,13 +157,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, }, @@ -172,13 +176,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, }, @@ -191,13 +195,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, }, @@ -210,13 +214,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, }, @@ -299,22 +303,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 2d656b630..d864e7eba 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" ) @@ -21,6 +24,12 @@ type Keeper struct { 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 @@ -41,9 +50,15 @@ func NewKeeper( ps = ps.WithKeyTable(types.ParamKeyTable()) } return &Keeper{ - cdc: cdc, - storeKey: storeKey, - paramstore: ps, + cdc: cdc, + storeKey: storeKey, + paramstore: ps, + 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, 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 385cc16f1..c0441a17a 100644 --- a/x/delayedack/keeper/rollapp_packet.go +++ b/x/delayedack/keeper/rollapp_packet.go @@ -1,6 +1,9 @@ package keeper import ( + "errors" + + "cosmossdk.io/collections" sdk "github.com/cosmos/cosmos-sdk/types" transfertypes "github.com/cosmos/ibc-go/v7/modules/apps/transfer/types" @@ -25,6 +28,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) @@ -54,23 +104,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, @@ -79,14 +133,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 } @@ -94,20 +155,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 e62354b8e..1fca74b66 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, }, @@ -169,27 +163,29 @@ func (suite *DelayedAckTestSuite) TestListRollappPackets() { suite.Require().Equal(totalLength, len(onRecvPackets)+len(onAckPackets)+len(onTimeoutPackets)) } -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 @@ -197,3 +193,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/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/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 ) From 53860295cce88229f16334e43dd1db3d35f2d4a7 Mon Sep 17 00:00:00 2001 From: zale144 Date: Mon, 4 Nov 2024 19:04:25 +0100 Subject: [PATCH 02/13] feat(rollapp): verify genesis checksum is same in hub and rollapp (#1384) --- ibctesting/utils_test.go | 2 +- x/rollapp/genesisbridge/ibc_module.go | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/ibctesting/utils_test.go b/ibctesting/utils_test.go index b5efb0694..191c3ed98 100644 --- a/ibctesting/utils_test.go +++ b/ibctesting/utils_test.go @@ -138,7 +138,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", 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) From 76aa1e103e0440d4a96bac27f09ae03a27acf3fc Mon Sep 17 00:00:00 2001 From: Daniel T <30197399+danwt@users.noreply.github.com> Date: Tue, 5 Nov 2024 11:37:44 +0000 Subject: [PATCH 03/13] feat(sequencer): conditional unbonding + kick for liveness (#1343) Co-authored-by: Omri --- .gitignore | 3 +- app/apptesting/test_suite.go | 1 - app/keepers/keepers.go | 7 +- app/upgrades/v4/upgrade.go | 4 +- app/upgrades/v4/upgrade_test.go | 12 +- go.mod | 5 +- go.sum | 4 +- ibctesting/light_client_test.go | 351 ------ ibctesting/utils_test.go | 1 + .../dymension/lightclient/genesis.proto | 20 +- .../dymension/rollapp/genesis.proto | 6 + .../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/lightclient.go | 79 +- testutil/keeper/sequencer.go | 2 + .../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 | 161 ++- .../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 | 151 ++- x/lightclient/keeper/hook_listener_test.go | 44 +- x/lightclient/keeper/keeper.go | 155 ++- x/lightclient/keeper/keeper_test.go | 74 ++ x/lightclient/types/errors.go | 1 - x/lightclient/types/expected_keepers.go | 8 +- 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 | 33 +- x/lightclient/types/params.go | 7 +- x/lightclient/types/state.go | 32 +- x/lightclient/types/state_test.go | 10 +- x/rollapp/genesis.go | 13 + x/rollapp/genesis_test.go | 24 + .../block_height_to_finalization_queue.go | 48 + ...block_height_to_finalization_queue_test.go | 33 + x/rollapp/keeper/expected_keepers.go | 3 +- x/rollapp/keeper/fraud_handler_test.go | 10 +- x/rollapp/keeper/hooks_listeners.go | 29 + x/rollapp/keeper/invariants.go | 2 +- x/rollapp/keeper/keeper.go | 14 +- x/rollapp/keeper/liveness.go | 60 +- x/rollapp/keeper/liveness_test.go | 34 +- .../keeper/msg_server_update_rollapp_test.go | 14 +- x/rollapp/keeper/msg_server_update_state.go | 11 +- .../keeper/msg_server_update_state_test.go | 8 +- x/rollapp/keeper/params.go | 6 - x/rollapp/types/errors.go | 2 +- x/rollapp/types/genesis.pb.go | 344 +++++- x/rollapp/types/genesis_test.go | 11 - 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 | 107 ++ x/sequencer/keeper/fraud_test.go | 129 ++ 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 | 45 +- x/sequencer/keeper/hooks_test.go | 65 -- 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 | 127 -- .../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 | 23 + .../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 | 45 - ...ncer_test.go => msg_server_update_test.go} | 80 +- .../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 | 132 +++ x/sequencer/keeper/proposer_test.go | 83 ++ x/sequencer/keeper/rotation.go | 158 +-- 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 | 92 -- 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/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 +- 163 files changed, 6521 insertions(+), 6137 deletions(-) delete mode 100644 ibctesting/light_client_test.go create mode 100644 x/lightclient/keeper/keeper_test.go create mode 100644 x/rollapp/keeper/hooks_listeners.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} (68%) 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/apptesting/test_suite.go b/app/apptesting/test_suite.go index f541cb0ee..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) diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 5d494e6c5..a81f212af 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -144,7 +144,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 @@ -363,7 +363,7 @@ func (a *AppKeepers) InitKeepers( nil, ) - a.SequencerKeeper = *sequencermodulekeeper.NewKeeper( + a.SequencerKeeper = sequencermodulekeeper.NewKeeper( appCodec, a.keys[sequencermoduletypes.StoreKey], a.BankKeeper, @@ -379,6 +379,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, diff --git a/app/upgrades/v4/upgrade.go b/app/upgrades/v4/upgrade.go index ee94afefd..7c8e186d2 100644 --- a/app/upgrades/v4/upgrade.go +++ b/app/upgrades/v4/upgrade.go @@ -168,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) diff --git a/app/upgrades/v4/upgrade_test.go b/app/upgrades/v4/upgrade_test.go index aa5dca060..34facd781 100644 --- a/app/upgrades/v4/upgrade_test.go +++ b/app/upgrades/v4/upgrade_test.go @@ -243,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 { @@ -256,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) @@ -269,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 diff --git a/go.mod b/go.mod index 3cec47b75..4a3088dc4 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,6 +237,7 @@ 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 @@ -245,6 +246,6 @@ replace ( // 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..96c9c29e5 100644 --- a/go.sum +++ b/go.sum @@ -508,8 +508,8 @@ github.com/dymensionxyz/osmosis/osmomath v0.0.6-dymension-v0.1.0.20240820121212- 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/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/light_client_test.go b/ibctesting/light_client_test.go deleted file mode 100644 index cc71a747e..000000000 --- a/ibctesting/light_client_test.go +++ /dev/null @@ -1,351 +0,0 @@ -package ibctesting_test - -import ( - "testing" - - errorsmod "cosmossdk.io/errors" - sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" - "github.com/cosmos/ibc-go/v7/testing/simapp" - - "github.com/dymensionxyz/dymension/v3/x/lightclient/types" - rollapptypes "github.com/dymensionxyz/dymension/v3/x/rollapp/types" - - ibctesting "github.com/cosmos/ibc-go/v7/testing" - 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, - MaxClockDrift: types.DefaultExpectedCanonicalClientParams().MaxClockDrift, -} - -type lightClientSuite struct { - utilSuite - path *ibctesting.Path -} - -func TestLightClientSuite(t *testing.T) { - suite.Run(t, new(lightClientSuite)) -} - -func (s *lightClientSuite) TestSetCanonicalClient_FailsTrustRequirements() { - s.createRollapp(false, nil) - s.registerSequencer() - // The default tm client does not match the trust requirements of a canonical client. - // So it should not be set as one. - s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) - s.coordinator.SetupClients(s.path) - - // Update rollapp state - this will trigger the check for prospective canonical client - currentRollappBlockHeight := uint64(s.rollappChain().App.LastBlockHeight()) - s.updateRollappState(currentRollappBlockHeight) - - _, found := s.hubApp().LightClientKeeper.GetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID) - s.False(found) -} - -func (s *lightClientSuite) TestSetCanonicalClient_FailsIncompatibleState() { - s.createRollapp(false, nil) - s.registerSequencer() - // create a custom tm client which matches the trust requirements of a canonical client - endpointA := ibctesting.NewEndpoint(s.hubChain(), &canonicalClientConfig, ibctesting.NewConnectionConfig(), ibctesting.NewChannelConfig()) - endpointB := ibctesting.NewEndpoint(s.rollappChain(), ibctesting.NewTendermintConfig(), ibctesting.NewConnectionConfig(), ibctesting.NewChannelConfig()) - endpointA.Counterparty = endpointB - endpointB.Counterparty = endpointA - s.path = &ibctesting.Path{EndpointA: endpointA, EndpointB: endpointB} - - // Creating the tm client - this will take us to the next block - s.coordinator.SetupClients(s.path) - - // Update the rollapp state - this will trigger the check for prospective canonical client - // The block descriptor root has dummy values and will not match the IBC roots for the same height - currentRollappBlockHeight := uint64(s.rollappChain().App.LastBlockHeight()) - s.updateRollappState(currentRollappBlockHeight) - - _, found := s.hubApp().LightClientKeeper.GetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID) - s.False(found) -} - -func (s *lightClientSuite) TestSetCanonicalClient_Succeeds() { - s.createRollapp(false, nil) - s.registerSequencer() - // create a custom tm client which matches the trust requirements of a canonical client - endpointA := ibctesting.NewEndpoint(s.hubChain(), &canonicalClientConfig, ibctesting.NewConnectionConfig(), ibctesting.NewChannelConfig()) - endpointB := ibctesting.NewEndpoint(s.rollappChain(), ibctesting.NewTendermintConfig(), ibctesting.NewConnectionConfig(), ibctesting.NewChannelConfig()) - endpointA.Counterparty = endpointB - endpointB.Counterparty = endpointA - s.path = &ibctesting.Path{EndpointA: endpointA, EndpointB: endpointB} - - currentHeader := s.rollappChain().CurrentHeader - startHeight := uint64(currentHeader.Height) - bd := rollapptypes.BlockDescriptor{Height: startHeight, StateRoot: currentHeader.AppHash, Timestamp: currentHeader.Time} - - // Creating the tm client - this will take us to the next block - s.NoError(s.path.EndpointA.CreateClient()) - - currentHeader = s.rollappChain().CurrentHeader - bdNext := rollapptypes.BlockDescriptor{Height: uint64(currentHeader.Height), StateRoot: currentHeader.AppHash, Timestamp: currentHeader.Time} - - // Update the rollapp state - this will trigger the check for prospective canonical client - msgUpdateState := rollapptypes.NewMsgUpdateState( - s.hubChain().SenderAccount.GetAddress().String(), - rollappChainID(), - "mock-da-path", - startHeight, - 2, - &rollapptypes.BlockDescriptors{BD: []rollapptypes.BlockDescriptor{bd, bdNext}}, - ) - _, err := s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) - s.Require().NoError(err) - - canonClientID, found := s.hubApp().LightClientKeeper.GetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID) - s.Require().True(found) - s.Equal(endpointA.ClientID, canonClientID) -} - -func (s *lightClientSuite) TestMsgUpdateClient_StateUpdateDoesntExist() { - s.createRollapp(false, nil) - s.registerSequencer() - currentRollappBlockHeight := uint64(s.rollappChain().App.LastBlockHeight()) - s.updateRollappState(currentRollappBlockHeight) - s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) - s.coordinator.SetupClients(s.path) - s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) - - for i := 0; i < 10; i++ { - s.hubChain().NextBlock() - s.rollappChain().NextBlock() - } - - s.NoError(s.path.EndpointA.UpdateClient()) - // As there was no stateinfo found for the height, should have accepted the update optimistically. - 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) - s.NoError(err) - s.Equal(s.hubChain().SenderAccount.GetAddress().String(), seqAddr) -} - -func (s *lightClientSuite) TestMsgUpdateClient_StateUpdateExists_Compatible() { - s.createRollapp(false, nil) - s.registerSequencer() - s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) - s.coordinator.SetupClients(s.path) - s.NoError(s.path.EndpointA.UpdateClient()) - s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) - - bds := rollapptypes.BlockDescriptors{} - for i := 0; i < 2; i++ { - lastHeader := s.rollappChain().LastHeader - bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} - bds.BD = append(bds.BD, bd) - s.hubChain().NextBlock() - s.rollappChain().NextBlock() - } - header, err := s.path.EndpointA.Chain.ConstructUpdateTMClientHeader(s.path.EndpointA.Counterparty.Chain, s.path.EndpointA.ClientID) - s.NoError(err) - - for i := 0; i < 2; i++ { - lastHeader := s.rollappChain().LastHeader - bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} - bds.BD = append(bds.BD, bd) - s.hubChain().NextBlock() - s.rollappChain().NextBlock() - } - msgUpdateState := rollapptypes.NewMsgUpdateState( - s.hubChain().SenderAccount.GetAddress().String(), - rollappChainID(), - "mock-da-path", - bds.BD[0].Height, uint64(len(bds.BD)), &bds, - ) - _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) - s.NoError(err) - - msg, err := clienttypes.NewMsgUpdateClient( - s.path.EndpointA.ClientID, header, - s.path.EndpointA.Chain.SenderAccount.GetAddress().String(), - ) - s.NoError(err) - - // As there was compatible stateinfo found, should accept the ClientUpdate without any error. - _, err = s.path.EndpointA.Chain.SendMsgs(msg) - s.NoError(err) - s.Equal(uint64(header.Header.Height), s.path.EndpointA.GetClientState().GetLatestHeight().GetRevisionHeight()) - // There shouldnt be any optimistic updates as the roots were verified - _, found := s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) - s.False(found) -} - -func (s *lightClientSuite) TestMsgUpdateClient_StateUpdateExists_NotCompatible() { - s.createRollapp(false, nil) - s.registerSequencer() - s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) - s.coordinator.SetupClients(s.path) - s.NoError(s.path.EndpointA.UpdateClient()) - s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) - - bds := rollapptypes.BlockDescriptors{} - for i := 0; i < 2; i++ { - lastHeader := s.rollappChain().LastHeader - bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} - bds.BD = append(bds.BD, bd) - s.hubChain().NextBlock() - s.rollappChain().NextBlock() - } - header, err := s.path.EndpointA.Chain.ConstructUpdateTMClientHeader(s.path.EndpointA.Counterparty.Chain, s.path.EndpointA.ClientID) - s.NoError(err) - - for i := 0; i < 2; i++ { - lastHeader := s.rollappChain().LastHeader - bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} - bd.Timestamp = bd.Timestamp.AddDate(0, 0, 1) // wrong timestamp to cause state mismatch - bds.BD = append(bds.BD, bd) - s.hubChain().NextBlock() - s.rollappChain().NextBlock() - } - msgUpdateState := rollapptypes.NewMsgUpdateState( - s.hubChain().SenderAccount.GetAddress().String(), - rollappChainID(), - "mock-da-path", - bds.BD[0].Height, uint64(len(bds.BD)), &bds, - ) - _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) - s.NoError(err) - - msg, err := clienttypes.NewMsgUpdateClient( - s.path.EndpointA.ClientID, header, - s.path.EndpointA.Chain.SenderAccount.GetAddress().String(), - ) - s.NoError(err) - - // As there was incompatible stateinfo found, should prevent light client update. - s.path.EndpointA.Chain.Coordinator.UpdateTimeForChain(s.path.EndpointA.Chain) - _, _, err = simapp.SignAndDeliver( // Explicitly submitting msg as we expect it to fail - s.path.EndpointA.Chain.T, - s.path.EndpointA.Chain.TxConfig, - s.path.EndpointA.Chain.App.GetBaseApp(), - s.path.EndpointA.Chain.GetContext().BlockHeader(), - []sdk.Msg{msg}, - s.path.EndpointA.Chain.ChainID, - []uint64{s.path.EndpointA.Chain.SenderAccount.GetAccountNumber()}, - []uint64{s.path.EndpointA.Chain.SenderAccount.GetSequence()}, - true, false, s.path.EndpointA.Chain.SenderPrivKey, - ) - s.Error(err) - s.True(errorsmod.IsOf(err, types.ErrTimestampMismatch)) -} - -func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_Compatible() { - s.createRollapp(false, nil) - s.registerSequencer() - s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) - s.coordinator.SetupClients(s.path) - s.NoError(s.path.EndpointA.UpdateClient()) - s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) - - bds := rollapptypes.BlockDescriptors{} - for i := 0; i < 2; i++ { - lastHeader := s.rollappChain().LastHeader - bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} - bds.BD = append(bds.BD, bd) - s.hubChain().NextBlock() - s.rollappChain().NextBlock() - } - header, err := s.path.EndpointA.Chain.ConstructUpdateTMClientHeader(s.path.EndpointA.Counterparty.Chain, s.path.EndpointA.ClientID) - s.NoError(err) - - for i := 0; i < 2; i++ { - lastHeader := s.rollappChain().LastHeader - bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} - bds.BD = append(bds.BD, bd) - s.hubChain().NextBlock() - s.rollappChain().NextBlock() - } - - msg, err := clienttypes.NewMsgUpdateClient( - s.path.EndpointA.ClientID, header, - s.path.EndpointA.Chain.SenderAccount.GetAddress().String(), - ) - s.NoError(err) - _, err = s.path.EndpointA.Chain.SendMsgs(msg) - s.NoError(err) - // There should be one optimistic update for the header height - _, found := s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) - s.True(found) - - msgUpdateState := rollapptypes.NewMsgUpdateState( - s.hubChain().SenderAccount.GetAddress().String(), - rollappChainID(), - "mock-da-path", - bds.BD[0].Height, uint64(len(bds.BD)), &bds, - ) - _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) - s.NoError(err) - // The optimistic update valhash should be removed as the state has been confirmed to be compatible - _, found = s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) - s.False(found) - // Ensuring that the stateinfo is now upto date as well - state, found := s.hubApp().RollappKeeper.GetLatestStateInfo(s.hubCtx(), s.rollappChain().ChainID) - s.True(found) - s.True(state.ContainsHeight(uint64(header.Header.Height))) -} - -func (s *lightClientSuite) TestAfterUpdateState_OptimisticUpdateExists_NotCompatible() { - s.createRollapp(false, nil) - s.registerSequencer() - s.path = s.newTransferPath(s.hubChain(), s.rollappChain()) - s.coordinator.SetupConnections(s.path) - s.hubApp().LightClientKeeper.SetCanonicalClient(s.hubCtx(), s.rollappChain().ChainID, s.path.EndpointA.ClientID) - s.coordinator.CreateChannels(s.path) - s.NoError(s.path.EndpointA.UpdateClient()) - - bds := rollapptypes.BlockDescriptors{} - for i := 0; i < 2; i++ { - lastHeader := s.rollappChain().LastHeader - bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} - bds.BD = append(bds.BD, bd) - s.hubChain().NextBlock() - s.rollappChain().NextBlock() - } - header, err := s.path.EndpointA.Chain.ConstructUpdateTMClientHeader(s.path.EndpointA.Counterparty.Chain, s.path.EndpointA.ClientID) - s.NoError(err) - - for i := 0; i < 2; i++ { - lastHeader := s.rollappChain().LastHeader - bd := rollapptypes.BlockDescriptor{Height: uint64(lastHeader.Header.Height), StateRoot: lastHeader.Header.AppHash, Timestamp: lastHeader.Header.Time} - bd.Timestamp = bd.Timestamp.AddDate(0, 0, 1) // wrong timestamp to cause state mismatch - bds.BD = append(bds.BD, bd) - s.hubChain().NextBlock() - s.rollappChain().NextBlock() - } - - msg, err := clienttypes.NewMsgUpdateClient( - s.path.EndpointA.ClientID, header, - s.path.EndpointA.Chain.SenderAccount.GetAddress().String(), - ) - s.NoError(err) - _, err = s.path.EndpointA.Chain.SendMsgs(msg) - s.NoError(err) - // There should be one optimistic update for the header height - _, found := s.hubApp().LightClientKeeper.GetConsensusStateValHash(s.hubCtx(), s.path.EndpointA.ClientID, uint64(header.Header.Height)) - s.True(found) - - msgUpdateState := rollapptypes.NewMsgUpdateState( - s.hubChain().SenderAccount.GetAddress().String(), - rollappChainID(), - "mock-da-path", - bds.BD[0].Height, uint64(len(bds.BD)), &bds, - ) - _, err = s.rollappMsgServer().UpdateState(s.hubCtx(), msgUpdateState) - s.Error(err) - // 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 - rollapp, _ := s.hubApp().RollappKeeper.GetRollapp(s.hubCtx(), s.rollappChain().ChainID) - s.True(rollapp.Frozen) -} diff --git a/ibctesting/utils_test.go b/ibctesting/utils_test.go index 191c3ed98..1ea8e1f77 100644 --- a/ibctesting/utils_test.go +++ b/ibctesting/utils_test.go @@ -111,6 +111,7 @@ func (s *utilSuite) rollappMsgServer() rollapptypes.MsgServer { func (s *utilSuite) SetupTest() { s.coordinator = ibctesting.NewCoordinator(s.T(), 2) // initializes test chains s.coordinator.Chains[rollappChainID()] = s.newTestChainWithSingleValidator(s.T(), s.coordinator, rollappChainID()) + s.hubApp().LightClientKeeper.SetEnabled(false) } func (s *utilSuite) fundSenderAccount() { diff --git a/proto/dymensionxyz/dymension/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 cab01cea4..6fa248afa 100644 --- a/proto/dymensionxyz/dymension/rollapp/genesis.proto +++ b/proto/dymensionxyz/dymension/rollapp/genesis.proto @@ -22,6 +22,12 @@ 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]; +} + +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/lightclient.go b/testutil/keeper/lightclient.go index a20a86126..157db71e0 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, @@ -133,32 +135,45 @@ func (m *MockIBCCLientKeeper) ConsensusStateHeights(c context.Context, req *ibcc } type MockSequencerKeeper struct { - sequencers map[string]sequencertypes.Sequencer -} - -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) UnbondingTime(ctx sdk.Context) (res time.Duration) { + return types.DefaultExpectedCanonicalClientParams().UnbondingPeriod +} + +func NewMockSequencerKeeper(sequencers map[string]*sequencertypes.Sequencer) *MockSequencerKeeper { + return &MockSequencerKeeper{ + sequencers: sequencers, + } +} + type MockRollappKeeper struct{} func NewMockRollappKeeper() *MockRollappKeeper { 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/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 f70d7481a..2451a1c7b 100644 --- a/x/lightclient/ante/ibc_msg_update_client.go +++ b/x/lightclient/ante/ibc_msg_update_client.go @@ -1,82 +1,153 @@ 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 + } + if errorsmod.IsOf(err, errNoHeader) { + // it doesn't concern us 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 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") + } + if err != nil { + return err + } + + // ~~~~~ + // 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") + } + + rollapp, ok := i.raK.GetRollapp(ctx, seq.RollappId) + if !ok { + return gerrc.ErrInternal.Wrapf("get rollapp from sequencer: rollapp: %s", seq.RollappId) + } + + // TODO: in hard fork will need to also use revision to make sure not from old revision + h := header.GetHeight().GetRevisionHeight() + stateInfos, err := i.getStateInfos(ctx, rollapp.RollappId, h) + if err != nil { + return errorsmod.Wrap(err, "get state infos") + } + + 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 } + 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 nil + return nil, errorsmod.Wrap(err, "unpack client message") } - _, ok = clientMessage.(*ibctm.Misbehaviour) + _, ok := clientMessage.(*ibctm.Misbehaviour) if ok { - return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "misbehavior evidence is disabled for canonical clients") + return nil, errIsMisbehaviour } header, ok := clientMessage.(*ibctm.Header) if !ok { - return nil + 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 +} +// 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 - height := uint64(header.Header.Height) - stateInfo, err := i.rollappKeeper.FindStateInfoByHeight(ctx, rollappID, height) - 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 + s0, err := i.raK.FindStateInfoByHeight(ctx, rollapp, h) + if errorsmod.IsOf(err, gerrc.ErrNotFound) { + return stateInfos{}, nil } - 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 + 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 + } } - sequencerPubKey, err := i.lightClientKeeper.GetSequencerPubKey(ctx, stateInfo.Sequencer) + return stateInfos{s0, s1}, nil +} + +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 err + return errorsmod.Wrap(errors.Join(err, gerrc.ErrInternal), "get sequencer of state info") } rollappState := types.RollappState{ BlockDescriptor: bd, - NextBlockSequencer: sequencerPubKey, + NextBlockSequencer: seq, } - // 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 - } - - return 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) + 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 0cbedef7f..3cd199545 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") @@ -106,9 +106,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 315419831..259b6f730 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,75 +35,114 @@ 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) } 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 { + if errorsmod.IsOf(err, gerrc.ErrFault) { + // TODO: should double check this flow when implementing hard fork + break + } + return errorsmod.Wrap(err, "validate optimistic") } } 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, + expectBD, err := hook.getBlockDescriptor(ctx, rollapp, cache, h) + if err != nil { + return err + } + expect := types.RollappState{ + BlockDescriptor: expectBD, + NextBlockSequencer: nextSequencer, } - err := types.CheckCompatibility(*tmConsensusState, rollappState) + signerAddr, err := hook.k.GetSigner(ctx, client, h) 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 - } - err = hook.k.rollappKeeper.HandleFraud(ctx, rollappId, canonicalClient, bd.GetHeight(), sequencerAddress) + 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 { + // everything is fine + return nil + } + // fraud! + err = hook.k.rollappKeeper.HandleFraud(ctx, signer.RollappId, client, h, signer.Address) + if err != nil { + return errorsmod.Wrap(err, "handle fraud") + } + return gerrc.ErrFault +} + +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 err + return rollapptypes.BlockDescriptor{}, errors.Join(err, gerrc.ErrInternal) } } - hook.k.RemoveConsensusStateValHash(ctx, canonicalClient, bd.GetHeight()) - return nil + 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 722ccb10a..d5a3cd879 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 8d8e704c4..9ce63ac39 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,94 @@ 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() + 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()) + }) } -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") +// PruneSigners removes bookkeeping for all heights ABOVE h for given rollapp +// This should only be called after canonical client set +// TODO: plug into hard fork +func (k Keeper) PruneSigners(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 seq.GetCometPubKey() -} + rng := collections.NewPrefixedPairRange[string, uint64](client).StartExclusive(h) -func (k Keeper) Logger(ctx sdk.Context) log.Logger { - return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) -} + seqs := make([]string, 0) + heights := make([]uint64, 0) -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 - } + // 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 "", types.ErrSequencerNotFound -} -// 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..eb1ebe77e --- /dev/null +++ b/x/lightclient/keeper/keeper_test.go @@ -0,0 +1,74 @@ +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().PruneSigners(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) +} diff --git a/x/lightclient/types/errors.go b/x/lightclient/types/errors.go index 309fb6e1f..f5d6fb055 100644 --- a/x/lightclient/types/errors.go +++ b/x/lightclient/types/errors.go @@ -9,5 +9,4 @@ 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") ) diff --git a/x/lightclient/types/expected_keepers.go b/x/lightclient/types/expected_keepers.go index 7acfd4090..a368071e5 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,15 +13,13 @@ 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) + SequencerByDymintAddr(ctx sdk.Context, addr cryptotypes.Address) (sequencertypes.Sequencer, error) + RealSequencer(ctx sdk.Context, addr string) (sequencertypes.Sequencer, error) } 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) SetRollapp(ctx sdk.Context, rollapp rollapptypes.Rollapp) HandleFraud(ctx sdk.Context, rollappID, clientId string, fraudHeight uint64, seqAddr string) error } 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 3ad12c0ad..4b64bd35c 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,14 +10,11 @@ const ( StoreKey = ModuleName ) -const ( - keySeparator = "/" -) - var ( - RollappClientKey = []byte{0x01} - ConsensusStateValhashKey = []byte{0x03} - canonicalClientKey = []byte{0x04} + RollappClientKey = []byte{0x01} + canonicalClientKey = []byte{0x04} + HeaderSignersPrefixKey = collections.NewPrefix("headerSigners/") + ClientHeightToSigner = collections.NewPrefix("clientHeightToSigner/") ) func GetRollappClientKey(rollappId string) []byte { @@ -30,24 +23,8 @@ 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 -} 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..6df044a2c 100644 --- a/x/rollapp/genesis.go +++ b/x/rollapp/genesis.go @@ -45,6 +45,13 @@ 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) } @@ -79,5 +86,11 @@ 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) + } + return genesis } diff --git a/x/rollapp/genesis_test.go b/x/rollapp/genesis_test.go index 18f9500dc..c7fa7feb7 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/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 c039c51d1..898b3580c 100644 --- a/x/rollapp/keeper/expected_keepers.go +++ b/x/rollapp/keeper/expected_keepers.go @@ -21,8 +21,7 @@ type ChannelKeeper interface { type SequencerKeeper interface { SlashLiveness(ctx sdk.Context, rollappID string) error - JailLiveness(ctx sdk.Context, rollappID string) error - GetProposer(ctx sdk.Context, rollappId string) (val types.Sequencer, found bool) + GetProposer(ctx sdk.Context, rollappId string) types.Sequencer } // BankKeeper defines the expected interface needed to retrieve account balances. diff --git a/x/rollapp/keeper/fraud_handler_test.go b/x/rollapp/keeper/fraud_handler_test.go index c73d1fbd2..82b7055a2 100644 --- a/x/rollapp/keeper/fraud_handler_test.go +++ b/x/rollapp/keeper/fraud_handler_test.go @@ -170,7 +170,7 @@ func (suite *RollappTestSuite) assertBeforeFraud(rollappId string, height uint64 suite.Require().False(rollapp.Frozen) // check sequencers - sequencers := suite.App.SequencerKeeper.GetSequencersByRollapp(suite.Ctx, rollappId) + sequencers := suite.App.SequencerKeeper.RollappSequencers(suite.Ctx, rollappId) for _, sequencer := range sequencers { suite.Require().Equal(types.Bonded, sequencer.Status) } @@ -202,14 +202,6 @@ func (suite *RollappTestSuite) assertFraudHandled(rollappId string) { 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) - // check states finalIdx, _ := suite.App.RollappKeeper.GetLatestFinalizedStateIndex(suite.Ctx, rollappId) start := finalIdx.Index + 1 diff --git a/x/rollapp/keeper/hooks_listeners.go b/x/rollapp/keeper/hooks_listeners.go new file mode 100644 index 000000000..89b757634 --- /dev/null +++ b/x/rollapp/keeper/hooks_listeners.go @@ -0,0 +1,29 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sequencertypes "github.com/dymensionxyz/dymension/v3/x/sequencer/types" +) + +var _ sequencertypes.Hooks = SequencerHooks{} + +type SequencerHooks struct { + *Keeper +} + +func (k SequencerHooks) AfterChooseNewProposer(ctx sdk.Context, rollapp string, before, after sequencertypes.Sequencer) { + // Start the liveness clock from zero + // NOTE: it could make more sense if liveness was a property of the sequencer rather than the rollapp + // TODO: tech debt https://github.com/dymensionxyz/dymension/issues/1357 + + ra := k.MustGetRollapp(ctx, rollapp) + k.ResetLivenessClock(ctx, &ra) + if !after.Sentinel() { + k.ScheduleLivenessEvent(ctx, &ra) + } + k.SetRollapp(ctx, ra) +} + +func (s SequencerHooks) AfterKickProposer(ctx sdk.Context, kicked sequencertypes.Sequencer) { + // TODO: trigger a hard fork +} diff --git a/x/rollapp/keeper/invariants.go b/x/rollapp/keeper/invariants.go index 98b63ed47..01071e518 100644 --- a/x/rollapp/keeper/invariants.go +++ b/x/rollapp/keeper/invariants.go @@ -269,7 +269,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..3cdd3956f 100644 --- a/x/rollapp/keeper/keeper.go +++ b/x/rollapp/keeper/keeper.go @@ -32,7 +32,8 @@ type Keeper struct { 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( @@ -56,6 +57,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, @@ -68,7 +72,7 @@ func NewKeeper( sequencerKeeper: sequencerKeeper, bankKeeper: bankKeeper, vulnerableDRSVersions: collections.NewKeySet( - collections.NewSchemaBuilder(collcompat.NewKVStoreService(storeKey)), + sb, collections.NewPrefix(types.VulnerableDRSVersionsKeyPrefix), "vulnerable_drs_versions", collections.Uint32Key, @@ -81,6 +85,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 96693362e..d199f6a98 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,13 +178,11 @@ func (suite *RollappTestSuite) TestLivenessFlow() { type livenessMockSequencerKeeper struct { slashes map[string]int - jails map[string]int } func newLivenessMockSequencerKeeper() livenessMockSequencerKeeper { return livenessMockSequencerKeeper{ make(map[string]int), - make(map[string]int), } } @@ -203,16 +191,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_update_rollapp_test.go b/x/rollapp/keeper/msg_server_update_rollapp_test.go index d1aadb652..b1a5b57d6 100644 --- a/x/rollapp/keeper/msg_server_update_rollapp_test.go +++ b/x/rollapp/keeper/msg_server_update_rollapp_test.go @@ -302,10 +302,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) @@ -321,8 +320,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 @@ -361,7 +359,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 0d6299ca6..4afa94d03 100644 --- a/x/rollapp/keeper/msg_server_update_state.go +++ b/x/rollapp/keeper/msg_server_update_state.go @@ -100,7 +100,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() @@ -121,7 +121,7 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) 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() @@ -140,9 +140,16 @@ func (k msgServer) UpdateState(goCtx context.Context, msg *types.MsgUpdateState) FinalizationQueue: newFinalizationQueue, }) + 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 65ef19c1e..994a08804 100644 --- a/x/rollapp/keeper/msg_server_update_state_test.go +++ b/x/rollapp/keeper/msg_server_update_state_test.go @@ -167,7 +167,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() { @@ -178,7 +178,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() { @@ -215,7 +215,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() { @@ -289,7 +289,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/types/errors.go b/x/rollapp/types/errors.go index c0a8851e7..1283fca93 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.pb.go b/x/rollapp/types/genesis.pb.go index 22a2a98f4..7a249b75b 100644 --- a/x/rollapp/types/genesis.pb.go +++ b/x/rollapp/types/genesis.pb.go @@ -32,9 +32,10 @@ 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"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -133,6 +134,65 @@ func (m *GenesisState) GetRegisteredDenoms() []RollappRegisteredDenoms { return nil } +func (m *GenesisState) GetSequencerHeightPairs() []SequencerHeightPair { + if m != nil { + return m.SequencerHeightPairs + } + 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 +202,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 +247,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 +256,42 @@ 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, + // 558 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0x4f, 0x6f, 0xd3, 0x30, + 0x18, 0xc6, 0x9b, 0x6d, 0xb4, 0xf4, 0x2d, 0x20, 0x64, 0x26, 0x88, 0xaa, 0x2d, 0x54, 0x45, 0x82, + 0x22, 0x58, 0x22, 0xad, 0x48, 0xdc, 0x90, 0x28, 0xe3, 0x4f, 0xc5, 0x04, 0x23, 0x03, 0x0e, 0x70, + 0x98, 0xd2, 0xc6, 0x4b, 0x2d, 0x12, 0x3b, 0xc4, 0x6e, 0xd5, 0xf6, 0x53, 0x70, 0xe0, 0x43, 0xed, + 0xb8, 0x23, 0x27, 0x84, 0xda, 0xcf, 0x81, 0x84, 0xea, 0x38, 0xa1, 0x6c, 0x6b, 0x5d, 0x89, 0x53, + 0x6b, 0xe7, 0x79, 0x7e, 0xcf, 0x63, 0xcb, 0x7a, 0xe1, 0xa1, 0x3f, 0x8a, 0x30, 0xe5, 0x84, 0xd1, + 0xe1, 0x68, 0xec, 0xe4, 0x0b, 0x27, 0x61, 0x61, 0xe8, 0xc5, 0xb1, 0x13, 0x60, 0x8a, 0x39, 0xe1, + 0x76, 0x9c, 0x30, 0xc1, 0x90, 0x35, 0xaf, 0xb6, 0xf3, 0x85, 0xad, 0xd4, 0xd5, 0xcd, 0x80, 0x05, + 0x4c, 0x4a, 0x9d, 0xd9, 0xbf, 0xd4, 0x55, 0x7d, 0xa0, 0xc9, 0x88, 0xbd, 0xc4, 0x8b, 0x54, 0x44, + 0x55, 0x57, 0x48, 0xfd, 0x2a, 0xb5, 0xa3, 0x51, 0x73, 0xe1, 0x09, 0x7c, 0x44, 0xe8, 0x71, 0xd6, + 0x65, 0x47, 0x63, 0x08, 0xc9, 0x60, 0x76, 0xe2, 0xac, 0x4d, 0x43, 0x23, 0xcf, 0x9b, 0xd4, 0x7f, + 0x97, 0xe0, 0xca, 0xcb, 0xf4, 0xb2, 0x0e, 0x67, 0xa1, 0x68, 0x0f, 0x8a, 0xe9, 0xc1, 0x4c, 0xa3, + 0x66, 0x34, 0x2a, 0xbb, 0x77, 0xed, 0xe5, 0x97, 0x67, 0x1f, 0x48, 0x75, 0x6b, 0xe3, 0xe4, 0xe7, + 0xed, 0x82, 0xab, 0xbc, 0xe8, 0x2d, 0x54, 0xd4, 0xf7, 0x7d, 0xc2, 0x85, 0xb9, 0x56, 0x5b, 0x6f, + 0x54, 0x76, 0xef, 0xe9, 0x50, 0x6e, 0xfa, 0xab, 0x58, 0xf3, 0x04, 0xf4, 0x01, 0xae, 0xca, 0x4b, + 0x69, 0xd3, 0x63, 0x26, 0x91, 0xeb, 0x12, 0x79, 0x5f, 0x87, 0x3c, 0xcc, 0x4c, 0x0a, 0xfa, 0x2f, + 0x05, 0xc5, 0x60, 0x86, 0x9e, 0xc0, 0x5c, 0xe4, 0xba, 0x36, 0xf5, 0xf1, 0x50, 0x26, 0x6c, 0xc8, + 0x04, 0x7b, 0xe5, 0x04, 0xe9, 0x54, 0x31, 0x0b, 0xa9, 0x68, 0x0c, 0xdb, 0xe9, 0xb7, 0x17, 0x84, + 0x7a, 0x21, 0x19, 0x63, 0x5f, 0x89, 0xb2, 0xd8, 0x4b, 0xff, 0x11, 0xbb, 0x1c, 0x8d, 0xbe, 0x1b, + 0x50, 0xef, 0x84, 0xac, 0xfb, 0xe5, 0x15, 0x26, 0x41, 0x4f, 0xbc, 0x67, 0x4a, 0xe8, 0x09, 0xc2, + 0xe8, 0xbb, 0x3e, 0xee, 0x63, 0xd9, 0xa0, 0x28, 0x1b, 0x3c, 0xd1, 0x35, 0x68, 0x2d, 0x25, 0xa9, + 0x46, 0x2b, 0xe4, 0xa1, 0xcf, 0x70, 0x2d, 0x7b, 0xbf, 0xcf, 0x07, 0x98, 0x0a, 0x6e, 0x96, 0x64, + 0x83, 0x1d, 0x5d, 0x83, 0xfd, 0x79, 0x97, 0x0a, 0x3c, 0x83, 0x42, 0xcf, 0xa0, 0x94, 0xbd, 0xc2, + 0xcb, 0x92, 0x7a, 0x47, 0x47, 0x7d, 0x9a, 0xbf, 0xc0, 0xcc, 0x89, 0x08, 0x5c, 0x4f, 0x70, 0x40, + 0xb8, 0xc0, 0x09, 0xf6, 0xf7, 0x30, 0x65, 0x11, 0x37, 0xcb, 0x92, 0xf6, 0x78, 0xc5, 0x37, 0xed, + 0x9e, 0xb1, 0xab, 0x84, 0x73, 0x58, 0x14, 0xc1, 0x26, 0xc7, 0x5f, 0xfb, 0x98, 0x76, 0x71, 0x92, + 0x5e, 0xdb, 0x81, 0x47, 0x12, 0x6e, 0x82, 0x8c, 0x6b, 0x6a, 0x9f, 0xc5, 0x79, 0xaf, 0x8a, 0xba, + 0x10, 0x5b, 0x7f, 0x0d, 0x37, 0x2e, 0xb0, 0xa0, 0x2d, 0x28, 0xe7, 0x72, 0x39, 0x08, 0xca, 0xee, + 0xdf, 0x0d, 0x74, 0x13, 0x8a, 0x3d, 0xa9, 0x35, 0xd7, 0x6a, 0x46, 0x63, 0xc3, 0x55, 0xab, 0xfa, + 0x47, 0xb8, 0xb5, 0xe0, 0xb8, 0x68, 0x1b, 0x40, 0x55, 0x3c, 0x22, 0x7e, 0x46, 0x54, 0x3b, 0x6d, + 0x1f, 0x6d, 0x41, 0xd1, 0x4f, 0xaf, 0x75, 0x36, 0x2a, 0xca, 0xd9, 0x34, 0x49, 0xf7, 0x5a, 0x6f, + 0x4e, 0x26, 0x96, 0x71, 0x3a, 0xb1, 0x8c, 0x5f, 0x13, 0xcb, 0xf8, 0x36, 0xb5, 0x0a, 0xa7, 0x53, + 0xab, 0xf0, 0x63, 0x6a, 0x15, 0x3e, 0x3d, 0x0a, 0x88, 0xe8, 0xf5, 0x3b, 0x76, 0x97, 0x45, 0x8b, + 0x66, 0xea, 0xa0, 0xe9, 0x0c, 0xf3, 0xc1, 0x27, 0x46, 0x31, 0xe6, 0x9d, 0xa2, 0x9c, 0x7d, 0xcd, + 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x71, 0xe2, 0x44, 0xa5, 0x46, 0x06, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -250,6 +314,20 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + 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 +453,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 +594,28 @@ 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)) + } + } + 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 +978,141 @@ 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 + 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..d2c228a64 100644 --- a/x/rollapp/types/genesis_test.go +++ b/x/rollapp/types/genesis_test.go @@ -108,17 +108,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{ 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 05a1ec20e..c9a7ccffa 100644 --- a/x/rollapp/types/rollapp.go +++ b/x/rollapp/types/rollapp.go @@ -49,10 +49,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..54982cef8 --- /dev/null +++ b/x/sequencer/keeper/fraud.go @@ -0,0 +1,107 @@ +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 { + if !kicker.IsPotentialProposer() { + return errorsmod.Wrap(gerrc.ErrFailedPrecondition, "not ready to propose") + } + + ra := kicker.RollappId + + proposer := k.GetProposer(ctx, ra) + + if k.Kickable(ctx, proposer) { + if err := k.unbond(ctx, &proposer); err != nil { + return errorsmod.Wrap(err, "unbond") + } + k.SetSequencer(ctx, proposer) + if err := k.optOutAllSequencers(ctx, ra, kicker.Address); err != nil { + return errorsmod.Wrap(err, "opt out all seqs") + } + k.hooks.AfterKickProposer(ctx, proposer) + + if err := uevent.EmitTypedEvent(ctx, &types.EventKickedProposer{ + Rollapp: ra, + Kicker: kicker.Address, + Proposer: proposer.Address, + }); err != nil { + return err + } + } + + // this will choose kicker as next proposer, since he is the only opted in and bonded + // sequencer remaining. + if err := k.ChooseProposer(ctx, ra); err != nil { + 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) HandleFraud(ctx sdk.Context, seq types.Sequencer, rewardee *sdk.AccAddress) error { + var err error + 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") + } + err = errorsmod.Wrap(k.unbond(ctx, &seq), "unbond") + k.SetSequencer(ctx, seq) + if err := k.optOutAllSequencers(ctx, seq.RollappId); err != nil { + return errorsmod.Wrap(err, "opt out all seqs") + } + return err +} + +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..53cfd521c --- /dev/null +++ b/x/sequencer/keeper/fraud_test.go @@ -0,0 +1,129 @@ +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().HandleFraud(s.Ctx, seq, 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()) + }) + s.Run("without rewardee", func() { + s.createSequencerWithBond(s.Ctx, ra.RollappId, bob, bond) + seq := s.seq(bob) + + s.k().SetProposer(s.Ctx, ra.RollappId, seq.Address) + err := s.k().HandleFraud(s.Ctx, seq, nil) + s.Require().NoError(err) + + seq = s.seq(bob) + mod := s.moduleBalance() + 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().HandleFraud(s.Ctx, seq, &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().False(rewardeeBalAfter.IsEqual(rewardeeBalBefore)) + }) +} + +// 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().HandleFraud(s.Ctx, s.seq(alice), nil) + s.Require().NoError(err) + 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 3df807374..5d2a8d35f 100644 --- a/x/sequencer/keeper/hook_listener.go +++ b/x/sequencer/keeper/hook_listener.go @@ -1,65 +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 nil -} - -// FraudSubmitted 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 { - 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 errorsmod.Wrap(hook.k.OnProposerLastBlock(ctx, proposer), "on proposer last block") } return nil diff --git a/x/sequencer/keeper/hooks_test.go b/x/sequencer/keeper/hooks_test.go deleted file mode 100644 index 50bc4918b..000000000 --- a/x/sequencer/keeper/hooks_test.go +++ /dev/null @@ -1,65 +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().FraudSubmitted(suite.Ctx, rollappId, 0, proposer) - 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++ { - 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..65900b0a6 --- /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.ChooseProposer(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 ba53cf9b9..000000000 --- a/x/sequencer/keeper/msg_server_create_sequencer.go +++ /dev/null @@ -1,127 +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 rollapp.Frozen { - return nil, types.ErrRollappFrozen - } - - 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) - } - - 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..3f49ea04d --- /dev/null +++ b/x/sequencer/keeper/msg_server_kick_proposer.go @@ -0,0 +1,23 @@ +package keeper + +import ( + "context" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/dymensionxyz/dymension/v3/x/sequencer/types" +) + +func (k msgServer) KickProposer(goCtx context.Context, msg *types.MsgKickProposer) (*types.MsgKickProposerResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + seq, err := k.RealSequencer(ctx, msg.GetCreator()) + if err != nil { + return nil, err + } + + if err := k.Keeper.TryKickProposer(ctx, seq); 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..fd447efa1 --- /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.ErrNotFound) + + // 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().NoError(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..3c1c02aec --- /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.ChooseProposer(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 9431bf9bf..000000000 --- a/x/sequencer/keeper/msg_server_update_sequencer.go +++ /dev/null @@ -1,45 +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 rollapp.Frozen { - return nil, types.ErrRollappFrozen - } - - 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 68% rename from x/sequencer/keeper/msg_server_update_sequencer_test.go rename to x/sequencer/keeper/msg_server_update_test.go index b369e6f86..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,36 +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 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{ - 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{ @@ -124,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, }) @@ -134,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, @@ -143,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..22e26d05c --- /dev/null +++ b/x/sequencer/keeper/proposer.go @@ -0,0 +1,132 @@ +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() + }) + return append(seqs, k.SentinelSequencer(ctx)) +} + +// ChooseProposer will assign a proposer to the rollapp. It won't replace the incumbent proposer +// if they are not sentinel. Otherwise it will prioritise a non sentinel successor. Finally, it +// choose one based on an algorithm. +// The result can be the sentinel sequencer. +func (k Keeper) ChooseProposer(ctx sdk.Context, rollapp string) error { + proposer := k.GetProposer(ctx, rollapp) + before := proposer + + if !proposer.Sentinel() { + if !proposer.Bonded() { + return gerrc.ErrInternal.Wrap("proposer is unbonded - invariant broken") + } + // a valid proposer is already set so there's no need to do anything + return nil + } + successor := k.GetSuccessor(ctx, rollapp) + k.SetProposer(ctx, rollapp, successor.Address) + k.SetSuccessor(ctx, rollapp, types.SentinelSeqAddr) + if k.GetProposer(ctx, rollapp).Sentinel() { + seqs := k.RollappPotentialProposers(ctx, rollapp) + proposer, err := ProposerChoiceAlgo(seqs) + if err != nil { + return err + } + k.SetProposer(ctx, rollapp, proposer.Address) + } + + after := k.GetProposer(ctx, rollapp) + if before.Address != after.Address { + k.hooks.AfterChooseNewProposer(ctx, rollapp, before, after) + + if err := uevent.EmitTypedEvent(ctx, &types.EventProposerChange{ + Rollapp: rollapp, + Before: before.Address, + After: after.Address, + }); err != nil { + return err + } + } + return 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..caff15214 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,86 @@ 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) + if err := k.ChooseProposer(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 3e2dc1206..000000000 --- a/x/sequencer/keeper/slashing.go +++ /dev/null @@ -1,92 +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 -} 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 b6df29000..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 { - return err - } - } - - 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/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 a6f9c558526aeea2391c7a4f91a26798ddc992ee Mon Sep 17 00:00:00 2001 From: keruch <53012408+keruch@users.noreply.github.com> Date: Tue, 5 Nov 2024 15:26:37 +0300 Subject: [PATCH 04/13] feat: rollapp royalties (#1368) Co-authored-by: Michael Tsitrin --- app/keepers/keepers.go | 11 ++++- go.mod | 2 +- go.sum | 4 +- ibctesting/bridging_fee_test.go | 4 +- testutil/keeper/dymns.go | 1 + testutil/keeper/iro.go | 4 +- testutil/keeper/rollapp.go | 2 +- utils/denom/ibc.go | 37 ++++++++++++++ utils/denom/ibc_test.go | 40 +++++++++++++++ x/bridgingfee/ibc_module.go | 26 ++++++++-- x/dymns/keeper/keeper_suite_test.go | 1 + 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 ++++++++++++++++ x/rollapp/keeper/expected_keepers.go | 7 +++ x/rollapp/keeper/keeper.go | 3 ++ x/rollapp/keeper/rollapp.go | 60 +++++++++++++++++++++++ 27 files changed, 353 insertions(+), 57 deletions(-) create mode 100644 utils/denom/ibc.go create mode 100644 utils/denom/ibc_test.go create mode 100644 x/iro/types/plan_test.go diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index a81f212af..984c0a897 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -311,7 +311,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 @@ -330,6 +331,7 @@ func (a *AppKeepers) InitKeepers( a.BankKeeper, a.PoolManagerKeeper, a.GAMMKeeper, + a.DistrKeeper, ) a.TxFeesKeeper = &txFeesKeeper @@ -359,10 +361,13 @@ func (a *AppKeepers) InitKeepers( a.IBCKeeper.ClientKeeper, nil, a.BankKeeper, + a.TransferKeeper, authtypes.NewModuleAddress(govtypes.ModuleName).String(), nil, ) + a.GAMMKeeper.SetRollapp(a.RollappKeeper) + a.SequencerKeeper = sequencermodulekeeper.NewKeeper( appCodec, a.keys[sequencermoduletypes.StoreKey], @@ -419,6 +424,7 @@ func (a *AppKeepers) InitKeepers( a.GAMMKeeper, a.IncentivesKeeper, a.PoolManagerKeeper, + a.TxFeesKeeper, ) a.SponsorshipKeeper = sponsorshipkeeper.NewKeeper( @@ -530,10 +536,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/go.mod b/go.mod index 4a3088dc4..cf523f3ec 100644 --- a/go.mod +++ b/go.mod @@ -242,7 +242,7 @@ replace ( 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 diff --git a/go.sum b/go.sum index 96c9c29e5..e7d34c04f 100644 --- a/go.sum +++ b/go.sum @@ -506,8 +506,8 @@ 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/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= diff --git a/ibctesting/bridging_fee_test.go b/ibctesting/bridging_fee_test.go index 65cf64692..a149c02c7 100644 --- a/ibctesting/bridging_fee_test.go +++ b/ibctesting/bridging_fee_test.go @@ -105,8 +105,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/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/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/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/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/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/rollapp/keeper/expected_keepers.go b/x/rollapp/keeper/expected_keepers.go index 898b3580c..10f00d5b7 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" ) @@ -33,3 +36,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/keeper.go b/x/rollapp/keeper/keeper.go index 3cdd3956f..e4e1663b1 100644 --- a/x/rollapp/keeper/keeper.go +++ b/x/rollapp/keeper/keeper.go @@ -28,6 +28,7 @@ type Keeper struct { channelKeeper ChannelKeeper sequencerKeeper SequencerKeeper bankKeeper BankKeeper + transferKeeper TransferKeeper vulnerableDRSVersions collections.KeySet[uint32] registeredRollappDenoms collections.KeySet[collections.Pair[string, string]] @@ -45,6 +46,7 @@ func NewKeeper( ibcclientKeeper IBCClientKeeper, sequencerKeeper SequencerKeeper, bankKeeper BankKeeper, + transferKeeper TransferKeeper, authority string, canonicalClientKeeper CanonicalLightClientKeeper, ) *Keeper { @@ -71,6 +73,7 @@ func NewKeeper( ibcClientKeeper: ibcclientKeeper, sequencerKeeper: sequencerKeeper, bankKeeper: bankKeeper, + transferKeeper: transferKeeper, vulnerableDRSVersions: collections.NewKeySet( sb, collections.NewPrefix(types.VulnerableDRSVersionsKeyPrefix), diff --git a/x/rollapp/keeper/rollapp.go b/x/rollapp/keeper/rollapp.go index 0a01cb025..588f9473f 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" ) @@ -219,6 +222,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 { From 870510fc68b7a102288a72a718a4bd7ac7e354de Mon Sep 17 00:00:00 2001 From: Daniel T <30197399+danwt@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:05:34 +0000 Subject: [PATCH 05/13] fix(lightclient): make sure to prune signers when setting canonical client for first time (#1399) --- x/lightclient/keeper/hook_listener.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x/lightclient/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index 259b6f730..438f3a7a8 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -45,6 +45,8 @@ func (hook rollappHook) AfterUpdateState( if ok { hook.k.SetCanonicalClient(ctx, rollappId, client) } + } + if !ok { return nil } From d081ce7aab3f2c58ab28f3427e7a634789eac3d7 Mon Sep 17 00:00:00 2001 From: Sergi Rene Date: Tue, 5 Nov 2024 15:06:26 +0100 Subject: [PATCH 06/13] fix(rollapp): return not found error when state info not found --- x/rollapp/keeper/grpc_query_state_info.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x/rollapp/keeper/grpc_query_state_info.go b/x/rollapp/keeper/grpc_query_state_info.go index b0d228e60..b37a05a0d 100644 --- a/x/rollapp/keeper/grpc_query_state_info.go +++ b/x/rollapp/keeper/grpc_query_state_info.go @@ -70,7 +70,7 @@ func (k Keeper) FindStateInfoByHeight(ctx sdk.Context, rollappId string, height stateInfoIndex, found := k.GetLatestStateInfoIndex(ctx, rollappId) if !found { - return nil, errorsmod.Wrapf(types.ErrNotFound, + return nil, errorsmod.Wrapf(gerrc.ErrNotFound, "LatestStateInfoIndex wasn't found for rollappId=%s", rollappId) } @@ -92,5 +92,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) } From 7850af9dc38cd05886c554497e91a016ecda18cc Mon Sep 17 00:00:00 2001 From: Itzhak Bokris Date: Tue, 5 Nov 2024 16:57:24 +0200 Subject: [PATCH 07/13] Register eibc and delayedack message in amino codec (#1401) Co-authored-by: Michael Tsitrin --- x/delayedack/ibc_middleware.go | 2 +- x/delayedack/keeper/keeper.go | 9 ++++++-- x/delayedack/types/codec.go | 21 ++++++++++++++----- x/delayedack/types/msgs.go | 38 ++++++++++++++++++++++++++++++++++ x/eibc/types/codec.go | 16 +++++++++++--- x/eibc/types/tx.go | 5 +++++ 6 files changed, 80 insertions(+), 11 deletions(-) diff --git a/x/delayedack/ibc_middleware.go b/x/delayedack/ibc_middleware.go index 58b8034c9..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) } diff --git a/x/delayedack/keeper/keeper.go b/x/delayedack/keeper/keeper.go index d864e7eba..3439f4088 100644 --- a/x/delayedack/keeper/keeper.go +++ b/x/delayedack/keeper/keeper.go @@ -19,7 +19,7 @@ import ( ) type Keeper struct { - cdc codec.BinaryCodec + cdc codec.Codec storeKey storetypes.StoreKey hooks types.MultiDelayedAckHooks paramstore paramtypes.Subspace @@ -37,7 +37,7 @@ type Keeper struct { } func NewKeeper( - cdc codec.BinaryCodec, + cdc codec.Codec, storeKey storetypes.StoreKey, ps paramtypes.Subspace, rollappKeeper types.RollappKeeper, @@ -70,6 +70,11 @@ 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) 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/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/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 { From 9cd39de6eb3dca7d9ff78c742d6ba1fda95a81fb Mon Sep 17 00:00:00 2001 From: Daniel T <30197399+danwt@users.noreply.github.com> Date: Tue, 5 Nov 2024 20:48:45 +0000 Subject: [PATCH 08/13] fix(lightclient): prune signers below on setting canonical (#1398) --- x/lightclient/keeper/hook_listener.go | 5 ++++ x/lightclient/keeper/keeper.go | 37 +++++++++++++++++++++-- x/lightclient/keeper/keeper_test.go | 43 ++++++++++++++++++++++++++- 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/x/lightclient/keeper/hook_listener.go b/x/lightclient/keeper/hook_listener.go index 438f3a7a8..1c6dba426 100644 --- a/x/lightclient/keeper/hook_listener.go +++ b/x/lightclient/keeper/hook_listener.go @@ -44,6 +44,11 @@ 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") + } } } if !ok { diff --git a/x/lightclient/keeper/keeper.go b/x/lightclient/keeper/keeper.go index 9ce63ac39..4b1eea520 100644 --- a/x/lightclient/keeper/keeper.go +++ b/x/lightclient/keeper/keeper.go @@ -96,10 +96,10 @@ func (k Keeper) CanUnbond(ctx sdk.Context, seq sequencertypes.Sequencer) error { }) } -// PruneSigners removes bookkeeping for all heights ABOVE h for given rollapp +// PruneSignersAbove removes bookkeeping for all heights ABOVE h for given rollapp // This should only be called after canonical client set // TODO: plug into hard fork -func (k Keeper) PruneSigners(ctx sdk.Context, rollapp string, h uint64) 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(` @@ -130,6 +130,39 @@ shouldnt be allowed 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") + } + + 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 +} + // 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)) diff --git a/x/lightclient/keeper/keeper_test.go b/x/lightclient/keeper/keeper_test.go index eb1ebe77e..ea5c59758 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().PruneSigners(s.Ctx, seq.RollappId, 6) + err = s.k().PruneSignersAbove(s.Ctx, seq.RollappId, 6) s.Require().NoError(err) err = s.k().CanUnbond(s.Ctx, seq) @@ -72,3 +72,44 @@ func (s *TestSuite) TestUnbondConditionFlow() { 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) +} From 5111f261887f334e3c3cf7b4c981f3fce92dfb2f Mon Sep 17 00:00:00 2001 From: zale144 Date: Tue, 5 Nov 2024 21:50:25 +0100 Subject: [PATCH 09/13] fix: ante handler reject messages recursively (#1392) Co-authored-by: Michael Tsitrin --- app/ante/ante_options.go | 5 +- app/ante/handlers.go | 15 ++- app/ante/reject_msgs.go | 118 ++++++++++++++++---- app/ante/reject_msgs_test.go | 204 +++++++++++++++++++++++++++++++++++ 4 files changed, 308 insertions(+), 34 deletions(-) create mode 100644 app/ante/reject_msgs_test.go 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}, + } +} From b4e5688249ede6a9b53a85e73dbe3392483f95f0 Mon Sep 17 00:00:00 2001 From: keruch <53012408+keruch@users.noreply.github.com> Date: Tue, 5 Nov 2024 23:51:32 +0300 Subject: [PATCH 10/13] fix(rollapp): DRS atomic iteration, DRS import/export genesis (#1404) --- .../dymension/rollapp/genesis.proto | 2 + x/rollapp/genesis.go | 15 +- .../msg_server_mark_vulnerable_rollapps.go | 10 +- x/rollapp/types/genesis.go | 10 + x/rollapp/types/genesis.pb.go | 185 ++++++++++++++---- x/rollapp/types/genesis_test.go | 13 ++ 6 files changed, 196 insertions(+), 39 deletions(-) diff --git a/proto/dymensionxyz/dymension/rollapp/genesis.proto b/proto/dymensionxyz/dymension/rollapp/genesis.proto index 6fa248afa..8b8abc9aa 100644 --- a/proto/dymensionxyz/dymension/rollapp/genesis.proto +++ b/proto/dymensionxyz/dymension/rollapp/genesis.proto @@ -23,6 +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; } message SequencerHeightPair { diff --git a/x/rollapp/genesis.go b/x/rollapp/genesis.go index 6df044a2c..1f07fcf61 100644 --- a/x/rollapp/genesis.go +++ b/x/rollapp/genesis.go @@ -44,13 +44,20 @@ 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) + } + } k.SetParams(ctx, genState.Params) } @@ -92,5 +99,11 @@ func ExportGenesis(ctx sdk.Context, k keeper.Keeper) *types.GenesisState { panic(err) } + drsVersions, err := k.GetAllVulnerableDRSVersions(ctx) + if err != nil { + panic(err) + } + genesis.VulnerableDrsVersions = drsVersions + return genesis } diff --git a/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go b/x/rollapp/keeper/msg_server_mark_vulnerable_rollapps.go index feef79b64..7cc0be3a3 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" ) @@ -68,9 +69,14 @@ func (k Keeper) MarkVulnerableRollapps(ctx sdk.Context, drsVersions []uint32) (i _, vulnerable := vulnerableVersions[bd.DrsVersion] if vulnerable { - err := k.MarkRollappAsVulnerable(ctx, rollapp.RollappId) + // If this fails, no state change happens + err := osmoutils.ApplyFuncIfNoError(ctx, func(ctx sdk.Context) error { + return k.MarkRollappAsVulnerable(ctx, rollapp.RollappId) + }) if err != nil { - return 0, fmt.Errorf("freeze rollapp: %w", 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/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 7a249b75b..03cee006b 100644 --- a/x/rollapp/types/genesis.pb.go +++ b/x/rollapp/types/genesis.pb.go @@ -36,6 +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"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -141,6 +143,13 @@ func (m *GenesisState) GetSequencerHeightPairs() []SequencerHeightPair { 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"` @@ -256,42 +265,45 @@ func init() { } var fileDescriptor_b76890aebc09aa04 = []byte{ - // 558 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x94, 0x4f, 0x6f, 0xd3, 0x30, - 0x18, 0xc6, 0x9b, 0x6d, 0xb4, 0xf4, 0x2d, 0x20, 0x64, 0x26, 0x88, 0xaa, 0x2d, 0x54, 0x45, 0x82, - 0x22, 0x58, 0x22, 0xad, 0x48, 0xdc, 0x90, 0x28, 0xe3, 0x4f, 0xc5, 0x04, 0x23, 0x03, 0x0e, 0x70, - 0x98, 0xd2, 0xc6, 0x4b, 0x2d, 0x12, 0x3b, 0xc4, 0x6e, 0xd5, 0xf6, 0x53, 0x70, 0xe0, 0x43, 0xed, - 0xb8, 0x23, 0x27, 0x84, 0xda, 0xcf, 0x81, 0x84, 0xea, 0x38, 0xa1, 0x6c, 0x6b, 0x5d, 0x89, 0x53, - 0x6b, 0xe7, 0x79, 0x7e, 0xcf, 0x63, 0xcb, 0x7a, 0xe1, 0xa1, 0x3f, 0x8a, 0x30, 0xe5, 0x84, 0xd1, - 0xe1, 0x68, 0xec, 0xe4, 0x0b, 0x27, 0x61, 0x61, 0xe8, 0xc5, 0xb1, 0x13, 0x60, 0x8a, 0x39, 0xe1, - 0x76, 0x9c, 0x30, 0xc1, 0x90, 0x35, 0xaf, 0xb6, 0xf3, 0x85, 0xad, 0xd4, 0xd5, 0xcd, 0x80, 0x05, - 0x4c, 0x4a, 0x9d, 0xd9, 0xbf, 0xd4, 0x55, 0x7d, 0xa0, 0xc9, 0x88, 0xbd, 0xc4, 0x8b, 0x54, 0x44, - 0x55, 0x57, 0x48, 0xfd, 0x2a, 0xb5, 0xa3, 0x51, 0x73, 0xe1, 0x09, 0x7c, 0x44, 0xe8, 0x71, 0xd6, - 0x65, 0x47, 0x63, 0x08, 0xc9, 0x60, 0x76, 0xe2, 0xac, 0x4d, 0x43, 0x23, 0xcf, 0x9b, 0xd4, 0x7f, - 0x97, 0xe0, 0xca, 0xcb, 0xf4, 0xb2, 0x0e, 0x67, 0xa1, 0x68, 0x0f, 0x8a, 0xe9, 0xc1, 0x4c, 0xa3, - 0x66, 0x34, 0x2a, 0xbb, 0x77, 0xed, 0xe5, 0x97, 0x67, 0x1f, 0x48, 0x75, 0x6b, 0xe3, 0xe4, 0xe7, - 0xed, 0x82, 0xab, 0xbc, 0xe8, 0x2d, 0x54, 0xd4, 0xf7, 0x7d, 0xc2, 0x85, 0xb9, 0x56, 0x5b, 0x6f, - 0x54, 0x76, 0xef, 0xe9, 0x50, 0x6e, 0xfa, 0xab, 0x58, 0xf3, 0x04, 0xf4, 0x01, 0xae, 0xca, 0x4b, - 0x69, 0xd3, 0x63, 0x26, 0x91, 0xeb, 0x12, 0x79, 0x5f, 0x87, 0x3c, 0xcc, 0x4c, 0x0a, 0xfa, 0x2f, - 0x05, 0xc5, 0x60, 0x86, 0x9e, 0xc0, 0x5c, 0xe4, 0xba, 0x36, 0xf5, 0xf1, 0x50, 0x26, 0x6c, 0xc8, - 0x04, 0x7b, 0xe5, 0x04, 0xe9, 0x54, 0x31, 0x0b, 0xa9, 0x68, 0x0c, 0xdb, 0xe9, 0xb7, 0x17, 0x84, - 0x7a, 0x21, 0x19, 0x63, 0x5f, 0x89, 0xb2, 0xd8, 0x4b, 0xff, 0x11, 0xbb, 0x1c, 0x8d, 0xbe, 0x1b, - 0x50, 0xef, 0x84, 0xac, 0xfb, 0xe5, 0x15, 0x26, 0x41, 0x4f, 0xbc, 0x67, 0x4a, 0xe8, 0x09, 0xc2, - 0xe8, 0xbb, 0x3e, 0xee, 0x63, 0xd9, 0xa0, 0x28, 0x1b, 0x3c, 0xd1, 0x35, 0x68, 0x2d, 0x25, 0xa9, - 0x46, 0x2b, 0xe4, 0xa1, 0xcf, 0x70, 0x2d, 0x7b, 0xbf, 0xcf, 0x07, 0x98, 0x0a, 0x6e, 0x96, 0x64, - 0x83, 0x1d, 0x5d, 0x83, 0xfd, 0x79, 0x97, 0x0a, 0x3c, 0x83, 0x42, 0xcf, 0xa0, 0x94, 0xbd, 0xc2, - 0xcb, 0x92, 0x7a, 0x47, 0x47, 0x7d, 0x9a, 0xbf, 0xc0, 0xcc, 0x89, 0x08, 0x5c, 0x4f, 0x70, 0x40, - 0xb8, 0xc0, 0x09, 0xf6, 0xf7, 0x30, 0x65, 0x11, 0x37, 0xcb, 0x92, 0xf6, 0x78, 0xc5, 0x37, 0xed, - 0x9e, 0xb1, 0xab, 0x84, 0x73, 0x58, 0x14, 0xc1, 0x26, 0xc7, 0x5f, 0xfb, 0x98, 0x76, 0x71, 0x92, - 0x5e, 0xdb, 0x81, 0x47, 0x12, 0x6e, 0x82, 0x8c, 0x6b, 0x6a, 0x9f, 0xc5, 0x79, 0xaf, 0x8a, 0xba, - 0x10, 0x5b, 0x7f, 0x0d, 0x37, 0x2e, 0xb0, 0xa0, 0x2d, 0x28, 0xe7, 0x72, 0x39, 0x08, 0xca, 0xee, - 0xdf, 0x0d, 0x74, 0x13, 0x8a, 0x3d, 0xa9, 0x35, 0xd7, 0x6a, 0x46, 0x63, 0xc3, 0x55, 0xab, 0xfa, - 0x47, 0xb8, 0xb5, 0xe0, 0xb8, 0x68, 0x1b, 0x40, 0x55, 0x3c, 0x22, 0x7e, 0x46, 0x54, 0x3b, 0x6d, - 0x1f, 0x6d, 0x41, 0xd1, 0x4f, 0xaf, 0x75, 0x36, 0x2a, 0xca, 0xd9, 0x34, 0x49, 0xf7, 0x5a, 0x6f, - 0x4e, 0x26, 0x96, 0x71, 0x3a, 0xb1, 0x8c, 0x5f, 0x13, 0xcb, 0xf8, 0x36, 0xb5, 0x0a, 0xa7, 0x53, - 0xab, 0xf0, 0x63, 0x6a, 0x15, 0x3e, 0x3d, 0x0a, 0x88, 0xe8, 0xf5, 0x3b, 0x76, 0x97, 0x45, 0x8b, - 0x66, 0xea, 0xa0, 0xe9, 0x0c, 0xf3, 0xc1, 0x27, 0x46, 0x31, 0xe6, 0x9d, 0xa2, 0x9c, 0x7d, 0xcd, - 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x71, 0xe2, 0x44, 0xa5, 0x46, 0x06, 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) { @@ -314,6 +326,24 @@ 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-- { { @@ -600,6 +630,13 @@ func (m *GenesisState) Size() (n int) { 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 } @@ -1012,6 +1049,82 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { 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:]) diff --git a/x/rollapp/types/genesis_test.go b/x/rollapp/types/genesis_test.go index d2c228a64..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, }, @@ -141,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() From b49d4f5ea55134173e9402143b5cab9dc74fe8c6 Mon Sep 17 00:00:00 2001 From: zale144 Date: Wed, 6 Nov 2024 11:44:18 +0100 Subject: [PATCH 11/13] fix(rollapp): add latest height and latest finalized height to rollapp summary (#1407) --- x/rollapp/keeper/grpc_query_rollapp.go | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/x/rollapp/keeper/grpc_query_rollapp.go b/x/rollapp/keeper/grpc_query_rollapp.go index 8afa4eb1b..888209578 100644 --- a/x/rollapp/keeper/grpc_query_rollapp.go +++ b/x/rollapp/keeper/grpc_query_rollapp.go @@ -67,10 +67,21 @@ func getSummaryResponse(ctx sdk.Context, k Keeper, rollapp types.Rollapp, ok, wi latestStateInfoIndex, found := k.GetLatestStateInfoIndex(ctx, rollapp.RollappId) if found { s.LatestStateIndex = &latestStateInfoIndex + + latestStateInfo, foundFin := k.GetStateInfo(ctx, rollapp.RollappId, latestStateInfoIndex.Index) + if foundFin { + s.LatestHeight = latestStateInfo.GetLatestHeight() + } } - latestFinalizedStateInfoIndex, found := k.GetLatestFinalizedStateIndex(ctx, rollapp.RollappId) - if found { + + latestFinalizedStateInfoIndex, foundFinIdx := k.GetLatestFinalizedStateIndex(ctx, rollapp.RollappId) + if foundFinIdx { s.LatestFinalizedStateIndex = &latestFinalizedStateInfoIndex + + latestFinalizedStateInfo, foundFin := k.GetStateInfo(ctx, rollapp.RollappId, latestFinalizedStateInfoIndex.Index) + if foundFin { + s.LatestFinalizedHeight = latestFinalizedStateInfo.GetLatestHeight() + } } resp := &types.QueryGetRollappResponse{ From ea79caf41821e2d23693a491074071f864fe40b4 Mon Sep 17 00:00:00 2001 From: Michael Tsitrin <114929630+mtsitrin@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:56:50 +0200 Subject: [PATCH 12/13] fix(crisis): Fix crisis module wiring (#1424) --- app/keepers/keepers.go | 8 ++++---- scripts/src/genesis_config_commands.sh | 1 - x/delayedack/client/cli/query.go | 9 ++++++++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/keepers/keepers.go b/app/keepers/keepers.go index 984c0a897..26bf98cfe 100644 --- a/app/keepers/keepers.go +++ b/app/keepers/keepers.go @@ -189,10 +189,6 @@ func (a *AppKeepers) InitKeepers( a.CapabilityKeeper.Seal() - a.CrisisKeeper = crisiskeeper.NewKeeper( - appCodec, a.keys[crisistypes.StoreKey], invCheckPeriod, a.BankKeeper, authtypes.FeeCollectorName, govModuleAddress, - ) - a.UpgradeKeeper = upgradekeeper.NewKeeper( skipUpgradeHeights, a.keys[upgradetypes.StoreKey], @@ -226,6 +222,10 @@ func (a *AppKeepers) InitKeepers( govModuleAddress, ) + a.CrisisKeeper = crisiskeeper.NewKeeper( + appCodec, a.keys[crisistypes.StoreKey], invCheckPeriod, a.BankKeeper, authtypes.FeeCollectorName, govModuleAddress, + ) + a.StakingKeeper = stakingkeeper.NewKeeper( appCodec, a.keys[stakingtypes.StoreKey], diff --git a/scripts/src/genesis_config_commands.sh b/scripts/src/genesis_config_commands.sh index 16feffebf..884f7f567 100644 --- a/scripts/src/genesis_config_commands.sh +++ b/scripts/src/genesis_config_commands.sh @@ -17,7 +17,6 @@ set_hub_params() { jq '.app_state.rollapp.params.dispute_period_in_blocks = "50"' "$GENESIS_FILE" > "$tmp" && mv "$tmp" "$GENESIS_FILE" - jq '.app_state.sequencer.params.unbonding_time = "1209600s"' "$GENESIS_FILE" > "$tmp" && mv "$tmp" "$GENESIS_FILE" jq '.app_state.sequencer.params.notice_period = "60s"' "$GENESIS_FILE" > "$tmp" && mv "$tmp" "$GENESIS_FILE" #increase the tx size cost per byte from 10 to 100 diff --git a/x/delayedack/client/cli/query.go b/x/delayedack/client/cli/query.go index 1451de912..fbda768bd 100644 --- a/x/delayedack/client/cli/query.go +++ b/x/delayedack/client/cli/query.go @@ -8,6 +8,8 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/spf13/cobra" + sdk "github.com/cosmos/cosmos-sdk/types" + commontypes "github.com/dymensionxyz/dymension/v3/x/common/types" "github.com/dymensionxyz/dymension/v3/x/delayedack/types" ) @@ -223,7 +225,7 @@ func CmdGetPendingPacketsByAddress() *cobra.Command { cmd := &cobra.Command{ Use: "pending-packets-by-address [address]", Short: "Get pending packets by address", - Args: cobra.MinimumNArgs(1), + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { clientCtx, err := client.GetClientQueryContext(cmd) if err != nil { @@ -231,6 +233,11 @@ func CmdGetPendingPacketsByAddress() *cobra.Command { } queryClient := types.NewQueryClient(clientCtx) + _, err = sdk.AccAddressFromBech32(args[0]) + if err != nil { + return err + } + res, err := queryClient.GetPendingPacketsByAddress(cmd.Context(), &types.QueryPendingPacketsByAddressRequest{ Address: args[0], Pagination: nil, // TODO: handle pagination From 4fe9719366d46ac78878ee527ea2c357eb097260 Mon Sep 17 00:00:00 2001 From: Daniel T <30197399+danwt@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:02:30 +0000 Subject: [PATCH 13/13] deletes v3 migration (#1422) --- app/app.go | 3 +- app/upgrades/v3/constants.go | 20 ----- app/upgrades/v3/upgrade.go | 47 ------------ app/upgrades/v3/upgrade_test.go | 130 -------------------------------- 4 files changed, 1 insertion(+), 199 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 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) - } - }) - } -}