From 3385830b33b3e34784f58e1a847283176b3c9277 Mon Sep 17 00:00:00 2001 From: Jongwon Park Date: Tue, 17 Sep 2024 19:43:16 -0500 Subject: [PATCH 1/6] feat(x/signal): signal module for single binary upgrade --- .../testutil/expected_keepers_mocks.go | 38 +- client/x/signal/cli/cli_test.go | 47 + client/x/signal/cli/query.go | 86 ++ client/x/signal/cli/tx.go | 77 ++ client/x/signal/keeper/keeper.go | 323 ++++++ client/x/signal/legacy_test.go | 204 ++++ client/x/signal/module/depinject.go | 61 ++ client/x/signal/module/module.go | 142 +++ client/x/signal/module/module.proto | 16 + client/x/signal/module/module.pulsar.go | 578 +++++++++++ client/x/signal/types/codec.go | 23 + client/x/signal/types/errors.go | 11 + client/x/signal/types/expected_keepers.go | 31 + client/x/signal/types/keys.go | 26 + client/x/signal/types/msgs.go | 91 ++ client/x/signal/types/query.pb.go | 969 ++++++++++++++++++ client/x/signal/types/query.pb.gw.go | 254 +++++ client/x/signal/types/query.proto | 42 + client/x/signal/types/tx.pb.go | 900 ++++++++++++++++ client/x/signal/types/tx.pb.gw.go | 254 +++++ client/x/signal/types/tx.proto | 35 + client/x/signal/types/upgrade.pb.go | 341 ++++++ client/x/signal/types/upgrade.proto | 15 + scripts/mockgen.sh | 1 + 24 files changed, 4531 insertions(+), 34 deletions(-) create mode 100644 client/x/signal/cli/cli_test.go create mode 100644 client/x/signal/cli/query.go create mode 100644 client/x/signal/cli/tx.go create mode 100644 client/x/signal/keeper/keeper.go create mode 100644 client/x/signal/legacy_test.go create mode 100644 client/x/signal/module/depinject.go create mode 100644 client/x/signal/module/module.go create mode 100644 client/x/signal/module/module.proto create mode 100644 client/x/signal/module/module.pulsar.go create mode 100644 client/x/signal/types/codec.go create mode 100644 client/x/signal/types/errors.go create mode 100644 client/x/signal/types/expected_keepers.go create mode 100644 client/x/signal/types/keys.go create mode 100644 client/x/signal/types/msgs.go create mode 100644 client/x/signal/types/query.pb.go create mode 100644 client/x/signal/types/query.pb.gw.go create mode 100644 client/x/signal/types/query.proto create mode 100644 client/x/signal/types/tx.pb.go create mode 100644 client/x/signal/types/tx.pb.gw.go create mode 100644 client/x/signal/types/tx.proto create mode 100644 client/x/signal/types/upgrade.pb.go create mode 100644 client/x/signal/types/upgrade.proto diff --git a/client/x/evmstaking/testutil/expected_keepers_mocks.go b/client/x/evmstaking/testutil/expected_keepers_mocks.go index ab85d653..544e4ea1 100644 --- a/client/x/evmstaking/testutil/expected_keepers_mocks.go +++ b/client/x/evmstaking/testutil/expected_keepers_mocks.go @@ -155,15 +155,15 @@ func (mr *MockAccountKeeperMockRecorder) SetAccount(ctx, acc any) *gomock.Call { } // SetModuleAccount mocks base method. -func (m *MockAccountKeeper) SetModuleAccount(arg0 context.Context, arg1 types0.ModuleAccountI) { +func (m *MockAccountKeeper) SetModuleAccount(ctx context.Context, modAcc types0.ModuleAccountI) { m.ctrl.T.Helper() - m.ctrl.Call(m, "SetModuleAccount", arg0, arg1) + m.ctrl.Call(m, "SetModuleAccount", ctx, modAcc) } // SetModuleAccount indicates an expected call of SetModuleAccount. -func (mr *MockAccountKeeperMockRecorder) SetModuleAccount(arg0, arg1 any) *gomock.Call { +func (mr *MockAccountKeeperMockRecorder) SetModuleAccount(ctx, modAcc any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).SetModuleAccount), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).SetModuleAccount), ctx, modAcc) } // MockBankKeeper is a mock of BankKeeper interface. @@ -395,21 +395,6 @@ func (mr *MockStakingKeeperMockRecorder) BondDenom(ctx any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BondDenom", reflect.TypeOf((*MockStakingKeeper)(nil).BondDenom), ctx) } -// CompleteRedelegation mocks base method. -func (m *MockStakingKeeper) CompleteRedelegation(ctx context.Context, delAddr types0.AccAddress, valSrcAddr, valDstAddr types0.ValAddress) (types0.Coins, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CompleteRedelegation", ctx, delAddr, valSrcAddr, valDstAddr) - ret0, _ := ret[0].(types0.Coins) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CompleteRedelegation indicates an expected call of CompleteRedelegation. -func (mr *MockStakingKeeperMockRecorder) CompleteRedelegation(ctx, delAddr, valSrcAddr, valDstAddr any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CompleteRedelegation", reflect.TypeOf((*MockStakingKeeper)(nil).CompleteRedelegation), ctx, delAddr, valSrcAddr, valDstAddr) -} - // DeleteUnbondingIndex mocks base method. func (m *MockStakingKeeper) DeleteUnbondingIndex(ctx context.Context, id uint64) error { m.ctrl.T.Helper() @@ -424,21 +409,6 @@ func (mr *MockStakingKeeperMockRecorder) DeleteUnbondingIndex(ctx, id any) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUnbondingIndex", reflect.TypeOf((*MockStakingKeeper)(nil).DeleteUnbondingIndex), ctx, id) } -// DequeueAllMatureRedelegationQueue mocks base method. -func (m *MockStakingKeeper) DequeueAllMatureRedelegationQueue(ctx context.Context, currTime time.Time) ([]types2.DVVTriplet, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DequeueAllMatureRedelegationQueue", ctx, currTime) - ret0, _ := ret[0].([]types2.DVVTriplet) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DequeueAllMatureRedelegationQueue indicates an expected call of DequeueAllMatureRedelegationQueue. -func (mr *MockStakingKeeperMockRecorder) DequeueAllMatureRedelegationQueue(ctx, currTime any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DequeueAllMatureRedelegationQueue", reflect.TypeOf((*MockStakingKeeper)(nil).DequeueAllMatureRedelegationQueue), ctx, currTime) -} - // EndBlocker mocks base method. func (m *MockStakingKeeper) EndBlocker(ctx context.Context) ([]types.ValidatorUpdate, error) { m.ctrl.T.Helper() diff --git a/client/x/signal/cli/cli_test.go b/client/x/signal/cli/cli_test.go new file mode 100644 index 00000000..94a7a030 --- /dev/null +++ b/client/x/signal/cli/cli_test.go @@ -0,0 +1,47 @@ +package cli_test + +import ( + "testing" + + "github.com/celestiaorg/celestia-app/v3/test/util/testnode" + testutil "github.com/cosmos/cosmos-sdk/testutil/cli" + "github.com/piplabs/story/client/x/signal/cli" + "github.com/stretchr/testify/suite" +) + +func TestCLITestSuite(t *testing.T) { + if testing.Short() { + t.Skip("skipping upgrade CLI test in short mode") + } + suite.Run(t, new(CLITestSuite)) +} + +type CLITestSuite struct { + suite.Suite + + ctx testnode.Context +} + +func (s *CLITestSuite) SetupSuite() { + s.T().Log("setting up CLI test suite") + ctx, _, _ := testnode.NewNetwork(s.T(), testnode.DefaultConfig()) + s.ctx = ctx + _, err := s.ctx.WaitForHeight(1) + s.Require().NoError(err) +} + +func (s *CLITestSuite) TestCmdQueryTally() { + cmd := cli.CmdQueryTally() + output, err := testutil.ExecTestCLICmd(s.ctx.Context, cmd, []string{"1"}) + s.Require().NoError(err) + s.Require().Contains(output.String(), "voting_power") + s.Require().Contains(output.String(), "threshold_power") + s.Require().Contains(output.String(), "total_voting_power") +} + +func (s *CLITestSuite) TestCmdGetUpgrade() { + cmd := cli.CmdGetUpgrade() + output, err := testutil.ExecTestCLICmd(s.ctx.Context, cmd, []string{}) + s.Require().NoError(err) + s.Require().Contains(output.String(), "No upgrade is pending.") +} diff --git a/client/x/signal/cli/query.go b/client/x/signal/cli/query.go new file mode 100644 index 00000000..a333a11b --- /dev/null +++ b/client/x/signal/cli/query.go @@ -0,0 +1,86 @@ +package cli + +import ( + "fmt" + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/piplabs/story/client/x/signal/types" + "github.com/spf13/cobra" +) + +// GetQueryCmd returns the CLI query commands for this module. +func GetQueryCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("Querying commands for the %s module", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(CmdQueryTally()) + cmd.AddCommand(CmdGetUpgrade()) + return cmd +} + +func CmdQueryTally() *cobra.Command { + cmd := &cobra.Command{ + Use: "tally version", + Short: "Query for the tally of voting power that has signalled for a particular version", + Args: cobra.ExactArgs(1), + Example: "tally 3", + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + version, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + + upgradeQueryClient := types.NewQueryClient(clientCtx) + resp, err := upgradeQueryClient.VersionTally(cmd.Context(), &types.QueryVersionTallyRequest{Version: version}) + if err != nil { + return err + } + + return clientCtx.PrintProto(resp) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} + +func CmdGetUpgrade() *cobra.Command { + cmd := &cobra.Command{ + Use: "upgrade", + Short: "Query for the upgrade information if an upgrade is pending", + Args: cobra.NoArgs, + Example: "upgrade", + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + + queryClient := types.NewQueryClient(clientCtx) + resp, err := queryClient.GetUpgrade(cmd.Context(), &types.QueryGetUpgradeRequest{}) + if err != nil { + return err + } + + if resp.Upgrade != nil { + return clientCtx.PrintString(fmt.Sprintf("An upgrade is pending to app version %d at height %d.\n", resp.Upgrade.AppVersion, resp.Upgrade.UpgradeHeight)) + } + return clientCtx.PrintString("No upgrade is pending.\n") + }, + } + + flags.AddQueryFlagsToCmd(cmd) + return cmd +} diff --git a/client/x/signal/cli/tx.go b/client/x/signal/cli/tx.go new file mode 100644 index 00000000..7738c5a1 --- /dev/null +++ b/client/x/signal/cli/tx.go @@ -0,0 +1,77 @@ +package cli + +import ( + "fmt" + "strconv" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/piplabs/story/client/x/signal/types" + "github.com/spf13/cobra" +) + +// GetTxCmd returns the transaction commands for this module. +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(CmdSignalVersion()) + cmd.AddCommand(CmdTryUpgrade()) + return cmd +} + +func CmdSignalVersion() *cobra.Command { + cmd := &cobra.Command{ + Use: "signal version", + Short: "Signal a software upgrade for the specified version", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + version, err := strconv.ParseUint(args[0], 10, 64) + if err != nil { + return err + } + + addr := clientCtx.GetFromAddress().Bytes() + valAddr := sdk.ValAddress(addr) + msg := types.NewMsgSignalVersion(valAddr, version) + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} + +func CmdTryUpgrade() *cobra.Command { + cmd := &cobra.Command{ + Use: "try-upgrade", + Short: "Try to perform a software upgrade", + Long: `This command will submit a TryUpgrade message to tally all +the signal votes. If a quorum has been reached, the network will upgrade +to the signalled version at the following height. +`, + RunE: func(cmd *cobra.Command, _ []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + msg := types.NewMsgTryUpgrade(clientCtx.GetFromAddress()) + return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + return cmd +} diff --git a/client/x/signal/keeper/keeper.go b/client/x/signal/keeper/keeper.go new file mode 100644 index 00000000..8a0ac150 --- /dev/null +++ b/client/x/signal/keeper/keeper.go @@ -0,0 +1,323 @@ +package keeper + +import ( + "context" + "encoding/binary" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + "cosmossdk.io/core/store" + sdkmath "cosmossdk.io/math" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/piplabs/story/client/x/signal/types" + "github.com/piplabs/story/lib/log" +) + +// DefaultUpgradeHeightDelay is the number of blocks after a quorum has been +// reached that the chain should upgrade to the new version. Assuming a block +// interval of 12 seconds, this is 7 days. +const DefaultUpgradeHeightDelay = int64(7 * 24 * 60 * 60 / 12) // 7 days * 24 hours * 60 minutes * 60 seconds / 12 seconds per block = 50,400 blocks. + +// Keeper implements the MsgServer and QueryServer interfaces. +var ( + _ types.MsgServer = &Keeper{} + _ types.QueryServer = Keeper{} + + // defaultSignalThreshold is 5/6 or approximately 83.33%. + defaultSignalThreshold = sdkmath.LegacyNewDec(5).Quo(sdkmath.LegacyNewDec(6)) +) + +// Threshold is the fraction of voting power that is required +// to signal for a version change. It is set to 5/6 as the middle point +// between 2/3 and 3/3 providing 1/6 fault tolerance to halting the +// network during an upgrade period. It can be modified through a +// hard fork change that modified the app version. +func Threshold(_ uint64) sdkmath.LegacyDec { + return defaultSignalThreshold +} + +type Keeper struct { + cdc codec.BinaryCodec + storeService store.KVStoreService + authority string + + authKeeper types.AccountKeeper + stakingKeeper types.StakingKeeper +} + +// NewKeeper returns a signal keeper. +func NewKeeper( + cdc codec.BinaryCodec, + storeService store.KVStoreService, + ak types.AccountKeeper, + stk types.StakingKeeper, + authority string, +) *Keeper { + // ensure that authority is a valid AccAddress + if _, err := ak.AddressCodec().StringToBytes(authority); err != nil { + panic("authority is not a valid acc address") + } + + // ensure the module account is set + if addr := ak.GetModuleAddress(types.ModuleName); addr == nil { + panic(types.ModuleName + " module account has not been set") + } + + return &Keeper{ + cdc: cdc, + storeService: storeService, + authKeeper: ak, + stakingKeeper: stk, + } +} + +// SignalVersion is a method required by the MsgServer interface. +func (k Keeper) SignalVersion(ctx context.Context, req *types.MsgSignalVersion) (*types.MsgSignalVersionResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + if k.IsUpgradePending(sdkCtx) { + return &types.MsgSignalVersionResponse{}, types.ErrUpgradePending.Wrapf("can not signal version") + } + + valAddr, err := sdk.ValAddressFromBech32(req.ValidatorAddress) + if err != nil { + return nil, err + } + + // The signaled version can not be less than the current version. + currentVersion := sdkCtx.BlockHeader().Version.App + if req.Version < currentVersion { + return nil, types.ErrInvalidSignalVersion.Wrapf("signaled version %d, current version %d", req.Version, currentVersion) + } + + if _, err := k.stakingKeeper.GetValidator(sdkCtx, valAddr); err != nil { + return nil, stakingtypes.ErrNoValidatorFound + } + + k.SetValidatorVersion(sdkCtx, valAddr, req.Version) + return &types.MsgSignalVersionResponse{}, nil +} + +// TryUpgrade is a method required by the MsgServer interface. It tallies the +// voting power that has voted on each version. If one version has reached a +// quorum, an upgrade is persisted to the store. The upgrade is used by the +// application later when it is time to upgrade to that version. +func (k *Keeper) TryUpgrade(ctx context.Context, _ *types.MsgTryUpgrade) (*types.MsgTryUpgradeResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + + if k.IsUpgradePending(sdkCtx) { + return &types.MsgTryUpgradeResponse{}, types.ErrUpgradePending.Wrapf("can not try upgrade") + } + + threshold := k.GetVotingPowerThreshold(sdkCtx) + hasQuorum, version := k.TallyVotingPower(sdkCtx, threshold.Int64()) + if hasQuorum { + if version <= sdkCtx.BlockHeader().Version.App { + return &types.MsgTryUpgradeResponse{}, types.ErrInvalidUpgradeVersion.Wrapf("can not upgrade to version %v because it is less than or equal to current version %v", version, sdkCtx.BlockHeader().Version.App) + } + upgrade := types.Upgrade{ + AppVersion: version, + UpgradeHeight: sdkCtx.BlockHeader().Height + DefaultUpgradeHeightDelay, + } + k.setUpgrade(sdkCtx, upgrade) + } + return &types.MsgTryUpgradeResponse{}, nil +} + +// VersionTally enables a client to query for the tally of voting power has +// signaled for a particular version. +func (k Keeper) VersionTally(ctx context.Context, req *types.QueryVersionTallyRequest) (*types.QueryVersionTallyResponse, error) { + sdkCtx := sdk.UnwrapSDKContext(ctx) + totalVotingPower, err := k.stakingKeeper.GetLastTotalPower(ctx) + if err != nil { + return &types.QueryVersionTallyResponse{}, err + } + currentVotingPower := sdkmath.NewInt(0) + + stores := k.storeService.OpenKVStore(ctx) + iterator, err := stores.Iterator(types.FirstSignalKey, nil) + if err != nil { + return &types.QueryVersionTallyResponse{}, err + } + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + valAddress := sdk.ValAddress(iterator.Key()) + power, err := k.stakingKeeper.GetLastValidatorPower(sdkCtx, valAddress) + if err != nil { + log.Error(ctx, "Failed to get last validator power", err) + continue + } + version := VersionFromBytes(iterator.Value()) + if version == req.Version { + currentVotingPower = currentVotingPower.AddRaw(power) + } + } + + threshold := k.GetVotingPowerThreshold(sdkCtx) + + return &types.QueryVersionTallyResponse{ + VotingPower: currentVotingPower.Uint64(), + ThresholdPower: threshold.Uint64(), + TotalVotingPower: totalVotingPower.Uint64(), + }, nil +} + +// SetValidatorVersion saves a signaled version for a validator. +func (k Keeper) SetValidatorVersion(ctx sdk.Context, valAddress sdk.ValAddress, version uint64) { + stores := k.storeService.OpenKVStore(ctx) + if err := stores.Set(valAddress, VersionToBytes(version)); err != nil { + panic(err) + } +} + +// DeleteValidatorVersion deletes a signaled version for a validator. +func (k Keeper) DeleteValidatorVersion(ctx sdk.Context, valAddress sdk.ValAddress) { + stores := k.storeService.OpenKVStore(ctx) + if err := stores.Delete(valAddress); err != nil { + panic(err) + } +} + +// TallyVotingPower tallies the voting power for each version and returns true +// and the version if any version has reached the quorum in voting power. +// Returns false and 0 otherwise. +func (k Keeper) TallyVotingPower(ctx sdk.Context, threshold int64) (bool, uint64) { + stores := k.storeService.OpenKVStore(ctx) + iterator, err := stores.Iterator(types.FirstSignalKey, nil) + if err != nil { + return false, 0 + } + defer iterator.Close() + + versionToPower := make(map[uint64]int64) + for ; iterator.Valid(); iterator.Next() { + valAddress := sdk.ValAddress(iterator.Key()) + // check that the validator is still part of the bonded set + val, err := k.stakingKeeper.GetValidator(ctx, valAddress) + if err != nil { + // if it no longer exists, delete the version + k.DeleteValidatorVersion(ctx, valAddress) + } + // if the validator is not bonded, skip it's voting power + if err != nil || !val.IsBonded() { + continue + } + power, err := k.stakingKeeper.GetLastValidatorPower(ctx, valAddress) + if err != nil { + log.Error(ctx, "Failed to get last validator power", err) + continue + } + version := VersionFromBytes(iterator.Value()) + if _, ok := versionToPower[version]; !ok { + versionToPower[version] = power + } else { + versionToPower[version] += power + } + if versionToPower[version] >= threshold { + return true, version + } + } + + return false, 0 +} + +// GetVotingPowerThreshold returns the voting power threshold required to +// upgrade to a new version. +func (k Keeper) GetVotingPowerThreshold(ctx sdk.Context) sdkmath.Int { + totalVotingPower, err := k.stakingKeeper.GetLastTotalPower(ctx) + if err != nil { + panic(err) + } + thresholdFraction := Threshold(ctx.BlockHeader().Version.App) + return thresholdFraction.MulInt(totalVotingPower).Ceil().TruncateInt() +} + +// ShouldUpgrade returns whether the signaling mechanism has concluded that the +// network is ready to upgrade and the version to upgrade to. It returns false +// and 0 if no version has reached quorum. +func (k *Keeper) ShouldUpgrade(ctx sdk.Context) (isQuorumVersion bool, version uint64) { + upgrade, ok := k.getUpgrade(ctx) + if !ok { + return false, 0 + } + + hasUpgradeHeightBeenReached := ctx.BlockHeight() >= upgrade.UpgradeHeight + if hasUpgradeHeightBeenReached { + return true, upgrade.AppVersion + } + return false, 0 +} + +// ResetTally resets the tally after a version change. It iterates over the +// store and deletes all versions. It also resets the quorumVersion and +// upgradeHeight to 0. +func (k *Keeper) ResetTally(ctx sdk.Context) { + stores := k.storeService.OpenKVStore(ctx) + iterator, err := stores.Iterator(nil, nil) + if err != nil { + panic(err) + } + defer iterator.Close() + // delete the value in the upgrade key and all signals. + for ; iterator.Valid(); iterator.Next() { + if err := stores.Delete(iterator.Key()); err != nil { + panic(err) + } + } +} + +func VersionToBytes(version uint64) []byte { + return binary.BigEndian.AppendUint64(nil, version) +} + +func VersionFromBytes(version []byte) uint64 { + return binary.BigEndian.Uint64(version) +} + +// GetUpgrade returns the current upgrade information. +func (k Keeper) GetUpgrade(ctx context.Context, _ *types.QueryGetUpgradeRequest) (*types.QueryGetUpgradeResponse, error) { + upgrade, ok := k.getUpgrade(sdk.UnwrapSDKContext(ctx)) + if !ok { + return &types.QueryGetUpgradeResponse{}, nil + } + return &types.QueryGetUpgradeResponse{Upgrade: &upgrade}, nil +} + +// IsUpgradePending returns true if an app version has reached quorum and the +// chain should upgrade to the app version at the upgrade height. While the +// keeper has an upgrade pending the SignalVersion and TryUpgrade messages will +// be rejected. +func (k *Keeper) IsUpgradePending(ctx sdk.Context) bool { + _, ok := k.getUpgrade(ctx) + return ok +} + +// getUpgrade returns the current upgrade information from the store. +// If an upgrade is found, it returns the upgrade object and true. +// If no upgrade is found, it returns an empty upgrade object and false. +func (k *Keeper) getUpgrade(ctx sdk.Context) (upgrade types.Upgrade, ok bool) { + stores := k.storeService.OpenKVStore(ctx) + bz, err := stores.Get(types.UpgradeKey) + if err != nil { + return types.Upgrade{}, false + } + + err = k.cdc.Unmarshal(bz, &upgrade) + if err != nil { + return upgrade, false + } + + return upgrade, true +} + +// setUpgrade sets the upgrade in the store. +func (k *Keeper) setUpgrade(ctx sdk.Context, upgrade types.Upgrade) { + stores := k.storeService.OpenKVStore(ctx) + value := k.cdc.MustMarshal(&upgrade) + + if err := stores.Set(types.UpgradeKey, value); err != nil { + panic(err) + } +} diff --git a/client/x/signal/legacy_test.go b/client/x/signal/legacy_test.go new file mode 100644 index 00000000..21f2695a --- /dev/null +++ b/client/x/signal/legacy_test.go @@ -0,0 +1,204 @@ +package signal_test + +import ( + "context" + "sync" + "testing" + "time" + + "github.com/celestiaorg/celestia-app/v3/app" + "github.com/celestiaorg/celestia-app/v3/app/encoding" + "github.com/celestiaorg/celestia-app/v3/pkg/user" + testutil "github.com/celestiaorg/celestia-app/v3/test/util" + "github.com/celestiaorg/celestia-app/v3/test/util/blobfactory" + "github.com/celestiaorg/celestia-app/v3/test/util/genesis" + "github.com/celestiaorg/celestia-app/v3/test/util/testnode" + "github.com/cosmos/cosmos-sdk/crypto/keyring" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + v1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/cosmos-sdk/x/upgrade/types" + ibctypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" + ibctmtypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + tmrand "github.com/tendermint/tendermint/libs/rand" +) + +func TestLegacyUpgrade(t *testing.T) { + if testing.Short() { + t.Skip("skipping x/upgrade SDK integration test in short mode.") + } + suite.Run(t, new(LegacyUpgradeTestSuite)) +} + +// TestRemoval verifies that no handler exists for msg-based software upgrade +// proposals. +func TestRemoval(t *testing.T) { + app, _ := testutil.SetupTestAppWithGenesisValSet(app.DefaultConsensusParams()) + msgSoftwareUpgrade := types.MsgSoftwareUpgrade{} + router := app.MsgServiceRouter() + handler := router.Handler(&msgSoftwareUpgrade) + require.Nil(t, handler) +} + +type LegacyUpgradeTestSuite struct { + suite.Suite + + accounts []string + cctx testnode.Context + ecfg encoding.Config + + govModuleAddress string + + mut sync.Mutex + accountCounter int +} + +// SetupSuite inits a standard chain, with the only exception being a +// dramatically lowered quorum and threshold to pass proposals +func (s *LegacyUpgradeTestSuite) SetupSuite() { + t := s.T() + + s.ecfg = encoding.MakeConfig(app.ModuleBasics) + + // we create an arbitrary number of funded accounts + accounts := make([]string, 3) + for i := 0; i < len(accounts); i++ { + accounts[i] = tmrand.Str(9) + } + + cfg := testnode.DefaultConfig(). + WithFundedAccounts(accounts...). + WithModifiers(genesis.ImmediateProposals(s.ecfg.Codec)) + + cctx, _, _ := testnode.NewNetwork(t, cfg) + + s.accounts = accounts + s.cctx = cctx + require.NoError(t, s.cctx.WaitForNextBlock()) + + // Retrieve the gov module account via grpc + aqc := authtypes.NewQueryClient(s.cctx.GRPCClient) + resp, err := aqc.ModuleAccountByName( + s.cctx.GoContext(), &authtypes.QueryModuleAccountByNameRequest{Name: "gov"}, + ) + s.Require().NoError(err) + var acc authtypes.AccountI + err = s.ecfg.InterfaceRegistry.UnpackAny(resp.Account, &acc) + s.Require().NoError(err) + + // Set the gov module address + s.govModuleAddress = acc.GetAddress().String() +} + +func (s *LegacyUpgradeTestSuite) unusedAccount() string { + s.mut.Lock() + acc := s.accounts[s.accountCounter] + s.accountCounter++ + s.mut.Unlock() + return acc +} + +// TestLegacyGovUpgradeFailure verifies that a transaction with a legacy +// software upgrade proposal fails to execute. +func (s *LegacyUpgradeTestSuite) TestLegacyGovUpgradeFailure() { + t := s.T() + + dep := sdk.NewCoins(sdk.NewCoin(app.BondDenom, sdk.NewInt(1000000000000))) + acc := s.unusedAccount() + accAddr := getAddress(acc, s.cctx.Keyring) + + sftwr := types.NewSoftwareUpgradeProposal("v1", "Social Consensus", types.Plan{ + Name: "v1", + Height: 20, + Info: "rough social consensus", + }) + + msg, err := v1beta1.NewMsgSubmitProposal(sftwr, dep, accAddr) + require.NoError(t, err) + + // submit the transaction and wait a block for it to be included + txClient, err := testnode.NewTxClientFromContext(s.cctx) + require.NoError(t, err) + subCtx, cancel := context.WithTimeout(s.cctx.GoContext(), time.Minute) + defer cancel() + _, err = txClient.SubmitTx(subCtx, []sdk.Msg{msg}, blobfactory.DefaultTxOpts()...) + code := err.(*user.BroadcastTxError).Code + // As the type is not registered, the message will fail with unable to resolve type URL + require.EqualValues(t, 2, code, err.Error()) +} + +// TestNewGovUpgradeFailure verifies that a transaction with a +// MsgSoftwareUpgrade fails to execute. +func (s *LegacyUpgradeTestSuite) TestNewGovUpgradeFailure() { + t := s.T() + sss := types.MsgSoftwareUpgrade{ + Authority: s.govModuleAddress, + Plan: types.Plan{ + Name: "v1", + Height: 20, + Info: "rough social consensus", + }, + } + dep := sdk.NewCoins(sdk.NewCoin(app.BondDenom, sdk.NewInt(1000000000000))) + acc := s.unusedAccount() + accAddr := getAddress(acc, s.cctx.Keyring) + msg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&sss}, dep, accAddr.String(), "") + require.NoError(t, err) + + // submit the transaction and wait a block for it to be included + txClient, err := testnode.NewTxClientFromContext(s.cctx) + require.NoError(t, err) + subCtx, cancel := context.WithTimeout(s.cctx.GoContext(), time.Minute) + defer cancel() + _, err = txClient.SubmitTx(subCtx, []sdk.Msg{msg}, blobfactory.DefaultTxOpts()...) + // As the type is not registered, the message will fail with unable to resolve type URL + require.Error(t, err) + code := err.(*user.BroadcastTxError).Code + require.EqualValues(t, 2, code, err.Error()) +} + +func (s *LegacyUpgradeTestSuite) TestIBCUpgradeFailure() { + t := s.T() + plan := types.Plan{ + Name: "v2", + Height: 20, + Info: "this should not pass", + } + upgradedClientState := &ibctmtypes.ClientState{} + + upgradeMsg, err := ibctypes.NewUpgradeProposal("Upgrade to v2!", "Upgrade to v2!", plan, upgradedClientState) + require.NoError(t, err) + + dep := sdk.NewCoins(sdk.NewCoin(app.BondDenom, sdk.NewInt(1000000000000))) + acc := s.unusedAccount() + accAddr := getAddress(acc, s.cctx.Keyring) + msg, err := v1beta1.NewMsgSubmitProposal(upgradeMsg, dep, accAddr) + require.NoError(t, err) + + // submit the transaction and wait a block for it to be included + txClient, err := testnode.NewTxClientFromContext(s.cctx) + require.NoError(t, err) + subCtx, cancel := context.WithTimeout(s.cctx.GoContext(), time.Minute) + defer cancel() + _, err = txClient.SubmitTx(subCtx, []sdk.Msg{msg}, blobfactory.DefaultTxOpts()...) + require.Error(t, err) + code := err.(*user.ExecutionError).Code + require.EqualValues(t, 9, code) // we're only submitting the tx, so we expect everything to work + assert.Contains(t, err.Error(), "ibc upgrade proposal not supported") +} + +func getAddress(account string, kr keyring.Keyring) sdk.AccAddress { + rec, err := kr.Key(account) + if err != nil { + panic(err) + } + addr, err := rec.GetAddress() + if err != nil { + panic(err) + } + return addr +} diff --git a/client/x/signal/module/depinject.go b/client/x/signal/module/depinject.go new file mode 100644 index 00000000..61b5c66a --- /dev/null +++ b/client/x/signal/module/depinject.go @@ -0,0 +1,61 @@ +package module + +import ( + "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/store" + "cosmossdk.io/depinject" + + "github.com/cosmos/cosmos-sdk/codec" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + "github.com/piplabs/story/client/x/signal/keeper" + "github.com/piplabs/story/client/x/signal/types" +) + +//nolint:gochecknoinits // depinject +func init() { + appmodule.Register( + &Module{}, + appmodule.Provide( + ProvideModule, + ), + ) +} + +type ModuleInputs struct { + depinject.In + + Config *Module + AccountKeeper types.AccountKeeper + StakingKeeper types.StakingKeeper + Cdc codec.Codec + StoreService store.KVStoreService +} + +type ModuleOutputs struct { + depinject.Out + + Keeper *keeper.Keeper + Module appmodule.AppModule +} + +func ProvideModule(in ModuleInputs) ModuleOutputs { + // default to governance authority if not provided + authority := authtypes.NewModuleAddress(govtypes.ModuleName) + if in.Config.GetAuthority() != "" { + authority = authtypes.NewModuleAddressOrBech32Address(in.Config.GetAuthority()) + } + + k := keeper.NewKeeper( + in.Cdc, + in.StoreService, + in.AccountKeeper, + in.StakingKeeper, + authority.String(), + ) + + m := NewAppModule(in.Cdc, k, in.AccountKeeper, &in.StakingKeeper) + + return ModuleOutputs{Keeper: k, Module: m} +} diff --git a/client/x/signal/module/module.go b/client/x/signal/module/module.go new file mode 100644 index 00000000..a0488724 --- /dev/null +++ b/client/x/signal/module/module.go @@ -0,0 +1,142 @@ +package module + +import ( + "context" + "cosmossdk.io/core/appmodule" + "encoding/json" + "github.com/piplabs/story/client/x/signal/keeper" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/piplabs/story/client/x/signal/cli" + "github.com/piplabs/story/client/x/signal/types" + "github.com/spf13/cobra" +) + +func init() { + types.RegisterLegacyAminoCodec(codec.NewLegacyAmino()) +} + +var ( + _ module.AppModuleBasic = AppModule{} + _ module.HasName = AppModule{} + _ module.HasServices = AppModule{} + + _ appmodule.AppModule = AppModule{} +) + +// AppModuleBasic implements the sdk.AppModuleBasic interface +type AppModuleBasic struct { + cdc codec.BinaryCodec +} + +func NewAppModuleBasic(cdc codec.BinaryCodec) AppModuleBasic { + return AppModuleBasic{cdc: cdc} +} + +// Name returns the ModuleName +func (AppModuleBasic) Name() string { + return types.ModuleName +} + +// RegisterLegacyAminoCodec registers the upgrade types on the LegacyAmino codec +func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + types.RegisterLegacyAminoCodec(cdc) +} + +// RegisterInterfaces registers the module's interface types on the InterfaceRegistry. +func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) { + types.RegisterInterfaces(registry) +} + +// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the upgrade module. +func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { + if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { + panic(err) + } +} + +// GetQueryCmd returns the CLI query commands for this module. +func (AppModuleBasic) GetQueryCmd() *cobra.Command { + return cli.GetQueryCmd() +} + +// GetTxCmd returns the CLI transaction commands for this module. +func (AppModuleBasic) GetTxCmd() *cobra.Command { + return cli.GetTxCmd() +} + +// ---------------------------------------------------------------------------- +// AppModule +// ---------------------------------------------------------------------------- + +// AppModule implements the AppModule interface that defines the inter-dependent methods that modules need to implement. + +// AppModule implements the sdk.AppModule interface +type AppModule struct { + AppModuleBasic + + keeper *keeper.Keeper + accountKeeper types.AccountKeeper + stakingKeeper *types.StakingKeeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule( + cdc codec.Codec, + keeper *keeper.Keeper, + accountKeeper types.AccountKeeper, + stakingKeeper *types.StakingKeeper, +) AppModule { + return AppModule{ + AppModuleBasic: NewAppModuleBasic(cdc), + keeper: keeper, + accountKeeper: accountKeeper, + stakingKeeper: stakingKeeper, + } +} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (AppModule) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (AppModule) IsAppModule() {} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (AppModule) ConsensusVersion() uint64 { return 1 } + +// RegisterInvariants does nothing because there are no invariants to enforce. +func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// QuerierRoute returns the query routing key used for ABCI queries. +func (AppModule) QuerierRoute() string { + return types.QuerierRoute +} + +// RegisterServices registers module services. +func (am AppModule) RegisterServices(cfg module.Configurator) { + types.RegisterMsgServer(cfg.MsgServer(), am.keeper) + types.RegisterQueryServer(cfg.QueryServer(), am.keeper) +} + +// DefaultGenesis returns an empty object. +func (AppModuleBasic) DefaultGenesis(_ codec.JSONCodec) json.RawMessage { + return []byte("{}") +} + +// ValidateGenesis is always successful, as we ignore the value. +func (AppModuleBasic) ValidateGenesis(_ codec.JSONCodec, _ client.TxEncodingConfig, _ json.RawMessage) error { + return nil +} + +// InitGenesis does nothing because there is no sense in serializing future upgrades. +func (AppModule) InitGenesis(_ sdk.Context, _ codec.JSONCodec, _ json.RawMessage) {} + +// ExportGenesis is always empty, as InitGenesis does nothing either. +func (am AppModule) ExportGenesis(_ sdk.Context, cdc codec.JSONCodec) json.RawMessage { + return am.DefaultGenesis(cdc) +} diff --git a/client/x/signal/module/module.proto b/client/x/signal/module/module.proto new file mode 100644 index 00000000..db5af3b6 --- /dev/null +++ b/client/x/signal/module/module.proto @@ -0,0 +1,16 @@ +syntax = "proto3"; +package client.x.signal.module; + +import "cosmos/app/v1alpha1/module.proto"; + +option go_package = "client/x/signal/module"; + +// ModuleName is the config object for the signal module. +message Module { + option (cosmos.app.v1alpha1.module) = { + go_import: "github.com/piplabs/story/client/x/signal" + }; + + // authority defines the custom module authority. If not set, defaults to the governance module. + string authority = 1; +} diff --git a/client/x/signal/module/module.pulsar.go b/client/x/signal/module/module.pulsar.go new file mode 100644 index 00000000..73c71948 --- /dev/null +++ b/client/x/signal/module/module.pulsar.go @@ -0,0 +1,578 @@ +// Code generated by protoc-gen-go-pulsar. DO NOT EDIT. +package module + +import ( + _ "cosmossdk.io/api/cosmos/app/v1alpha1" + fmt "fmt" + runtime "github.com/cosmos/cosmos-proto/runtime" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoiface "google.golang.org/protobuf/runtime/protoiface" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + io "io" + reflect "reflect" + sync "sync" +) + +var ( + md_Module protoreflect.MessageDescriptor + fd_Module_authority protoreflect.FieldDescriptor +) + +func init() { + file_client_x_signal_module_module_proto_init() + md_Module = File_client_x_signal_module_module_proto.Messages().ByName("Module") + fd_Module_authority = md_Module.Fields().ByName("authority") +} + +var _ protoreflect.Message = (*fastReflection_Module)(nil) + +type fastReflection_Module Module + +func (x *Module) ProtoReflect() protoreflect.Message { + return (*fastReflection_Module)(x) +} + +func (x *Module) slowProtoReflect() protoreflect.Message { + mi := &file_client_x_signal_module_module_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +var _fastReflection_Module_messageType fastReflection_Module_messageType +var _ protoreflect.MessageType = fastReflection_Module_messageType{} + +type fastReflection_Module_messageType struct{} + +func (x fastReflection_Module_messageType) Zero() protoreflect.Message { + return (*fastReflection_Module)(nil) +} +func (x fastReflection_Module_messageType) New() protoreflect.Message { + return new(fastReflection_Module) +} +func (x fastReflection_Module_messageType) Descriptor() protoreflect.MessageDescriptor { + return md_Module +} + +// Descriptor returns message descriptor, which contains only the protobuf +// type information for the message. +func (x *fastReflection_Module) Descriptor() protoreflect.MessageDescriptor { + return md_Module +} + +// Type returns the message type, which encapsulates both Go and protobuf +// type information. If the Go type information is not needed, +// it is recommended that the message descriptor be used instead. +func (x *fastReflection_Module) Type() protoreflect.MessageType { + return _fastReflection_Module_messageType +} + +// New returns a newly allocated and mutable empty message. +func (x *fastReflection_Module) New() protoreflect.Message { + return new(fastReflection_Module) +} + +// Interface unwraps the message reflection interface and +// returns the underlying ProtoMessage interface. +func (x *fastReflection_Module) Interface() protoreflect.ProtoMessage { + return (*Module)(x) +} + +// Range iterates over every populated field in an undefined order, +// calling f for each field descriptor and value encountered. +// Range returns immediately if f returns false. +// While iterating, mutating operations may only be performed +// on the current field descriptor. +func (x *fastReflection_Module) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) { + if x.Authority != "" { + value := protoreflect.ValueOfString(x.Authority) + if !f(fd_Module_authority, value) { + return + } + } +} + +// Has reports whether a field is populated. +// +// Some fields have the property of nullability where it is possible to +// distinguish between the default value of a field and whether the field +// was explicitly populated with the default value. Singular message fields, +// member fields of a oneof, and proto2 scalar fields are nullable. Such +// fields are populated only if explicitly set. +// +// In other cases (aside from the nullable cases above), +// a proto3 scalar field is populated if it contains a non-zero value, and +// a repeated field is populated if it is non-empty. +func (x *fastReflection_Module) Has(fd protoreflect.FieldDescriptor) bool { + switch fd.FullName() { + case "client.x.signal.module.Module.authority": + return x.Authority != "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: client.x.signal.module.Module")) + } + panic(fmt.Errorf("message client.x.signal.module.Module does not contain field %s", fd.FullName())) + } +} + +// Clear clears the field such that a subsequent Has call reports false. +// +// Clearing an extension field clears both the extension type and value +// associated with the given field number. +// +// Clear is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Module) Clear(fd protoreflect.FieldDescriptor) { + switch fd.FullName() { + case "client.x.signal.module.Module.authority": + x.Authority = "" + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: client.x.signal.module.Module")) + } + panic(fmt.Errorf("message client.x.signal.module.Module does not contain field %s", fd.FullName())) + } +} + +// Get retrieves the value for a field. +// +// For unpopulated scalars, it returns the default value, where +// the default value of a bytes scalar is guaranteed to be a copy. +// For unpopulated composite types, it returns an empty, read-only view +// of the value; to obtain a mutable reference, use Mutable. +func (x *fastReflection_Module) Get(descriptor protoreflect.FieldDescriptor) protoreflect.Value { + switch descriptor.FullName() { + case "client.x.signal.module.Module.authority": + value := x.Authority + return protoreflect.ValueOfString(value) + default: + if descriptor.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: client.x.signal.module.Module")) + } + panic(fmt.Errorf("message client.x.signal.module.Module does not contain field %s", descriptor.FullName())) + } +} + +// Set stores the value for a field. +// +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType. +// When setting a composite type, it is unspecified whether the stored value +// aliases the source's memory in any way. If the composite value is an +// empty, read-only value, then it panics. +// +// Set is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Module) Set(fd protoreflect.FieldDescriptor, value protoreflect.Value) { + switch fd.FullName() { + case "client.x.signal.module.Module.authority": + x.Authority = value.Interface().(string) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: client.x.signal.module.Module")) + } + panic(fmt.Errorf("message client.x.signal.module.Module does not contain field %s", fd.FullName())) + } +} + +// Mutable returns a mutable reference to a composite type. +// +// If the field is unpopulated, it may allocate a composite value. +// For a field belonging to a oneof, it implicitly clears any other field +// that may be currently set within the same oneof. +// For extension fields, it implicitly stores the provided ExtensionType +// if not already stored. +// It panics if the field does not contain a composite type. +// +// Mutable is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Module) Mutable(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "client.x.signal.module.Module.authority": + panic(fmt.Errorf("field authority of message client.x.signal.module.Module is not mutable")) + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: client.x.signal.module.Module")) + } + panic(fmt.Errorf("message client.x.signal.module.Module does not contain field %s", fd.FullName())) + } +} + +// NewField returns a new value that is assignable to the field +// for the given descriptor. For scalars, this returns the default value. +// For lists, maps, and messages, this returns a new, empty, mutable value. +func (x *fastReflection_Module) NewField(fd protoreflect.FieldDescriptor) protoreflect.Value { + switch fd.FullName() { + case "client.x.signal.module.Module.authority": + return protoreflect.ValueOfString("") + default: + if fd.IsExtension() { + panic(fmt.Errorf("proto3 declared messages do not support extensions: client.x.signal.module.Module")) + } + panic(fmt.Errorf("message client.x.signal.module.Module does not contain field %s", fd.FullName())) + } +} + +// WhichOneof reports which field within the oneof is populated, +// returning nil if none are populated. +// It panics if the oneof descriptor does not belong to this message. +func (x *fastReflection_Module) WhichOneof(d protoreflect.OneofDescriptor) protoreflect.FieldDescriptor { + switch d.FullName() { + default: + panic(fmt.Errorf("%s is not a oneof field in client.x.signal.module.Module", d.FullName())) + } + panic("unreachable") +} + +// GetUnknown retrieves the entire list of unknown fields. +// The caller may only mutate the contents of the RawFields +// if the mutated bytes are stored back into the message with SetUnknown. +func (x *fastReflection_Module) GetUnknown() protoreflect.RawFields { + return x.unknownFields +} + +// SetUnknown stores an entire list of unknown fields. +// The raw fields must be syntactically valid according to the wire format. +// An implementation may panic if this is not the case. +// Once stored, the caller must not mutate the content of the RawFields. +// An empty RawFields may be passed to clear the fields. +// +// SetUnknown is a mutating operation and unsafe for concurrent use. +func (x *fastReflection_Module) SetUnknown(fields protoreflect.RawFields) { + x.unknownFields = fields +} + +// IsValid reports whether the message is valid. +// +// An invalid message is an empty, read-only value. +// +// An invalid message often corresponds to a nil pointer of the concrete +// message type, but the details are implementation dependent. +// Validity is not part of the protobuf data model, and may not +// be preserved in marshaling or other operations. +func (x *fastReflection_Module) IsValid() bool { + return x != nil +} + +// ProtoMethods returns optional fastReflectionFeature-path implementations of various operations. +// This method may return nil. +// +// The returned methods type is identical to +// "google.golang.org/protobuf/runtime/protoiface".Methods. +// Consult the protoiface package documentation for details. +func (x *fastReflection_Module) ProtoMethods() *protoiface.Methods { + size := func(input protoiface.SizeInput) protoiface.SizeOutput { + x := input.Message.Interface().(*Module) + if x == nil { + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: 0, + } + } + options := runtime.SizeInputToOptions(input) + _ = options + var n int + var l int + _ = l + l = len(x.Authority) + if l > 0 { + n += 1 + l + runtime.Sov(uint64(l)) + } + if x.unknownFields != nil { + n += len(x.unknownFields) + } + return protoiface.SizeOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Size: n, + } + } + + marshal := func(input protoiface.MarshalInput) (protoiface.MarshalOutput, error) { + x := input.Message.Interface().(*Module) + if x == nil { + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + options := runtime.MarshalInputToOptions(input) + _ = options + size := options.Size(x) + dAtA := make([]byte, size) + i := len(dAtA) + _ = i + var l int + _ = l + if x.unknownFields != nil { + i -= len(x.unknownFields) + copy(dAtA[i:], x.unknownFields) + } + if len(x.Authority) > 0 { + i -= len(x.Authority) + copy(dAtA[i:], x.Authority) + i = runtime.EncodeVarint(dAtA, i, uint64(len(x.Authority))) + i-- + dAtA[i] = 0xa + } + if input.Buf != nil { + input.Buf = append(input.Buf, dAtA...) + } else { + input.Buf = dAtA + } + return protoiface.MarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Buf: input.Buf, + }, nil + } + unmarshal := func(input protoiface.UnmarshalInput) (protoiface.UnmarshalOutput, error) { + x := input.Message.Interface().(*Module) + if x == nil { + return protoiface.UnmarshalOutput{ + NoUnkeyedLiterals: input.NoUnkeyedLiterals, + Flags: input.Flags, + }, nil + } + options := runtime.UnmarshalInputToOptions(input) + _ = options + dAtA := input.Buf + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, 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 protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Module: wiretype end group for non-group") + } + if fieldNum <= 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: Module: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field Authority", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow + } + if iNdEx >= l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if postIndex > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + x.Authority = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := runtime.Skip(dAtA[iNdEx:]) + if err != nil { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrInvalidLength + } + if (iNdEx + skippy) > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + if !options.DiscardUnknown { + x.unknownFields = append(x.unknownFields, dAtA[iNdEx:iNdEx+skippy]...) + } + iNdEx += skippy + } + } + + if iNdEx > l { + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, io.ErrUnexpectedEOF + } + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, nil + } + return &protoiface.Methods{ + NoUnkeyedLiterals: struct{}{}, + Flags: protoiface.SupportMarshalDeterministic | protoiface.SupportUnmarshalDiscardUnknown, + Size: size, + Marshal: marshal, + Unmarshal: unmarshal, + Merge: nil, + CheckInitialized: nil, + } +} + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.0 +// protoc (unknown) +// source: client/x/signal/module/module.proto + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// ModuleName is the config object for the signal module. +type Module struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // authority defines the custom module authority. If not set, defaults to the governance module. + Authority string `protobuf:"bytes,1,opt,name=authority,proto3" json:"authority,omitempty"` +} + +func (x *Module) Reset() { + *x = Module{} + if protoimpl.UnsafeEnabled { + mi := &file_client_x_signal_module_module_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Module) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Module) ProtoMessage() {} + +// Deprecated: Use Module.ProtoReflect.Descriptor instead. +func (*Module) Descriptor() ([]byte, []int) { + return file_client_x_signal_module_module_proto_rawDescGZIP(), []int{0} +} + +func (x *Module) GetAuthority() string { + if x != nil { + return x.Authority + } + return "" +} + +var File_client_x_signal_module_module_proto protoreflect.FileDescriptor + +var file_client_x_signal_module_module_proto_rawDesc = []byte{ + 0x0a, 0x23, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2f, 0x78, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x16, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x78, 0x2e, + 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x1a, 0x20, 0x63, + 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2f, 0x61, 0x70, 0x70, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70, 0x68, + 0x61, 0x31, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x58, 0x0a, 0x06, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x75, 0x74, + 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x75, + 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x3a, 0x30, 0xba, 0xc0, 0x96, 0xda, 0x01, 0x2a, 0x0a, + 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x69, 0x70, 0x6c, + 0x61, 0x62, 0x73, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x2f, 0x78, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x42, 0xce, 0x01, 0x0a, 0x1a, 0x63, 0x6f, + 0x6d, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x78, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x61, + 0x6c, 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x42, 0x0b, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x27, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, + 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x2f, 0x78, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x2f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0xa2, 0x02, 0x04, 0x43, 0x58, 0x53, 0x4d, 0xaa, 0x02, 0x16, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x2e, 0x58, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0xca, 0x02, 0x16, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5c, 0x58, 0x5c, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x5c, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0xe2, 0x02, 0x22, 0x43, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x5c, 0x58, 0x5c, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5c, 0x4d, 0x6f, 0x64, 0x75, + 0x6c, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, + 0x19, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x3a, 0x3a, 0x58, 0x3a, 0x3a, 0x53, 0x69, 0x67, 0x6e, + 0x61, 0x6c, 0x3a, 0x3a, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, +} + +var ( + file_client_x_signal_module_module_proto_rawDescOnce sync.Once + file_client_x_signal_module_module_proto_rawDescData = file_client_x_signal_module_module_proto_rawDesc +) + +func file_client_x_signal_module_module_proto_rawDescGZIP() []byte { + file_client_x_signal_module_module_proto_rawDescOnce.Do(func() { + file_client_x_signal_module_module_proto_rawDescData = protoimpl.X.CompressGZIP(file_client_x_signal_module_module_proto_rawDescData) + }) + return file_client_x_signal_module_module_proto_rawDescData +} + +var file_client_x_signal_module_module_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_client_x_signal_module_module_proto_goTypes = []interface{}{ + (*Module)(nil), // 0: client.x.signal.module.Module +} +var file_client_x_signal_module_module_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_client_x_signal_module_module_proto_init() } +func file_client_x_signal_module_module_proto_init() { + if File_client_x_signal_module_module_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_client_x_signal_module_module_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Module); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_client_x_signal_module_module_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_client_x_signal_module_module_proto_goTypes, + DependencyIndexes: file_client_x_signal_module_module_proto_depIdxs, + MessageInfos: file_client_x_signal_module_module_proto_msgTypes, + }.Build() + File_client_x_signal_module_module_proto = out.File + file_client_x_signal_module_module_proto_rawDesc = nil + file_client_x_signal_module_module_proto_goTypes = nil + file_client_x_signal_module_module_proto_depIdxs = nil +} diff --git a/client/x/signal/types/codec.go b/client/x/signal/types/codec.go new file mode 100644 index 00000000..49a08996 --- /dev/null +++ b/client/x/signal/types/codec.go @@ -0,0 +1,23 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" +) + +// RegisterLegacyAminoCodec registers the upgrade types on the provided +// LegacyAmino codec. +func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + cdc.RegisterConcrete(&MsgTryUpgrade{}, URLMsgTryUpgrade, nil) + cdc.RegisterConcrete(&MsgSignalVersion{}, URLMsgSignalVersion, nil) +} + +// RegisterInterfaces registers the upgrade module types on the provided +// registry. +func RegisterInterfaces(registry codectypes.InterfaceRegistry) { + registry.RegisterImplementations((*sdk.Msg)(nil), &MsgTryUpgrade{}) + registry.RegisterImplementations((*sdk.Msg)(nil), &MsgSignalVersion{}) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) +} diff --git a/client/x/signal/types/errors.go b/client/x/signal/types/errors.go new file mode 100644 index 00000000..0dc1d5c3 --- /dev/null +++ b/client/x/signal/types/errors.go @@ -0,0 +1,11 @@ +package types + +import ( + "cosmossdk.io/errors" +) + +var ( + ErrInvalidSignalVersion = errors.Register(ModuleName, 1, "invalid signal version because signal version can not be less than the current version") + ErrInvalidUpgradeVersion = errors.Register(ModuleName, 3, "invalid upgrade version") + ErrUpgradePending = errors.Register(ModuleName, 2, "upgrade is already pending") +) diff --git a/client/x/signal/types/expected_keepers.go b/client/x/signal/types/expected_keepers.go new file mode 100644 index 00000000..070e24f7 --- /dev/null +++ b/client/x/signal/types/expected_keepers.go @@ -0,0 +1,31 @@ +package types + +import ( + "context" + "cosmossdk.io/math" + + "cosmossdk.io/core/address" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// AccountKeeper defines the expected account keeper (noalias). +type AccountKeeper interface { + AddressCodec() address.Codec + HasAccount(ctx context.Context, addr sdk.AccAddress) bool + NewAccountWithAddress(ctx context.Context, addr sdk.AccAddress) sdk.AccountI + SetAccount(ctx context.Context, acc sdk.AccountI) + GetModuleAddress(moduleName string) sdk.AccAddress + // only used for simulation + GetAccount(ctx context.Context, addr sdk.AccAddress) sdk.AccountI + IterateAccounts(ctx context.Context, process func(sdk.AccountI) (stop bool)) + GetModuleAccount(ctx context.Context, moduleName string) sdk.ModuleAccountI + SetModuleAccount(ctx context.Context, modAcc sdk.ModuleAccountI) +} + +type StakingKeeper interface { + GetLastValidatorPower(ctx context.Context, addr sdk.ValAddress) (power int64, err error) + GetValidator(ctx context.Context, addr sdk.ValAddress) (validator stakingtypes.Validator, err error) + GetLastTotalPower(ctx context.Context) (math.Int, error) +} diff --git a/client/x/signal/types/keys.go b/client/x/signal/types/keys.go new file mode 100644 index 00000000..84e4c6b0 --- /dev/null +++ b/client/x/signal/types/keys.go @@ -0,0 +1,26 @@ +package types + +const ( + // ModuleName is the name of the signal module. + ModuleName = "signal" + + // StoreKey is the string store representation. + StoreKey = ModuleName + + // QuerierRoute is the querier route key for the signal module. + QuerierRoute = ModuleName + + // RouterKey is the msg router key for the signal module. + RouterKey = ModuleName +) + +// KVStore keys. +var ( + // UpgradeKey is the key in the signal store used to persist an upgrade if one is pending. + UpgradeKey = []byte{0x00} + + // FirstSignalKey is used as a divider to separate the UpgradeKey from all + // the keys associated with signals from validators. In practice, this key + // isn't expected to be set or retrieved. + FirstSignalKey = []byte{0x000} +) diff --git a/client/x/signal/types/msgs.go b/client/x/signal/types/msgs.go new file mode 100644 index 00000000..6295af3a --- /dev/null +++ b/client/x/signal/types/msgs.go @@ -0,0 +1,91 @@ +package types + +import ( + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" +) + +const ( + URLMsgSignalVersion = "/client.x.signal.Msg/SignalVersion" + URLMsgTryUpgrade = "/client.x.signal.Msg/TryUpgrade" +) + +var ( + _ sdk.Msg = &MsgSignalVersion{} + _ sdk.Msg = &MsgTryUpgrade{} + _ legacytx.LegacyMsg = &MsgSignalVersion{} + _ legacytx.LegacyMsg = &MsgTryUpgrade{} +) + +var ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry()) + +func NewMsgSignalVersion(valAddress sdk.ValAddress, version uint64) *MsgSignalVersion { + return &MsgSignalVersion{ + ValidatorAddress: valAddress.String(), + Version: version, + } +} + +func (msg *MsgSignalVersion) GetSigners() []sdk.AccAddress { + valAddr, err := sdk.ValAddressFromBech32(msg.ValidatorAddress) + if err != nil { + panic(err) + } + return []sdk.AccAddress{sdk.AccAddress(valAddr)} +} + +func (msg *MsgSignalVersion) ValidateBasic() error { + _, err := sdk.ValAddressFromBech32(msg.ValidatorAddress) + return err +} + +// GetSignBytes implements legacytx.LegacyMsg. +func (msg *MsgSignalVersion) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +// Route implements legacytx.LegacyMsg. +func (msg *MsgSignalVersion) Route() string { + return RouterKey +} + +// Type implements legacytx.LegacyMsg. +func (msg *MsgSignalVersion) Type() string { + return URLMsgSignalVersion +} + +func NewMsgTryUpgrade(signer sdk.AccAddress) *MsgTryUpgrade { + return &MsgTryUpgrade{ + Signer: signer.String(), + } +} + +func (msg *MsgTryUpgrade) GetSigners() []sdk.AccAddress { + addr, err := sdk.AccAddressFromBech32(msg.Signer) + if err != nil { + panic(err) + } + return []sdk.AccAddress{addr} +} + +func (msg *MsgTryUpgrade) ValidateBasic() error { + _, err := sdk.AccAddressFromBech32(msg.Signer) + return err +} + +// GetSignBytes implements legacytx.LegacyMsg. +func (msg *MsgTryUpgrade) GetSignBytes() []byte { + return sdk.MustSortJSON(ModuleCdc.MustMarshalJSON(msg)) +} + +// Route implements legacytx.LegacyMsg. +func (msg *MsgTryUpgrade) Route() string { + return RouterKey +} + +// Type implements legacytx.LegacyMsg. +func (msg *MsgTryUpgrade) Type() string { + return URLMsgTryUpgrade +} diff --git a/client/x/signal/types/query.pb.go b/client/x/signal/types/query.pb.go new file mode 100644 index 00000000..c2aad2e2 --- /dev/null +++ b/client/x/signal/types/query.pb.go @@ -0,0 +1,969 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: client/x/signal/types/query.proto + +package types + +import ( + context "context" + fmt "fmt" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// QueryVersionTallyRequest is the request type for the VersionTally query. +type QueryVersionTallyRequest struct { + Version uint64 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"` +} + +func (m *QueryVersionTallyRequest) Reset() { *m = QueryVersionTallyRequest{} } +func (m *QueryVersionTallyRequest) String() string { return proto.CompactTextString(m) } +func (*QueryVersionTallyRequest) ProtoMessage() {} +func (*QueryVersionTallyRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_c2b5e83c670e32e0, []int{0} +} +func (m *QueryVersionTallyRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryVersionTallyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryVersionTallyRequest.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 *QueryVersionTallyRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryVersionTallyRequest.Merge(m, src) +} +func (m *QueryVersionTallyRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryVersionTallyRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryVersionTallyRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryVersionTallyRequest proto.InternalMessageInfo + +func (m *QueryVersionTallyRequest) GetVersion() uint64 { + if m != nil { + return m.Version + } + return 0 +} + +// QueryVersionTallyResponse is the response type for the VersionTally query. +type QueryVersionTallyResponse struct { + VotingPower uint64 `protobuf:"varint,1,opt,name=voting_power,json=votingPower,proto3" json:"voting_power,omitempty"` + ThresholdPower uint64 `protobuf:"varint,2,opt,name=threshold_power,json=thresholdPower,proto3" json:"threshold_power,omitempty"` + TotalVotingPower uint64 `protobuf:"varint,3,opt,name=total_voting_power,json=totalVotingPower,proto3" json:"total_voting_power,omitempty"` +} + +func (m *QueryVersionTallyResponse) Reset() { *m = QueryVersionTallyResponse{} } +func (m *QueryVersionTallyResponse) String() string { return proto.CompactTextString(m) } +func (*QueryVersionTallyResponse) ProtoMessage() {} +func (*QueryVersionTallyResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_c2b5e83c670e32e0, []int{1} +} +func (m *QueryVersionTallyResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryVersionTallyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryVersionTallyResponse.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 *QueryVersionTallyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryVersionTallyResponse.Merge(m, src) +} +func (m *QueryVersionTallyResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryVersionTallyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryVersionTallyResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryVersionTallyResponse proto.InternalMessageInfo + +func (m *QueryVersionTallyResponse) GetVotingPower() uint64 { + if m != nil { + return m.VotingPower + } + return 0 +} + +func (m *QueryVersionTallyResponse) GetThresholdPower() uint64 { + if m != nil { + return m.ThresholdPower + } + return 0 +} + +func (m *QueryVersionTallyResponse) GetTotalVotingPower() uint64 { + if m != nil { + return m.TotalVotingPower + } + return 0 +} + +// QueryGetUpgradeRequest is the request type for the GetUpgrade query. +type QueryGetUpgradeRequest struct { +} + +func (m *QueryGetUpgradeRequest) Reset() { *m = QueryGetUpgradeRequest{} } +func (m *QueryGetUpgradeRequest) String() string { return proto.CompactTextString(m) } +func (*QueryGetUpgradeRequest) ProtoMessage() {} +func (*QueryGetUpgradeRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_c2b5e83c670e32e0, []int{2} +} +func (m *QueryGetUpgradeRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryGetUpgradeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryGetUpgradeRequest.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 *QueryGetUpgradeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryGetUpgradeRequest.Merge(m, src) +} +func (m *QueryGetUpgradeRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryGetUpgradeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryGetUpgradeRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryGetUpgradeRequest proto.InternalMessageInfo + +// QueryGetUpgradeResponse is the response type for the GetUpgrade query. +type QueryGetUpgradeResponse struct { + Upgrade *Upgrade `protobuf:"bytes,1,opt,name=upgrade,proto3" json:"upgrade,omitempty"` +} + +func (m *QueryGetUpgradeResponse) Reset() { *m = QueryGetUpgradeResponse{} } +func (m *QueryGetUpgradeResponse) String() string { return proto.CompactTextString(m) } +func (*QueryGetUpgradeResponse) ProtoMessage() {} +func (*QueryGetUpgradeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_c2b5e83c670e32e0, []int{3} +} +func (m *QueryGetUpgradeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryGetUpgradeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryGetUpgradeResponse.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 *QueryGetUpgradeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryGetUpgradeResponse.Merge(m, src) +} +func (m *QueryGetUpgradeResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryGetUpgradeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryGetUpgradeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryGetUpgradeResponse proto.InternalMessageInfo + +func (m *QueryGetUpgradeResponse) GetUpgrade() *Upgrade { + if m != nil { + return m.Upgrade + } + return nil +} + +func init() { + proto.RegisterType((*QueryVersionTallyRequest)(nil), "client.x.signal.types.QueryVersionTallyRequest") + proto.RegisterType((*QueryVersionTallyResponse)(nil), "client.x.signal.types.QueryVersionTallyResponse") + proto.RegisterType((*QueryGetUpgradeRequest)(nil), "client.x.signal.types.QueryGetUpgradeRequest") + proto.RegisterType((*QueryGetUpgradeResponse)(nil), "client.x.signal.types.QueryGetUpgradeResponse") +} + +func init() { proto.RegisterFile("client/x/signal/types/query.proto", fileDescriptor_c2b5e83c670e32e0) } + +var fileDescriptor_c2b5e83c670e32e0 = []byte{ + // 388 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x92, 0xc1, 0x4e, 0x32, 0x31, + 0x14, 0x85, 0x29, 0xff, 0xaf, 0x24, 0x85, 0x88, 0x36, 0x41, 0x86, 0x89, 0x19, 0x65, 0x5c, 0xe8, + 0x42, 0xa7, 0x06, 0x5d, 0xb8, 0x76, 0xe3, 0x56, 0x51, 0x59, 0xb8, 0x21, 0xa3, 0x34, 0xc3, 0x24, + 0x93, 0x76, 0x98, 0x16, 0x84, 0x18, 0x37, 0xc6, 0x07, 0x30, 0x1a, 0x9f, 0xc0, 0x97, 0x71, 0x49, + 0xe2, 0xc6, 0xa5, 0x01, 0x1f, 0xc4, 0xd0, 0x76, 0x40, 0xc3, 0x60, 0x58, 0xf6, 0xde, 0xef, 0x9e, + 0x9e, 0x7b, 0x5a, 0x58, 0xbe, 0x0e, 0x7c, 0x42, 0x05, 0xee, 0x62, 0xee, 0x7b, 0xd4, 0x0d, 0xb0, + 0xe8, 0x85, 0x84, 0xe3, 0x56, 0x9b, 0x44, 0x3d, 0x27, 0x8c, 0x98, 0x60, 0xa8, 0xa0, 0x10, 0xa7, + 0xeb, 0x28, 0xc4, 0x91, 0x88, 0xb9, 0xe6, 0x31, 0xe6, 0x05, 0x04, 0xbb, 0xa1, 0x8f, 0x5d, 0x4a, + 0x99, 0x70, 0x85, 0xcf, 0x28, 0x57, 0x43, 0xe6, 0x66, 0xb2, 0x6e, 0x3b, 0xf4, 0x22, 0xb7, 0x41, + 0x14, 0x64, 0x1f, 0x40, 0xe3, 0x74, 0x74, 0x51, 0x8d, 0x44, 0xdc, 0x67, 0xf4, 0xdc, 0x0d, 0x82, + 0x5e, 0x95, 0xb4, 0xda, 0x84, 0x0b, 0x64, 0xc0, 0x4c, 0x47, 0x95, 0x0d, 0xb0, 0x01, 0xb6, 0xff, + 0x57, 0xe3, 0xa3, 0xfd, 0x02, 0x60, 0x29, 0x61, 0x8c, 0x87, 0x8c, 0x72, 0x82, 0xca, 0x30, 0xd7, + 0x61, 0xc2, 0xa7, 0x5e, 0x3d, 0x64, 0x37, 0x24, 0xd2, 0xc3, 0x59, 0x55, 0x3b, 0x19, 0x95, 0xd0, + 0x16, 0xcc, 0x8b, 0x66, 0x44, 0x78, 0x93, 0x05, 0x0d, 0x4d, 0xa5, 0x25, 0xb5, 0x34, 0x2e, 0x2b, + 0x70, 0x07, 0x22, 0xc1, 0x84, 0x1b, 0xd4, 0x7f, 0x29, 0xfe, 0x93, 0xec, 0xb2, 0xec, 0xd4, 0x26, + 0xb2, 0xb6, 0x01, 0x57, 0xa5, 0xad, 0x63, 0x22, 0x2e, 0xd4, 0x9a, 0x7a, 0x17, 0xfb, 0x0c, 0x16, + 0xa7, 0x3a, 0xda, 0xee, 0x21, 0xcc, 0xe8, 0x4c, 0xa4, 0xd3, 0x6c, 0xc5, 0x72, 0x12, 0xe3, 0x76, + 0xe2, 0xc1, 0x18, 0xaf, 0xbc, 0xa6, 0xe1, 0x82, 0x54, 0x45, 0x4f, 0x00, 0xe6, 0x7e, 0x66, 0x81, + 0xf0, 0x0c, 0x8d, 0x59, 0x61, 0x9b, 0x7b, 0xf3, 0x0f, 0x28, 0xdf, 0xf6, 0xfa, 0xfd, 0xfb, 0xd7, + 0x73, 0xba, 0x84, 0x8a, 0xe3, 0xf7, 0x1d, 0xb5, 0xf1, 0xad, 0x7e, 0xa4, 0x3b, 0xf4, 0x00, 0x20, + 0x9c, 0xec, 0x8b, 0x76, 0xff, 0xba, 0x61, 0x2a, 0x31, 0xd3, 0x99, 0x17, 0xd7, 0x76, 0x8a, 0xd2, + 0xce, 0x0a, 0xca, 0xc7, 0x76, 0x74, 0x4a, 0x47, 0xf8, 0x6d, 0x60, 0x81, 0xfe, 0xc0, 0x02, 0x9f, + 0x03, 0x0b, 0x3c, 0x0e, 0xad, 0x54, 0x7f, 0x68, 0xa5, 0x3e, 0x86, 0x56, 0xea, 0xb2, 0x90, 0xf8, + 0x43, 0xaf, 0x16, 0xe5, 0xd7, 0xdc, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xb9, 0x38, 0xea, 0x4f, + 0x19, 0x03, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// QueryClient is the client API for Query service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type QueryClient interface { + // VersionTally enables a client to query for the tally of voting power that + // has signalled for a particular version. + VersionTally(ctx context.Context, in *QueryVersionTallyRequest, opts ...grpc.CallOption) (*QueryVersionTallyResponse, error) + // GetUpgrade enables a client to query for upgrade information if an upgrade is pending. + // The response will be empty if no upgrade is pending. + GetUpgrade(ctx context.Context, in *QueryGetUpgradeRequest, opts ...grpc.CallOption) (*QueryGetUpgradeResponse, error) +} + +type queryClient struct { + cc grpc1.ClientConn +} + +func NewQueryClient(cc grpc1.ClientConn) QueryClient { + return &queryClient{cc} +} + +func (c *queryClient) VersionTally(ctx context.Context, in *QueryVersionTallyRequest, opts ...grpc.CallOption) (*QueryVersionTallyResponse, error) { + out := new(QueryVersionTallyResponse) + err := c.cc.Invoke(ctx, "/client.x.signal.types.Query/VersionTally", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) GetUpgrade(ctx context.Context, in *QueryGetUpgradeRequest, opts ...grpc.CallOption) (*QueryGetUpgradeResponse, error) { + out := new(QueryGetUpgradeResponse) + err := c.cc.Invoke(ctx, "/client.x.signal.types.Query/GetUpgrade", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// QueryServer is the server API for Query service. +type QueryServer interface { + // VersionTally enables a client to query for the tally of voting power that + // has signalled for a particular version. + VersionTally(context.Context, *QueryVersionTallyRequest) (*QueryVersionTallyResponse, error) + // GetUpgrade enables a client to query for upgrade information if an upgrade is pending. + // The response will be empty if no upgrade is pending. + GetUpgrade(context.Context, *QueryGetUpgradeRequest) (*QueryGetUpgradeResponse, error) +} + +// UnimplementedQueryServer can be embedded to have forward compatible implementations. +type UnimplementedQueryServer struct { +} + +func (*UnimplementedQueryServer) VersionTally(ctx context.Context, req *QueryVersionTallyRequest) (*QueryVersionTallyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method VersionTally not implemented") +} +func (*UnimplementedQueryServer) GetUpgrade(ctx context.Context, req *QueryGetUpgradeRequest) (*QueryGetUpgradeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUpgrade not implemented") +} + +func RegisterQueryServer(s grpc1.Server, srv QueryServer) { + s.RegisterService(&_Query_serviceDesc, srv) +} + +func _Query_VersionTally_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryVersionTallyRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).VersionTally(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/client.x.signal.types.Query/VersionTally", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).VersionTally(ctx, req.(*QueryVersionTallyRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_GetUpgrade_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryGetUpgradeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).GetUpgrade(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/client.x.signal.types.Query/GetUpgrade", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).GetUpgrade(ctx, req.(*QueryGetUpgradeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Query_serviceDesc = grpc.ServiceDesc{ + ServiceName: "client.x.signal.types.Query", + HandlerType: (*QueryServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "VersionTally", + Handler: _Query_VersionTally_Handler, + }, + { + MethodName: "GetUpgrade", + Handler: _Query_GetUpgrade_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "client/x/signal/types/query.proto", +} + +func (m *QueryVersionTallyRequest) 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 *QueryVersionTallyRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryVersionTallyRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Version != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryVersionTallyResponse) 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 *QueryVersionTallyResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryVersionTallyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.TotalVotingPower != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.TotalVotingPower)) + i-- + dAtA[i] = 0x18 + } + if m.ThresholdPower != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.ThresholdPower)) + i-- + dAtA[i] = 0x10 + } + if m.VotingPower != 0 { + i = encodeVarintQuery(dAtA, i, uint64(m.VotingPower)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *QueryGetUpgradeRequest) 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 *QueryGetUpgradeRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryGetUpgradeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *QueryGetUpgradeResponse) 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 *QueryGetUpgradeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryGetUpgradeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Upgrade != nil { + { + size, err := m.Upgrade.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintQuery(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { + offset -= sovQuery(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *QueryVersionTallyRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Version != 0 { + n += 1 + sovQuery(uint64(m.Version)) + } + return n +} + +func (m *QueryVersionTallyResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.VotingPower != 0 { + n += 1 + sovQuery(uint64(m.VotingPower)) + } + if m.ThresholdPower != 0 { + n += 1 + sovQuery(uint64(m.ThresholdPower)) + } + if m.TotalVotingPower != 0 { + n += 1 + sovQuery(uint64(m.TotalVotingPower)) + } + return n +} + +func (m *QueryGetUpgradeRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *QueryGetUpgradeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Upgrade != nil { + l = m.Upgrade.Size() + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryVersionTallyRequest) 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 ErrIntOverflowQuery + } + 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: QueryVersionTallyRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryVersionTallyRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryVersionTallyResponse) 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 ErrIntOverflowQuery + } + 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: QueryVersionTallyResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryVersionTallyResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field VotingPower", wireType) + } + m.VotingPower = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.VotingPower |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ThresholdPower", wireType) + } + m.ThresholdPower = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ThresholdPower |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field TotalVotingPower", wireType) + } + m.TotalVotingPower = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.TotalVotingPower |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryGetUpgradeRequest) 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 ErrIntOverflowQuery + } + 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: QueryGetUpgradeRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryGetUpgradeRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryGetUpgradeResponse) 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 ErrIntOverflowQuery + } + 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: QueryGetUpgradeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryGetUpgradeResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Upgrade", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Upgrade == nil { + m.Upgrade = &Upgrade{} + } + if err := m.Upgrade.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipQuery(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowQuery + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthQuery + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupQuery + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthQuery + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthQuery = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowQuery = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupQuery = fmt.Errorf("proto: unexpected end of group") +) diff --git a/client/x/signal/types/query.pb.gw.go b/client/x/signal/types/query.pb.gw.go new file mode 100644 index 00000000..c28aa9a3 --- /dev/null +++ b/client/x/signal/types/query.pb.gw.go @@ -0,0 +1,254 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: celestia/signal/v1/query.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +func request_Query_VersionTally_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryVersionTallyRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["version"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "version") + } + + protoReq.Version, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "version", err) + } + + msg, err := client.VersionTally(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_VersionTally_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryVersionTallyRequest + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["version"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "version") + } + + protoReq.Version, err = runtime.Uint64(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "version", err) + } + + msg, err := server.VersionTally(ctx, &protoReq) + return msg, metadata, err + +} + +func request_Query_GetUpgrade_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryGetUpgradeRequest + var metadata runtime.ServerMetadata + + msg, err := client.GetUpgrade(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_GetUpgrade_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryGetUpgradeRequest + var metadata runtime.ServerMetadata + + msg, err := server.GetUpgrade(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". +// UnaryRPC :call QueryServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. +func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { + + mux.Handle("GET", pattern_Query_VersionTally_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_VersionTally_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 { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_VersionTally_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_GetUpgrade_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_GetUpgrade_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 { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_GetUpgrade_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterQueryHandler(ctx, mux, conn) +} + +// RegisterQueryHandler registers the http handlers for service Query to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) +} + +// RegisterQueryHandlerClient registers the http handlers for service Query +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "QueryClient" to call the correct interceptors. +func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { + + mux.Handle("GET", pattern_Query_VersionTally_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) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_VersionTally_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_VersionTally_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_GetUpgrade_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) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_GetUpgrade_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_GetUpgrade_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Query_VersionTally_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"signal", "v1", "tally", "version"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_GetUpgrade_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"signal", "v1", "upgrade"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Query_VersionTally_0 = runtime.ForwardResponseMessage + + forward_Query_GetUpgrade_0 = runtime.ForwardResponseMessage +) diff --git a/client/x/signal/types/query.proto b/client/x/signal/types/query.proto new file mode 100644 index 00000000..e1ebe046 --- /dev/null +++ b/client/x/signal/types/query.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; +package client.x.signal.types; + +import "google/api/annotations.proto"; +import "client/x/signal/types/upgrade.proto"; + +option go_package = "client/x/signal/types"; + +// Query defines the signal Query service. +service Query { + // VersionTally enables a client to query for the tally of voting power that + // has signalled for a particular version. + rpc VersionTally(QueryVersionTallyRequest) + returns (QueryVersionTallyResponse) { + option (google.api.http).get = "/signal/tally/{version}"; + } + + // GetUpgrade enables a client to query for upgrade information if an upgrade is pending. + // The response will be empty if no upgrade is pending. + rpc GetUpgrade(QueryGetUpgradeRequest) + returns (QueryGetUpgradeResponse) { + option (google.api.http).get = "/signal/upgrade"; + } +} + +// QueryVersionTallyRequest is the request type for the VersionTally query. +message QueryVersionTallyRequest { uint64 version = 1; } + +// QueryVersionTallyResponse is the response type for the VersionTally query. +message QueryVersionTallyResponse { + uint64 voting_power = 1; + uint64 threshold_power = 2; + uint64 total_voting_power = 3; +} + +// QueryGetUpgradeRequest is the request type for the GetUpgrade query. +message QueryGetUpgradeRequest {} + +// QueryGetUpgradeResponse is the response type for the GetUpgrade query. +message QueryGetUpgradeResponse { + Upgrade upgrade = 1; +} \ No newline at end of file diff --git a/client/x/signal/types/tx.pb.go b/client/x/signal/types/tx.pb.go new file mode 100644 index 00000000..fc481999 --- /dev/null +++ b/client/x/signal/types/tx.pb.go @@ -0,0 +1,900 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: client/x/signal/types/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + grpc1 "github.com/cosmos/gogoproto/grpc" + proto "github.com/cosmos/gogoproto/proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// MsgSignalVersion signals for an upgrade. +type MsgSignalVersion struct { + ValidatorAddress string `protobuf:"bytes,1,opt,name=validator_address,json=validatorAddress,proto3" json:"validator_address,omitempty"` + Version uint64 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"` +} + +func (m *MsgSignalVersion) Reset() { *m = MsgSignalVersion{} } +func (m *MsgSignalVersion) String() string { return proto.CompactTextString(m) } +func (*MsgSignalVersion) ProtoMessage() {} +func (*MsgSignalVersion) Descriptor() ([]byte, []int) { + return fileDescriptor_c8c69f9a0364addd, []int{0} +} +func (m *MsgSignalVersion) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSignalVersion) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSignalVersion.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 *MsgSignalVersion) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSignalVersion.Merge(m, src) +} +func (m *MsgSignalVersion) XXX_Size() int { + return m.Size() +} +func (m *MsgSignalVersion) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSignalVersion.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSignalVersion proto.InternalMessageInfo + +func (m *MsgSignalVersion) GetValidatorAddress() string { + if m != nil { + return m.ValidatorAddress + } + return "" +} + +func (m *MsgSignalVersion) GetVersion() uint64 { + if m != nil { + return m.Version + } + return 0 +} + +// MsgSignalVersionResponse is the response type for the SignalVersion method. +type MsgSignalVersionResponse struct { +} + +func (m *MsgSignalVersionResponse) Reset() { *m = MsgSignalVersionResponse{} } +func (m *MsgSignalVersionResponse) String() string { return proto.CompactTextString(m) } +func (*MsgSignalVersionResponse) ProtoMessage() {} +func (*MsgSignalVersionResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_c8c69f9a0364addd, []int{1} +} +func (m *MsgSignalVersionResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgSignalVersionResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgSignalVersionResponse.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 *MsgSignalVersionResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgSignalVersionResponse.Merge(m, src) +} +func (m *MsgSignalVersionResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgSignalVersionResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgSignalVersionResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgSignalVersionResponse proto.InternalMessageInfo + +// MsgTryUpgrade tries to upgrade the chain. +type MsgTryUpgrade struct { + Signer string `protobuf:"bytes,1,opt,name=signer,proto3" json:"signer,omitempty"` +} + +func (m *MsgTryUpgrade) Reset() { *m = MsgTryUpgrade{} } +func (m *MsgTryUpgrade) String() string { return proto.CompactTextString(m) } +func (*MsgTryUpgrade) ProtoMessage() {} +func (*MsgTryUpgrade) Descriptor() ([]byte, []int) { + return fileDescriptor_c8c69f9a0364addd, []int{2} +} +func (m *MsgTryUpgrade) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgTryUpgrade) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgTryUpgrade.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 *MsgTryUpgrade) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgTryUpgrade.Merge(m, src) +} +func (m *MsgTryUpgrade) XXX_Size() int { + return m.Size() +} +func (m *MsgTryUpgrade) XXX_DiscardUnknown() { + xxx_messageInfo_MsgTryUpgrade.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgTryUpgrade proto.InternalMessageInfo + +func (m *MsgTryUpgrade) GetSigner() string { + if m != nil { + return m.Signer + } + return "" +} + +// MsgTryUpgradeResponse is the response type for the TryUpgrade method. +type MsgTryUpgradeResponse struct { +} + +func (m *MsgTryUpgradeResponse) Reset() { *m = MsgTryUpgradeResponse{} } +func (m *MsgTryUpgradeResponse) String() string { return proto.CompactTextString(m) } +func (*MsgTryUpgradeResponse) ProtoMessage() {} +func (*MsgTryUpgradeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_c8c69f9a0364addd, []int{3} +} +func (m *MsgTryUpgradeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgTryUpgradeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgTryUpgradeResponse.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 *MsgTryUpgradeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgTryUpgradeResponse.Merge(m, src) +} +func (m *MsgTryUpgradeResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgTryUpgradeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgTryUpgradeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgTryUpgradeResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgSignalVersion)(nil), "client.x.signal.types.MsgSignalVersion") + proto.RegisterType((*MsgSignalVersionResponse)(nil), "client.x.signal.types.MsgSignalVersionResponse") + proto.RegisterType((*MsgTryUpgrade)(nil), "client.x.signal.types.MsgTryUpgrade") + proto.RegisterType((*MsgTryUpgradeResponse)(nil), "client.x.signal.types.MsgTryUpgradeResponse") +} + +func init() { proto.RegisterFile("client/x/signal/types/tx.proto", fileDescriptor_c8c69f9a0364addd) } + +var fileDescriptor_c8c69f9a0364addd = []byte{ + // 321 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x4d, 0x4b, 0xfb, 0x30, + 0x18, 0x5f, 0xf6, 0xff, 0x33, 0xf1, 0x81, 0xe9, 0x56, 0xd8, 0x56, 0x8a, 0x84, 0x51, 0x84, 0x0d, + 0x94, 0x04, 0xf4, 0x13, 0xe8, 0x7d, 0x97, 0xf9, 0x02, 0x7a, 0x91, 0x68, 0x43, 0x08, 0x94, 0xa4, + 0x24, 0x71, 0x6c, 0x47, 0xc5, 0x0f, 0x20, 0xf8, 0xa5, 0x3c, 0x0e, 0xbc, 0x78, 0x94, 0xcd, 0x0f, + 0x22, 0x36, 0x6b, 0x75, 0x63, 0xc2, 0x4e, 0xe5, 0xe9, 0xef, 0x35, 0x79, 0x02, 0xf8, 0x2e, 0x95, + 0x5c, 0x39, 0x3a, 0xa6, 0x56, 0x0a, 0xc5, 0x52, 0xea, 0x26, 0x19, 0xb7, 0xd4, 0x8d, 0x49, 0x66, + 0xb4, 0xd3, 0x41, 0xcb, 0xe3, 0x64, 0x4c, 0x3c, 0x4e, 0x72, 0x3c, 0xda, 0x13, 0x5a, 0x8b, 0x94, + 0x53, 0x96, 0x49, 0xca, 0x94, 0xd2, 0x8e, 0x39, 0xa9, 0x95, 0xf5, 0xa2, 0xf8, 0x0a, 0x1a, 0x03, + 0x2b, 0xce, 0x72, 0xc1, 0x25, 0x37, 0x56, 0x6a, 0x15, 0x1c, 0x40, 0x73, 0xc4, 0x52, 0x99, 0x30, + 0xa7, 0xcd, 0x0d, 0x4b, 0x12, 0xc3, 0xad, 0x0d, 0x51, 0x17, 0xf5, 0xb7, 0x87, 0x8d, 0x12, 0x38, + 0xf1, 0xff, 0x83, 0x10, 0xb6, 0x46, 0x5e, 0x17, 0x56, 0xbb, 0xa8, 0xff, 0x7f, 0x58, 0x8c, 0x71, + 0x04, 0xe1, 0xaa, 0xf5, 0x90, 0xdb, 0x4c, 0x2b, 0xcb, 0xe3, 0x1e, 0xd4, 0x07, 0x56, 0x9c, 0x9b, + 0xc9, 0x45, 0x26, 0x0c, 0x4b, 0x78, 0xd0, 0x86, 0xda, 0x77, 0x6b, 0x6e, 0x16, 0x41, 0x8b, 0x29, + 0xee, 0x40, 0x6b, 0x89, 0x58, 0x38, 0x1c, 0x3d, 0x55, 0xe1, 0xdf, 0xc0, 0x8a, 0xe0, 0x01, 0x41, + 0x7d, 0xb9, 0x7e, 0x8f, 0xac, 0xbd, 0x08, 0xb2, 0x5a, 0x26, 0xa2, 0x1b, 0x12, 0xcb, 0xd6, 0xed, + 0xc7, 0xb7, 0xcf, 0x97, 0x6a, 0x23, 0xde, 0x29, 0x36, 0xe0, 0x3f, 0xc1, 0x04, 0xe0, 0xd7, 0x51, + 0xf6, 0xff, 0xb6, 0xfd, 0x61, 0x45, 0x87, 0x9b, 0xb0, 0xca, 0xe4, 0x4e, 0x9e, 0xdc, 0x8c, 0x77, + 0x8b, 0xe4, 0x7b, 0x4f, 0x38, 0xa5, 0xaf, 0x33, 0x8c, 0xa6, 0x33, 0x8c, 0x3e, 0x66, 0x18, 0x3d, + 0xcf, 0x71, 0x65, 0x3a, 0xc7, 0x95, 0xf7, 0x39, 0xae, 0x5c, 0xb7, 0xd6, 0x3e, 0x97, 0xdb, 0x5a, + 0xbe, 0xf7, 0xe3, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x81, 0x1e, 0x7d, 0x9a, 0x4e, 0x02, 0x00, + 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + // SignalVersion allows a validator to signal for a version. + SignalVersion(ctx context.Context, in *MsgSignalVersion, opts ...grpc.CallOption) (*MsgSignalVersionResponse, error) + // TryUpgrade tallies all the votes for all the versions to determine if a + // quorum has been reached for a version. + TryUpgrade(ctx context.Context, in *MsgTryUpgrade, opts ...grpc.CallOption) (*MsgTryUpgradeResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) SignalVersion(ctx context.Context, in *MsgSignalVersion, opts ...grpc.CallOption) (*MsgSignalVersionResponse, error) { + out := new(MsgSignalVersionResponse) + err := c.cc.Invoke(ctx, "/client.x.signal.types.Msg/SignalVersion", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *msgClient) TryUpgrade(ctx context.Context, in *MsgTryUpgrade, opts ...grpc.CallOption) (*MsgTryUpgradeResponse, error) { + out := new(MsgTryUpgradeResponse) + err := c.cc.Invoke(ctx, "/client.x.signal.types.Msg/TryUpgrade", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + // SignalVersion allows a validator to signal for a version. + SignalVersion(context.Context, *MsgSignalVersion) (*MsgSignalVersionResponse, error) + // TryUpgrade tallies all the votes for all the versions to determine if a + // quorum has been reached for a version. + TryUpgrade(context.Context, *MsgTryUpgrade) (*MsgTryUpgradeResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) SignalVersion(ctx context.Context, req *MsgSignalVersion) (*MsgSignalVersionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SignalVersion not implemented") +} +func (*UnimplementedMsgServer) TryUpgrade(ctx context.Context, req *MsgTryUpgrade) (*MsgTryUpgradeResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method TryUpgrade not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_SignalVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgSignalVersion) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).SignalVersion(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/client.x.signal.types.Msg/SignalVersion", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).SignalVersion(ctx, req.(*MsgSignalVersion)) + } + return interceptor(ctx, in, info, handler) +} + +func _Msg_TryUpgrade_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgTryUpgrade) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).TryUpgrade(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/client.x.signal.types.Msg/TryUpgrade", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).TryUpgrade(ctx, req.(*MsgTryUpgrade)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "client.x.signal.types.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SignalVersion", + Handler: _Msg_SignalVersion_Handler, + }, + { + MethodName: "TryUpgrade", + Handler: _Msg_TryUpgrade_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "client/x/signal/types/tx.proto", +} + +func (m *MsgSignalVersion) 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 *MsgSignalVersion) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSignalVersion) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Version != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Version)) + i-- + dAtA[i] = 0x10 + } + if len(m.ValidatorAddress) > 0 { + i -= len(m.ValidatorAddress) + copy(dAtA[i:], m.ValidatorAddress) + i = encodeVarintTx(dAtA, i, uint64(len(m.ValidatorAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgSignalVersionResponse) 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 *MsgSignalVersionResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgSignalVersionResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *MsgTryUpgrade) 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 *MsgTryUpgrade) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgTryUpgrade) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Signer) > 0 { + i -= len(m.Signer) + copy(dAtA[i:], m.Signer) + i = encodeVarintTx(dAtA, i, uint64(len(m.Signer))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgTryUpgradeResponse) 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 *MsgTryUpgradeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgTryUpgradeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgSignalVersion) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ValidatorAddress) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.Version != 0 { + n += 1 + sovTx(uint64(m.Version)) + } + return n +} + +func (m *MsgSignalVersionResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *MsgTryUpgrade) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Signer) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgTryUpgradeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgSignalVersion) 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: MsgSignalVersion: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSignalVersion: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorAddress", 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.ValidatorAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) + } + m.Version = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Version |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + 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 *MsgSignalVersionResponse) 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: MsgSignalVersionResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgSignalVersionResponse: 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 *MsgTryUpgrade) 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: MsgTryUpgrade: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgTryUpgrade: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Signer", 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.Signer = 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 *MsgTryUpgradeResponse) 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: MsgTryUpgradeResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgTryUpgradeResponse: 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 skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/client/x/signal/types/tx.pb.gw.go b/client/x/signal/types/tx.pb.gw.go new file mode 100644 index 00000000..9cb53050 --- /dev/null +++ b/client/x/signal/types/tx.pb.gw.go @@ -0,0 +1,254 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: celestia/signal/v1/tx.proto + +/* +Package types is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package types + +import ( + "context" + "io" + "net/http" + + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/grpc-ecosystem/grpc-gateway/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = descriptor.ForMessage +var _ = metadata.Join + +var ( + filter_Msg_SignalVersion_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Msg_SignalVersion_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgSignalVersion + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_SignalVersion_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.SignalVersion(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Msg_SignalVersion_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgSignalVersion + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_SignalVersion_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.SignalVersion(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Msg_TryUpgrade_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Msg_TryUpgrade_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgTryUpgrade + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_TryUpgrade_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.TryUpgrade(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Msg_TryUpgrade_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq MsgTryUpgrade + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_TryUpgrade_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.TryUpgrade(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterMsgHandlerServer registers the http handlers for service Msg to "mux". +// UnaryRPC :call MsgServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMsgHandlerFromEndpoint instead. +func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MsgServer) error { + + mux.Handle("POST", pattern_Msg_SignalVersion_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Msg_SignalVersion_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 { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_SignalVersion_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_Msg_TryUpgrade_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Msg_TryUpgrade_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 { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_TryUpgrade_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterMsgHandlerFromEndpoint is same as RegisterMsgHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterMsgHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.Dial(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterMsgHandler(ctx, mux, conn) +} + +// RegisterMsgHandler registers the http handlers for service Msg to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterMsgHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterMsgHandlerClient(ctx, mux, NewMsgClient(conn)) +} + +// RegisterMsgHandlerClient registers the http handlers for service Msg +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MsgClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MsgClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "MsgClient" to call the correct interceptors. +func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MsgClient) error { + + mux.Handle("POST", pattern_Msg_SignalVersion_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) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Msg_SignalVersion_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_SignalVersion_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_Msg_TryUpgrade_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) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Msg_TryUpgrade_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Msg_TryUpgrade_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_Msg_SignalVersion_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 0}, []string{"signal", "v1"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Msg_TryUpgrade_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"signal", "v1", "upgrade"}, "", runtime.AssumeColonVerbOpt(false))) +) + +var ( + forward_Msg_SignalVersion_0 = runtime.ForwardResponseMessage + + forward_Msg_TryUpgrade_0 = runtime.ForwardResponseMessage +) diff --git a/client/x/signal/types/tx.proto b/client/x/signal/types/tx.proto new file mode 100644 index 00000000..3218e0cd --- /dev/null +++ b/client/x/signal/types/tx.proto @@ -0,0 +1,35 @@ +syntax = "proto3"; +package client.x.signal.types; + +import "google/api/annotations.proto"; + +option go_package = "client/x/signal/types"; + +// Msg defines the signal Msg service. +service Msg { + // SignalVersion allows a validator to signal for a version. + rpc SignalVersion(MsgSignalVersion) returns (MsgSignalVersionResponse) { + option (google.api.http).post = "/signal/signal"; + } + + // TryUpgrade tallies all the votes for all the versions to determine if a + // quorum has been reached for a version. + rpc TryUpgrade(MsgTryUpgrade) returns (MsgTryUpgradeResponse) { + option (google.api.http).post = "/signal/upgrade"; + } +} + +// MsgSignalVersion signals for an upgrade. +message MsgSignalVersion { + string validator_address = 1; + uint64 version = 2; +} + +// MsgSignalVersionResponse is the response type for the SignalVersion method. +message MsgSignalVersionResponse {} + +// MsgTryUpgrade tries to upgrade the chain. +message MsgTryUpgrade { string signer = 1; } + +// MsgTryUpgradeResponse is the response type for the TryUpgrade method. +message MsgTryUpgradeResponse {} \ No newline at end of file diff --git a/client/x/signal/types/upgrade.pb.go b/client/x/signal/types/upgrade.pb.go new file mode 100644 index 00000000..bfb37d26 --- /dev/null +++ b/client/x/signal/types/upgrade.pb.go @@ -0,0 +1,341 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: client/x/signal/types/upgrade.proto + +package types + +import ( + fmt "fmt" + proto "github.com/cosmos/gogoproto/proto" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +// Upgrade is a type that represents a network upgrade. +type Upgrade struct { + // AppVersion is the app version that has received a quorum of validators to + // signal for it. + AppVersion uint64 `protobuf:"varint,1,opt,name=app_version,json=appVersion,proto3" json:"app_version,omitempty"` + // UpgradeHeight is the height at which the network should upgrade to the + // AppVersion. + UpgradeHeight int64 `protobuf:"varint,2,opt,name=upgrade_height,json=upgradeHeight,proto3" json:"upgrade_height,omitempty"` +} + +func (m *Upgrade) Reset() { *m = Upgrade{} } +func (m *Upgrade) String() string { return proto.CompactTextString(m) } +func (*Upgrade) ProtoMessage() {} +func (*Upgrade) Descriptor() ([]byte, []int) { + return fileDescriptor_04edc79a0c7811ae, []int{0} +} +func (m *Upgrade) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *Upgrade) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_Upgrade.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 *Upgrade) XXX_Merge(src proto.Message) { + xxx_messageInfo_Upgrade.Merge(m, src) +} +func (m *Upgrade) XXX_Size() int { + return m.Size() +} +func (m *Upgrade) XXX_DiscardUnknown() { + xxx_messageInfo_Upgrade.DiscardUnknown(m) +} + +var xxx_messageInfo_Upgrade proto.InternalMessageInfo + +func (m *Upgrade) GetAppVersion() uint64 { + if m != nil { + return m.AppVersion + } + return 0 +} + +func (m *Upgrade) GetUpgradeHeight() int64 { + if m != nil { + return m.UpgradeHeight + } + return 0 +} + +func init() { + proto.RegisterType((*Upgrade)(nil), "client.x.signal.types.Upgrade") +} + +func init() { + proto.RegisterFile("client/x/signal/types/upgrade.proto", fileDescriptor_04edc79a0c7811ae) +} + +var fileDescriptor_04edc79a0c7811ae = []byte{ + // 172 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x52, 0x4e, 0xce, 0xc9, 0x4c, + 0xcd, 0x2b, 0xd1, 0xaf, 0xd0, 0x2f, 0xce, 0x4c, 0xcf, 0x4b, 0xcc, 0xd1, 0x2f, 0xa9, 0x2c, 0x48, + 0x2d, 0xd6, 0x2f, 0x2d, 0x48, 0x2f, 0x4a, 0x4c, 0x49, 0xd5, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, + 0x12, 0x85, 0x28, 0xd2, 0xab, 0xd0, 0x83, 0x28, 0xd2, 0x03, 0x2b, 0x52, 0x0a, 0xe4, 0x62, 0x0f, + 0x85, 0xa8, 0x13, 0x92, 0xe7, 0xe2, 0x4e, 0x2c, 0x28, 0x88, 0x2f, 0x4b, 0x2d, 0x2a, 0xce, 0xcc, + 0xcf, 0x93, 0x60, 0x54, 0x60, 0xd4, 0x60, 0x09, 0xe2, 0x4a, 0x2c, 0x28, 0x08, 0x83, 0x88, 0x08, + 0xa9, 0x72, 0xf1, 0x41, 0xcd, 0x8c, 0xcf, 0x48, 0xcd, 0x4c, 0xcf, 0x28, 0x91, 0x60, 0x52, 0x60, + 0xd4, 0x60, 0x0e, 0xe2, 0x85, 0x8a, 0x7a, 0x80, 0x05, 0x9d, 0xf4, 0x4f, 0x3c, 0x92, 0x63, 0xbc, + 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x09, 0x8f, 0xe5, 0x18, 0x2e, 0x3c, 0x96, 0x63, + 0xb8, 0xf1, 0x58, 0x8e, 0x21, 0x4a, 0x14, 0xab, 0x43, 0x93, 0xd8, 0xc0, 0x2e, 0x34, 0x06, 0x04, + 0x00, 0x00, 0xff, 0xff, 0xa9, 0xcc, 0x2a, 0x8a, 0xc8, 0x00, 0x00, 0x00, +} + +func (m *Upgrade) 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 *Upgrade) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *Upgrade) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.UpgradeHeight != 0 { + i = encodeVarintUpgrade(dAtA, i, uint64(m.UpgradeHeight)) + i-- + dAtA[i] = 0x10 + } + if m.AppVersion != 0 { + i = encodeVarintUpgrade(dAtA, i, uint64(m.AppVersion)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func encodeVarintUpgrade(dAtA []byte, offset int, v uint64) int { + offset -= sovUpgrade(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *Upgrade) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.AppVersion != 0 { + n += 1 + sovUpgrade(uint64(m.AppVersion)) + } + if m.UpgradeHeight != 0 { + n += 1 + sovUpgrade(uint64(m.UpgradeHeight)) + } + return n +} + +func sovUpgrade(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozUpgrade(x uint64) (n int) { + return sovUpgrade(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *Upgrade) 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 ErrIntOverflowUpgrade + } + 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: Upgrade: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Upgrade: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AppVersion", wireType) + } + m.AppVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AppVersion |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field UpgradeHeight", wireType) + } + m.UpgradeHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowUpgrade + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.UpgradeHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipUpgrade(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthUpgrade + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipUpgrade(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowUpgrade + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowUpgrade + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowUpgrade + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthUpgrade + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupUpgrade + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthUpgrade + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthUpgrade = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowUpgrade = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupUpgrade = fmt.Errorf("proto: unexpected end of group") +) diff --git a/client/x/signal/types/upgrade.proto b/client/x/signal/types/upgrade.proto new file mode 100644 index 00000000..164d7b74 --- /dev/null +++ b/client/x/signal/types/upgrade.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; +package client.x.signal.types; + +option go_package = "client/x/signal/types"; + +// Upgrade is a type that represents a network upgrade. +message Upgrade { + // AppVersion is the app version that has received a quorum of validators to + // signal for it. + uint64 app_version = 1; + + // UpgradeHeight is the height at which the network should upgrade to the + // AppVersion. + int64 upgrade_height = 2; +} \ No newline at end of file diff --git a/scripts/mockgen.sh b/scripts/mockgen.sh index bd9ddab0..d351c54b 100644 --- a/scripts/mockgen.sh +++ b/scripts/mockgen.sh @@ -5,3 +5,4 @@ $mockgen_cmd -package mock -destination testutil/mock/grpc_server.go github.com/ $mockgen_cmd -package mock -destination testutil/mock/logger.go cosmossdk.io/log Logger $mockgen_cmd -source=client/x/evmengine/types/expected_keepers.go -package testutil -destination client/x/evmengine/testutil/expected_keepers_mocks.go $mockgen_cmd -source=client/x/evmstaking/types/expected_keepers.go -package testutil -destination client/x/evmstaking/testutil/expected_keepers_mocks.go +$mockgen_cmd -source=client/x/signal/types/expected_keepers.go -package testutil -destination client/x/signal/testutil/expected_keepers_mocks.go From dd69227ceba8f8a3299ee9d496dfffda55b99e93 Mon Sep 17 00:00:00 2001 From: Jongwon Park Date: Tue, 17 Sep 2024 22:41:54 -0500 Subject: [PATCH 2/6] feat(x/signal): update proto tx --- client/x/signal/types/tx.pb.go | 106 +++++++++++++++++---------------- client/x/signal/types/tx.proto | 5 +- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/client/x/signal/types/tx.pb.go b/client/x/signal/types/tx.pb.go index fc481999..876de32b 100644 --- a/client/x/signal/types/tx.pb.go +++ b/client/x/signal/types/tx.pb.go @@ -6,6 +6,7 @@ package types import ( context "context" fmt "fmt" + _ "github.com/cosmos/cosmos-sdk/types/msgservice" grpc1 "github.com/cosmos/gogoproto/grpc" proto "github.com/cosmos/gogoproto/proto" _ "google.golang.org/genproto/googleapis/api/annotations" @@ -210,28 +211,29 @@ func init() { func init() { proto.RegisterFile("client/x/signal/types/tx.proto", fileDescriptor_c8c69f9a0364addd) } var fileDescriptor_c8c69f9a0364addd = []byte{ - // 321 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x4d, 0x4b, 0xfb, 0x30, - 0x18, 0x5f, 0xf6, 0xff, 0x33, 0xf1, 0x81, 0xe9, 0x56, 0xd8, 0x56, 0x8a, 0x84, 0x51, 0x84, 0x0d, - 0x94, 0x04, 0xf4, 0x13, 0xe8, 0x7d, 0x97, 0xf9, 0x02, 0x7a, 0x91, 0x68, 0x43, 0x08, 0x94, 0xa4, - 0x24, 0x71, 0x6c, 0x47, 0xc5, 0x0f, 0x20, 0xf8, 0xa5, 0x3c, 0x0e, 0xbc, 0x78, 0x94, 0xcd, 0x0f, - 0x22, 0x36, 0x6b, 0x75, 0x63, 0xc2, 0x4e, 0xe5, 0xe9, 0xef, 0x35, 0x79, 0x02, 0xf8, 0x2e, 0x95, - 0x5c, 0x39, 0x3a, 0xa6, 0x56, 0x0a, 0xc5, 0x52, 0xea, 0x26, 0x19, 0xb7, 0xd4, 0x8d, 0x49, 0x66, - 0xb4, 0xd3, 0x41, 0xcb, 0xe3, 0x64, 0x4c, 0x3c, 0x4e, 0x72, 0x3c, 0xda, 0x13, 0x5a, 0x8b, 0x94, - 0x53, 0x96, 0x49, 0xca, 0x94, 0xd2, 0x8e, 0x39, 0xa9, 0x95, 0xf5, 0xa2, 0xf8, 0x0a, 0x1a, 0x03, - 0x2b, 0xce, 0x72, 0xc1, 0x25, 0x37, 0x56, 0x6a, 0x15, 0x1c, 0x40, 0x73, 0xc4, 0x52, 0x99, 0x30, - 0xa7, 0xcd, 0x0d, 0x4b, 0x12, 0xc3, 0xad, 0x0d, 0x51, 0x17, 0xf5, 0xb7, 0x87, 0x8d, 0x12, 0x38, - 0xf1, 0xff, 0x83, 0x10, 0xb6, 0x46, 0x5e, 0x17, 0x56, 0xbb, 0xa8, 0xff, 0x7f, 0x58, 0x8c, 0x71, - 0x04, 0xe1, 0xaa, 0xf5, 0x90, 0xdb, 0x4c, 0x2b, 0xcb, 0xe3, 0x1e, 0xd4, 0x07, 0x56, 0x9c, 0x9b, - 0xc9, 0x45, 0x26, 0x0c, 0x4b, 0x78, 0xd0, 0x86, 0xda, 0x77, 0x6b, 0x6e, 0x16, 0x41, 0x8b, 0x29, - 0xee, 0x40, 0x6b, 0x89, 0x58, 0x38, 0x1c, 0x3d, 0x55, 0xe1, 0xdf, 0xc0, 0x8a, 0xe0, 0x01, 0x41, - 0x7d, 0xb9, 0x7e, 0x8f, 0xac, 0xbd, 0x08, 0xb2, 0x5a, 0x26, 0xa2, 0x1b, 0x12, 0xcb, 0xd6, 0xed, - 0xc7, 0xb7, 0xcf, 0x97, 0x6a, 0x23, 0xde, 0x29, 0x36, 0xe0, 0x3f, 0xc1, 0x04, 0xe0, 0xd7, 0x51, - 0xf6, 0xff, 0xb6, 0xfd, 0x61, 0x45, 0x87, 0x9b, 0xb0, 0xca, 0xe4, 0x4e, 0x9e, 0xdc, 0x8c, 0x77, - 0x8b, 0xe4, 0x7b, 0x4f, 0x38, 0xa5, 0xaf, 0x33, 0x8c, 0xa6, 0x33, 0x8c, 0x3e, 0x66, 0x18, 0x3d, - 0xcf, 0x71, 0x65, 0x3a, 0xc7, 0x95, 0xf7, 0x39, 0xae, 0x5c, 0xb7, 0xd6, 0x3e, 0x97, 0xdb, 0x5a, - 0xbe, 0xf7, 0xe3, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x81, 0x1e, 0x7d, 0x9a, 0x4e, 0x02, 0x00, - 0x00, + // 349 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x52, 0x4d, 0x4a, 0x03, 0x31, + 0x18, 0x6d, 0x8a, 0x56, 0x0c, 0x54, 0xdb, 0x81, 0xb6, 0xc3, 0x20, 0xa1, 0x0c, 0x42, 0x8b, 0xca, + 0x04, 0xf5, 0x04, 0xba, 0xef, 0xa6, 0xfe, 0x80, 0x6e, 0x24, 0x76, 0x42, 0x08, 0x4c, 0x93, 0x21, + 0x89, 0x43, 0xbb, 0x53, 0x4f, 0x20, 0x7a, 0x11, 0x8f, 0xe1, 0xb2, 0xe0, 0xc6, 0xa5, 0xb4, 0x82, + 0xd7, 0x90, 0x4e, 0x3a, 0xa3, 0x2d, 0x15, 0xba, 0xfa, 0xf8, 0xf2, 0x5e, 0xde, 0xfb, 0x5e, 0xf2, + 0x41, 0xd4, 0x8b, 0x38, 0x15, 0x06, 0x0f, 0xb0, 0xe6, 0x4c, 0x90, 0x08, 0x9b, 0x61, 0x4c, 0x35, + 0x36, 0x83, 0x20, 0x56, 0xd2, 0x48, 0xa7, 0x66, 0xf1, 0x60, 0x10, 0x58, 0x3c, 0x48, 0x71, 0xaf, + 0xd1, 0x93, 0xba, 0x2f, 0x35, 0xee, 0x6b, 0x86, 0x93, 0xc3, 0x69, 0xb1, 0x7c, 0x6f, 0x87, 0x49, + 0xc9, 0x22, 0x8a, 0x49, 0xcc, 0x31, 0x11, 0x42, 0x1a, 0x62, 0xb8, 0x14, 0xda, 0xa2, 0xfe, 0x15, + 0xac, 0x74, 0x34, 0x3b, 0x4b, 0x95, 0x2e, 0xa9, 0xd2, 0x5c, 0x0a, 0x67, 0x1f, 0x56, 0x13, 0x12, + 0xf1, 0x90, 0x18, 0xa9, 0x6e, 0x48, 0x18, 0x2a, 0xaa, 0xb5, 0x0b, 0x9a, 0xa0, 0xbd, 0xd9, 0xad, + 0xe4, 0xc0, 0x89, 0x3d, 0x77, 0x5c, 0xb8, 0x91, 0xd8, 0x7b, 0x6e, 0xb1, 0x09, 0xda, 0x6b, 0xdd, + 0xac, 0xf5, 0x3d, 0xe8, 0x2e, 0x4a, 0x77, 0xa9, 0x8e, 0xa5, 0xd0, 0xd4, 0x6f, 0xc1, 0x72, 0x47, + 0xb3, 0x73, 0x35, 0xbc, 0x88, 0x99, 0x22, 0x21, 0x75, 0xea, 0xb0, 0x34, 0x8d, 0x43, 0xd5, 0xcc, + 0x68, 0xd6, 0xf9, 0x0d, 0x58, 0x9b, 0x23, 0x66, 0x0a, 0x47, 0xcf, 0x45, 0x08, 0xa7, 0xf2, 0x54, + 0x25, 0xbc, 0x47, 0x9d, 0x07, 0x00, 0xcb, 0xf3, 0x29, 0x5a, 0xc1, 0xd2, 0x87, 0x0a, 0x16, 0x67, + 0xf2, 0xf0, 0x8a, 0xc4, 0x7c, 0xf8, 0xfa, 0xe3, 0xfb, 0xd7, 0x4b, 0xb1, 0xe2, 0x6f, 0x65, 0x3f, + 0x64, 0x8b, 0x33, 0x84, 0xf0, 0x4f, 0xa2, 0xdd, 0xff, 0x65, 0x7f, 0x59, 0xde, 0xc1, 0x2a, 0xac, + 0xdc, 0xb9, 0x91, 0x3a, 0x57, 0xfd, 0xed, 0xcc, 0xf9, 0x6e, 0x26, 0xb3, 0x7e, 0xff, 0xfd, 0xba, + 0x07, 0x4e, 0xf1, 0xdb, 0x18, 0x81, 0xd1, 0x18, 0x81, 0xcf, 0x31, 0x02, 0x4f, 0x13, 0x54, 0x18, + 0x4d, 0x50, 0xe1, 0x63, 0x82, 0x0a, 0xd7, 0xb5, 0xa5, 0x5b, 0x75, 0x5b, 0x4a, 0xb7, 0xe0, 0xf8, + 0x27, 0x00, 0x00, 0xff, 0xff, 0x3c, 0x85, 0xa1, 0x2a, 0x75, 0x02, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -242,10 +244,10 @@ var _ grpc.ClientConn // is compatible with the grpc package it is being compiled against. const _ = grpc.SupportPackageIsVersion4 -// MsgClient is the client API for Msg service. +// MsgServiceClient is the client API for MsgService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type MsgClient interface { +type MsgServiceClient interface { // SignalVersion allows a validator to signal for a version. SignalVersion(ctx context.Context, in *MsgSignalVersion, opts ...grpc.CallOption) (*MsgSignalVersionResponse, error) // TryUpgrade tallies all the votes for all the versions to determine if a @@ -253,34 +255,34 @@ type MsgClient interface { TryUpgrade(ctx context.Context, in *MsgTryUpgrade, opts ...grpc.CallOption) (*MsgTryUpgradeResponse, error) } -type msgClient struct { +type msgServiceClient struct { cc grpc1.ClientConn } -func NewMsgClient(cc grpc1.ClientConn) MsgClient { - return &msgClient{cc} +func NewMsgServiceClient(cc grpc1.ClientConn) MsgServiceClient { + return &msgServiceClient{cc} } -func (c *msgClient) SignalVersion(ctx context.Context, in *MsgSignalVersion, opts ...grpc.CallOption) (*MsgSignalVersionResponse, error) { +func (c *msgServiceClient) SignalVersion(ctx context.Context, in *MsgSignalVersion, opts ...grpc.CallOption) (*MsgSignalVersionResponse, error) { out := new(MsgSignalVersionResponse) - err := c.cc.Invoke(ctx, "/client.x.signal.types.Msg/SignalVersion", in, out, opts...) + err := c.cc.Invoke(ctx, "/client.x.signal.types.MsgService/SignalVersion", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *msgClient) TryUpgrade(ctx context.Context, in *MsgTryUpgrade, opts ...grpc.CallOption) (*MsgTryUpgradeResponse, error) { +func (c *msgServiceClient) TryUpgrade(ctx context.Context, in *MsgTryUpgrade, opts ...grpc.CallOption) (*MsgTryUpgradeResponse, error) { out := new(MsgTryUpgradeResponse) - err := c.cc.Invoke(ctx, "/client.x.signal.types.Msg/TryUpgrade", in, out, opts...) + err := c.cc.Invoke(ctx, "/client.x.signal.types.MsgService/TryUpgrade", in, out, opts...) if err != nil { return nil, err } return out, nil } -// MsgServer is the server API for Msg service. -type MsgServer interface { +// MsgServiceServer is the server API for MsgService service. +type MsgServiceServer interface { // SignalVersion allows a validator to signal for a version. SignalVersion(context.Context, *MsgSignalVersion) (*MsgSignalVersionResponse, error) // TryUpgrade tallies all the votes for all the versions to determine if a @@ -288,68 +290,68 @@ type MsgServer interface { TryUpgrade(context.Context, *MsgTryUpgrade) (*MsgTryUpgradeResponse, error) } -// UnimplementedMsgServer can be embedded to have forward compatible implementations. -type UnimplementedMsgServer struct { +// UnimplementedMsgServiceServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServiceServer struct { } -func (*UnimplementedMsgServer) SignalVersion(ctx context.Context, req *MsgSignalVersion) (*MsgSignalVersionResponse, error) { +func (*UnimplementedMsgServiceServer) SignalVersion(ctx context.Context, req *MsgSignalVersion) (*MsgSignalVersionResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SignalVersion not implemented") } -func (*UnimplementedMsgServer) TryUpgrade(ctx context.Context, req *MsgTryUpgrade) (*MsgTryUpgradeResponse, error) { +func (*UnimplementedMsgServiceServer) TryUpgrade(ctx context.Context, req *MsgTryUpgrade) (*MsgTryUpgradeResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method TryUpgrade not implemented") } -func RegisterMsgServer(s grpc1.Server, srv MsgServer) { - s.RegisterService(&_Msg_serviceDesc, srv) +func RegisterMsgServiceServer(s grpc1.Server, srv MsgServiceServer) { + s.RegisterService(&_MsgService_serviceDesc, srv) } -func _Msg_SignalVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _MsgService_SignalVersion_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgSignalVersion) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).SignalVersion(ctx, in) + return srv.(MsgServiceServer).SignalVersion(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/client.x.signal.types.Msg/SignalVersion", + FullMethod: "/client.x.signal.types.MsgService/SignalVersion", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).SignalVersion(ctx, req.(*MsgSignalVersion)) + return srv.(MsgServiceServer).SignalVersion(ctx, req.(*MsgSignalVersion)) } return interceptor(ctx, in, info, handler) } -func _Msg_TryUpgrade_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { +func _MsgService_TryUpgrade_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MsgTryUpgrade) if err := dec(in); err != nil { return nil, err } if interceptor == nil { - return srv.(MsgServer).TryUpgrade(ctx, in) + return srv.(MsgServiceServer).TryUpgrade(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: "/client.x.signal.types.Msg/TryUpgrade", + FullMethod: "/client.x.signal.types.MsgService/TryUpgrade", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MsgServer).TryUpgrade(ctx, req.(*MsgTryUpgrade)) + return srv.(MsgServiceServer).TryUpgrade(ctx, req.(*MsgTryUpgrade)) } return interceptor(ctx, in, info, handler) } -var _Msg_serviceDesc = grpc.ServiceDesc{ - ServiceName: "client.x.signal.types.Msg", - HandlerType: (*MsgServer)(nil), +var _MsgService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "client.x.signal.types.MsgService", + HandlerType: (*MsgServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "SignalVersion", - Handler: _Msg_SignalVersion_Handler, + Handler: _MsgService_SignalVersion_Handler, }, { MethodName: "TryUpgrade", - Handler: _Msg_TryUpgrade_Handler, + Handler: _MsgService_TryUpgrade_Handler, }, }, Streams: []grpc.StreamDesc{}, diff --git a/client/x/signal/types/tx.proto b/client/x/signal/types/tx.proto index 3218e0cd..b46d1981 100644 --- a/client/x/signal/types/tx.proto +++ b/client/x/signal/types/tx.proto @@ -1,12 +1,15 @@ syntax = "proto3"; package client.x.signal.types; +import "cosmos/msg/v1/msg.proto"; import "google/api/annotations.proto"; option go_package = "client/x/signal/types"; // Msg defines the signal Msg service. -service Msg { +service MsgService { + option (cosmos.msg.v1.service) = true; + // SignalVersion allows a validator to signal for a version. rpc SignalVersion(MsgSignalVersion) returns (MsgSignalVersionResponse) { option (google.api.http).post = "/signal/signal"; From db4b7d3a6c0ceaca1909742e1a84009cfa48eccd Mon Sep 17 00:00:00 2001 From: Jongwon Park Date: Tue, 17 Sep 2024 22:42:45 -0500 Subject: [PATCH 3/6] test(x/signal): keeper tests and testutil --- client/x/signal/keeper/keeper.go | 3 +- client/x/signal/keeper/keeper_test.go | 569 ++++++++++++++++++ client/x/signal/testutil/common.go | 191 ++++++ .../signal/testutil/expected_keepers_mocks.go | 232 +++++++ 4 files changed, 994 insertions(+), 1 deletion(-) create mode 100644 client/x/signal/keeper/keeper_test.go create mode 100644 client/x/signal/testutil/common.go create mode 100644 client/x/signal/testutil/expected_keepers_mocks.go diff --git a/client/x/signal/keeper/keeper.go b/client/x/signal/keeper/keeper.go index 8a0ac150..32a5f54f 100644 --- a/client/x/signal/keeper/keeper.go +++ b/client/x/signal/keeper/keeper.go @@ -3,13 +3,14 @@ package keeper import ( "context" "encoding/binary" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "cosmossdk.io/core/store" sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/piplabs/story/client/x/signal/types" "github.com/piplabs/story/lib/log" ) diff --git a/client/x/signal/keeper/keeper_test.go b/client/x/signal/keeper/keeper_test.go new file mode 100644 index 00000000..32e75957 --- /dev/null +++ b/client/x/signal/keeper/keeper_test.go @@ -0,0 +1,569 @@ +package keeper_test + +import ( + "context" + "fmt" + "math" + "math/big" + "testing" + "time" + + "cosmossdk.io/log" + sdkmath "cosmossdk.io/math" + "cosmossdk.io/store" + "cosmossdk.io/store/metrics" + storetypes "cosmossdk.io/store/types" + + cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + tmversion "github.com/cometbft/cometbft/proto/tendermint/version" + dbm "github.com/cosmos/cosmos-db" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/address" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + "github.com/cosmos/cosmos-sdk/runtime" + sdk "github.com/cosmos/cosmos-sdk/types" + moduletestutil "github.com/cosmos/cosmos-sdk/types/module/testutil" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + stypes "github.com/cosmos/cosmos-sdk/x/staking/types" + v1 "github.com/docker/docker/image/spec/specs-go" + "github.com/stretchr/testify/suite" + + "github.com/piplabs/story/client/x/signal/keeper" + "github.com/piplabs/story/client/x/signal/module" + "github.com/piplabs/story/client/x/signal/testutil" + "github.com/piplabs/story/client/x/signal/types" + "github.com/piplabs/story/lib/errors" + + "go.uber.org/mock/gomock" +) + +type TestSuite struct { + suite.Suite + + Ctx sdk.Context + + AccountKeeper *testutil.MockAccountKeeper + StakingKeeper types.StakingKeeper + UpgradeKeeper *keeper.Keeper + msgServer types.MsgServiceServer + + encCfg moduletestutil.TestEncodingConfig +} + +func (s *TestSuite) SetupTest(t *testing.T) { + s.encCfg = moduletestutil.MakeTestEncodingConfig(module.AppModuleBasic{}) + signalStore := storetypes.NewKVStoreKey(types.StoreKey) + storeService := runtime.NewKVStoreService(signalStore) + + db := dbm.NewMemDB() + cms := store.NewCommitMultiStore(db, log.NewNopLogger(), metrics.NewNoOpMetrics()) + cms.MountStoreWithDB(signalStore, storetypes.StoreTypeIAVL, db) + err := cms.LoadLatestVersion() + s.Require().NoError(err) + + s.Ctx = sdk.NewContext(cms, cmtproto.Header{Time: time.Now()}, false, log.NewNopLogger()) + + interfaceRegistry := codectypes.NewInterfaceRegistry() + cryptocodec.RegisterInterfaces(interfaceRegistry) + legacyAmino := codec.NewLegacyAmino() + stypes.RegisterLegacyAminoCodec(legacyAmino) + stypes.RegisterInterfaces(interfaceRegistry) + marshaler := codec.NewProtoCodec(interfaceRegistry) + + cfg := sdk.GetConfig() + cfg.SetBech32PrefixForAccount("story", "storypub") + cfg.SetBech32PrefixForValidator("storyvaloper", "storyvaloperpub") + cfg.SetBech32PrefixForConsensusNode("storyvalcons", "storyvalconspub") + + // gomock initializations + ctrl := gomock.NewController(s.T()) + + // mock keepers + accountKeeper := testutil.NewMockAccountKeeper(ctrl) + accountKeeper.EXPECT().GetModuleAddress(types.ModuleName).Return(authtypes.NewModuleAddress(types.ModuleName)).AnyTimes() + accountKeeper.EXPECT().GetModuleAddress(stypes.ModuleName).Return(authtypes.NewModuleAddress(stypes.ModuleName)).AnyTimes() + accountKeeper.EXPECT().GetModuleAddress(stypes.BondedPoolName).Return(authtypes.NewModuleAddress(stypes.BondedPoolName)).AnyTimes() + accountKeeper.EXPECT().GetModuleAddress(stypes.NotBondedPoolName).Return(authtypes.NewModuleAddress(stypes.NotBondedPoolName)).AnyTimes() + accountKeeper.EXPECT().AddressCodec().Return(address.NewBech32Codec("story")).AnyTimes() + + mockStakingKeeper := newMockStakingKeeper( + map[string]int64{ + testutil.ValAddrs[0].String(): 40, + testutil.ValAddrs[1].String(): 1, + testutil.ValAddrs[2].String(): 59, + testutil.ValAddrs[3].String(): 20, + }, + ) + s.StakingKeeper = mockStakingKeeper + + upgradeKeeper := keeper.NewKeeper( + marshaler, + storeService, + accountKeeper, + mockStakingKeeper, + authtypes.NewModuleAddress(stypes.ModuleName).String(), + ) + s.UpgradeKeeper = upgradeKeeper +} + +func (s *TestSuite) TestGetVotingPowerThreshold() { + require := s.Require() + + bigInt := big.NewInt(0) + bigInt.SetString("23058430092136939509", 10) + + type testCase struct { + name string + validators map[string]int64 + want sdkmath.Int + } + tcs := []testCase{ + { + name: "empty validators", + validators: map[string]int64{}, + want: sdkmath.NewInt(0), + }, + { + name: "one validator with 6 power returns 5 because the defaultSignalThreshold is 5/6", + validators: map[string]int64{"a": 6}, + want: sdkmath.NewInt(5), + }, + { + name: "one validator with 11 power (11 * 5/6 = 9.16666667) so should round up to 10", + validators: map[string]int64{"a": 11}, + want: sdkmath.NewInt(10), + }, + { + name: "one validator with voting power of math.MaxInt64", + validators: map[string]int64{"a": math.MaxInt64}, + want: sdkmath.NewInt(7686143364045646503), + }, + { + name: "multiple validators with voting power of math.MaxInt64", + validators: map[string]int64{"a": math.MaxInt64, "b": math.MaxInt64, "c": math.MaxInt64}, + want: sdkmath.NewIntFromBigInt(bigInt), + }, + } + for _, tc := range tcs { + s.Run(tc.name, func() { + got := s.UpgradeKeeper.GetVotingPowerThreshold(sdk.Context{}) + require.Equal(tc.want, got, fmt.Sprintf("want %v, got %v", tc.want.String(), got.String())) + }) + } +} + +func (s *TestSuite) TestSignalVersion() { + require := s.Require() + + ctx, upgradeKeeper := s.Ctx, s.UpgradeKeeper + goCtx := sdk.WrapSDKContext(ctx) + + s.Run("should return an error if the signal version is less than the current version", func() { + _, err := upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[0].String(), + Version: 0, + }) + require.Error(err) + require.ErrorIs(err, types.ErrInvalidSignalVersion) + }) + + s.Run("should not return an error if the signal version is greater than the next version", func() { + _, err := upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[0].String(), + Version: 3, + }) + require.NoError(err) + }) + + s.Run("should return an error if the validator was not found", func() { + _, err := upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[4].String(), + Version: 2, + }) + require.Error(err) + require.ErrorIs(err, stypes.ErrNoValidatorFound) + }) + + s.Run("should not return an error if the signal version and validator are valid", func() { + _, err := upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[0].String(), + Version: 2, + }) + require.NoError(err) + + res, err := upgradeKeeper.VersionTally(goCtx, &types.QueryVersionTallyRequest{ + Version: 2, + }) + require.NoError(err) + require.EqualValues(40, res.VotingPower) + require.EqualValues(100, res.ThresholdPower) + require.EqualValues(120, res.TotalVotingPower) + }) +} + +func (s *TestSuite) TestTallyingLogic(t *testing.T) { + require := s.Require() + + ctx, upgradeKeeper := s.Ctx, s.UpgradeKeeper + stakingKeeper := s.StakingKeeper.(*mockStakingKeeper) + goCtx := sdk.WrapSDKContext(ctx) + + _, err := upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[0].String(), + Version: 0, + }) + require.Error(err) + require.ErrorIs(err, types.ErrInvalidSignalVersion) + + _, err = upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[0].String(), + Version: 3, + }) + require.NoError(err) // version 3 is valid because it is greater than the current version + + _, err = upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[0].String(), + Version: 2, + }) + require.NoError(err) + + res, err := upgradeKeeper.VersionTally(goCtx, &types.QueryVersionTallyRequest{ + Version: 2, + }) + require.NoError(err) + require.EqualValues(40, res.VotingPower) + require.EqualValues(100, res.ThresholdPower) + require.EqualValues(120, res.TotalVotingPower) + + _, err = upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[2].String(), + Version: 2, + }) + require.NoError(err) + + res, err = upgradeKeeper.VersionTally(goCtx, &types.QueryVersionTallyRequest{ + Version: 2, + }) + require.NoError(err) + require.EqualValues(99, res.VotingPower) + require.EqualValues(100, res.ThresholdPower) + require.EqualValues(120, res.TotalVotingPower) + + _, err = upgradeKeeper.TryUpgrade(goCtx, &types.MsgTryUpgrade{}) + require.NoError(err) + shouldUpgrade, version := upgradeKeeper.ShouldUpgrade(ctx) + require.False(shouldUpgrade) + require.Equal(uint64(0), version) + + // we now have 101/120 + _, err = upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[1].String(), + Version: 2, + }) + require.NoError(err) + + _, err = upgradeKeeper.TryUpgrade(goCtx, &types.MsgTryUpgrade{}) + require.NoError(err) + + shouldUpgrade, version = upgradeKeeper.ShouldUpgrade(ctx) + require.False(shouldUpgrade) // should be false because upgrade height hasn't been reached. + require.Equal(uint64(0), version) + + ctx = ctx.WithBlockHeight(ctx.BlockHeight() + keeper.DefaultUpgradeHeightDelay) + + shouldUpgrade, version = upgradeKeeper.ShouldUpgrade(ctx) + require.True(shouldUpgrade) // should be true because upgrade height has been reached. + require.Equal(2, version) + + upgradeKeeper.ResetTally(ctx) + + // update the version to 2 + ctx = ctx.WithBlockHeader(tmproto.Header{ + Version: tmversion.Consensus{ + Block: 1, + App: 2, + }, + }) + goCtx = sdk.WrapSDKContext(ctx) + + _, err = upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[0].String(), + Version: 3, + }) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[1].String(), + Version: 2, + }) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[2].String(), + Version: 2, + }) + require.NoError(err) + + res, err = upgradeKeeper.VersionTally(goCtx, &types.QueryVersionTallyRequest{ + Version: 2, + }) + require.NoError(err) + require.EqualValues(60, res.VotingPower) + require.EqualValues(100, res.ThresholdPower) + require.EqualValues(120, res.TotalVotingPower) + + // remove one of the validators from the set + delete(stakingKeeper.validators, testutil.ValAddrs[1].String()) + // the validator had 1 voting power, so we deduct it from the total + stakingKeeper.totalVotingPower = stakingKeeper.totalVotingPower.SubRaw(1) + + res, err = upgradeKeeper.VersionTally(goCtx, &types.QueryVersionTallyRequest{ + Version: 2, + }) + require.NoError(err) + require.EqualValues(59, res.VotingPower) + require.EqualValues(100, res.ThresholdPower) + require.EqualValues(119, res.TotalVotingPower) + + // That validator should not be able to signal a version + _, err = upgradeKeeper.SignalVersion(goCtx, &types.MsgSignalVersion{ + ValidatorAddress: testutil.ValAddrs[1].String(), + Version: 2, + }) + require.Error(err) + + // resetting the tally should clear other votes + upgradeKeeper.ResetTally(ctx) + res, err = upgradeKeeper.VersionTally(goCtx, &types.QueryVersionTallyRequest{ + Version: 2, + }) + require.NoError(err) + require.EqualValues(0, res.VotingPower) +} + +// TestCanSkipVersion verifies that the signal keeper can upgrade to an app +// version greater than the next app version. Example: if the current version is +// 1, the next version is 2, but the chain can upgrade directly from 1 to 3. +func (s *TestSuite) TestCanSkipVersion(t *testing.T) { + require := s.Require() + + ctx, upgradeKeeper := s.Ctx, s.UpgradeKeeper + goCtx := sdk.WrapSDKContext(ctx) + + require.Equal(v1.Version, ctx.BlockHeader().Version.App) + + validators := []sdk.ValAddress{ + testutil.ValAddrs[0], + testutil.ValAddrs[1], + testutil.ValAddrs[2], + testutil.ValAddrs[3], + } + // signal version 3 for all validators + for _, validator := range validators { + _, err := upgradeKeeper.SignalVersion(sdk.WrapSDKContext(ctx), &types.MsgSignalVersion{ + ValidatorAddress: validator.String(), + Version: 3, + }) + require.NoError(err) + } + + _, err := upgradeKeeper.TryUpgrade(goCtx, &types.MsgTryUpgrade{}) + require.NoError(err) + + isUpgradePending := upgradeKeeper.IsUpgradePending(ctx) + require.True(isUpgradePending) +} + +func (s *TestSuite) TestEmptyStore(t *testing.T) { + require := s.Require() + + ctx, upgradeKeeper := s.Ctx, s.UpgradeKeeper + goCtx := sdk.WrapSDKContext(ctx) + + res, err := upgradeKeeper.VersionTally(goCtx, &types.QueryVersionTallyRequest{ + Version: 2, + }) + require.NoError(err) + require.EqualValues(0, res.VotingPower) + // 120 is the summation in voting power of the four validators + require.EqualValues(120, res.TotalVotingPower) +} + +func (s *TestSuite) TestThresholdVotingPower(t *testing.T) { + require := s.Require() + + ctx, upgradeKeeper := s.Ctx, s.UpgradeKeeper + stakingKeeper := s.StakingKeeper.(*mockStakingKeeper) + + for _, tc := range []struct { + total int64 + threshold int64 + }{ + {total: 1, threshold: 1}, + {total: 2, threshold: 2}, + {total: 3, threshold: 3}, + {total: 6, threshold: 5}, + {total: 59, threshold: 50}, + } { + stakingKeeper.totalVotingPower = sdkmath.NewInt(tc.total) + threshold := upgradeKeeper.GetVotingPowerThreshold(ctx) + require.EqualValues(tc.threshold, threshold.Int64()) + } +} + +// TestResetTally verifies that ResetTally resets the VotingPower for all +// versions to 0 and any pending upgrade is cleared. +func (s *TestSuite) TestResetTally(t *testing.T) { + require := s.Require() + + ctx, upgradeKeeper := s.Ctx, s.UpgradeKeeper + + _, err := upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[0].String(), Version: 2}) + require.NoError(err) + resp, err := upgradeKeeper.VersionTally(ctx, &types.QueryVersionTallyRequest{Version: 2}) + require.NoError(err) + require.Equal(uint64(40), resp.VotingPower) + + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[1].String(), Version: 3}) + require.NoError(err) + resp, err = upgradeKeeper.VersionTally(ctx, &types.QueryVersionTallyRequest{Version: 3}) + require.NoError(err) + require.Equal(uint64(1), resp.VotingPower) + + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[2].String(), Version: 2}) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[3].String(), Version: 2}) + require.NoError(err) + + _, err = upgradeKeeper.TryUpgrade(ctx, &types.MsgTryUpgrade{}) + require.NoError(err) + + require.True(upgradeKeeper.IsUpgradePending(ctx)) + + upgradeKeeper.ResetTally(ctx) + + resp, err = upgradeKeeper.VersionTally(ctx, &types.QueryVersionTallyRequest{Version: 2}) + require.NoError(err) + require.Equal(uint64(0), resp.VotingPower) + + resp, err = upgradeKeeper.VersionTally(ctx, &types.QueryVersionTallyRequest{Version: 3}) + require.NoError(err) + require.Equal(uint64(0), resp.VotingPower) + + require.False(upgradeKeeper.IsUpgradePending(ctx)) +} + +func (s *TestSuite) TestTryUpgrade(t *testing.T) { + require := s.Require() + + ctx, upgradeKeeper := s.Ctx, s.UpgradeKeeper + goCtx := sdk.WrapSDKContext(ctx) + + t.Run("should return an error if an upgrade is already pending", func(t *testing.T) { + _, err := upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[0].String(), Version: 2}) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[1].String(), Version: 2}) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[2].String(), Version: 2}) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[3].String(), Version: 2}) + require.NoError(err) + + // This TryUpgrade should succeed. + _, err = upgradeKeeper.TryUpgrade(goCtx, &types.MsgTryUpgrade{}) + require.NoError(err) + + // This TryUpgrade should fail because an upgrade is pending. + _, err = upgradeKeeper.TryUpgrade(goCtx, &types.MsgTryUpgrade{}) + require.Error(err) + require.ErrorIs(err, types.ErrUpgradePending) + }) + + t.Run("should return an error if quorum version is less than or equal to the current version", func(t *testing.T) { + _, err := upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[0].String(), Version: 1}) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[1].String(), Version: 1}) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[2].String(), Version: 1}) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[3].String(), Version: 1}) + require.NoError(err) + + _, err = upgradeKeeper.TryUpgrade(goCtx, &types.MsgTryUpgrade{}) + require.Error(err) + require.ErrorIs(err, types.ErrInvalidUpgradeVersion) + }) +} + +func (s *TestSuite) TestGetUpgrade(t *testing.T) { + require := s.Require() + + ctx, upgradeKeeper := s.Ctx, s.UpgradeKeeper + goCtx := sdk.WrapSDKContext(ctx) + + t.Run("should return an empty upgrade if no upgrade is pending", func(t *testing.T) { + got, err := upgradeKeeper.GetUpgrade(ctx, &types.QueryGetUpgradeRequest{}) + require.NoError(err) + require.Nil(got.Upgrade) + }) + + t.Run("should return an upgrade if an upgrade is pending", func(t *testing.T) { + _, err := upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[0].String(), Version: 2}) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[1].String(), Version: 2}) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[2].String(), Version: 2}) + require.NoError(err) + _, err = upgradeKeeper.SignalVersion(ctx, &types.MsgSignalVersion{ValidatorAddress: testutil.ValAddrs[3].String(), Version: 2}) + require.NoError(err) + + // This TryUpgrade should succeed. + _, err = upgradeKeeper.TryUpgrade(goCtx, &types.MsgTryUpgrade{}) + require.NoError(err) + + got, err := upgradeKeeper.GetUpgrade(ctx, &types.QueryGetUpgradeRequest{}) + require.NoError(err) + require.Equal(2, got.Upgrade.AppVersion) + require.Equal(keeper.DefaultUpgradeHeightDelay, got.Upgrade.UpgradeHeight) + }) +} + +var _ types.StakingKeeper = (*mockStakingKeeper)(nil) + +type mockStakingKeeper struct { + totalVotingPower sdkmath.Int + validators map[string]int64 +} + +func newMockStakingKeeper(validators map[string]int64) *mockStakingKeeper { + totalVotingPower := sdkmath.NewInt(0) + for _, power := range validators { + totalVotingPower = totalVotingPower.AddRaw(power) + } + return &mockStakingKeeper{ + totalVotingPower: totalVotingPower, + validators: validators, + } +} + +func (m *mockStakingKeeper) GetLastTotalPower(ctx context.Context) (sdkmath.Int, error) { + return m.totalVotingPower, nil +} + +func (m *mockStakingKeeper) GetLastValidatorPower(_ context.Context, addr sdk.ValAddress) (power int64, err error) { + addrStr := addr.String() + if power, ok := m.validators[addrStr]; ok { + return power, nil + } + + return 0, nil +} + +func (m *mockStakingKeeper) GetValidator(_ context.Context, addr sdk.ValAddress) (validator stypes.Validator, err error) { + addrStr := addr.String() + if _, ok := m.validators[addrStr]; ok { + return stypes.Validator{Status: stypes.Bonded}, nil + } + + return stypes.Validator{}, errors.New("not found") +} diff --git a/client/x/signal/testutil/common.go b/client/x/signal/testutil/common.go new file mode 100644 index 00000000..62ccf741 --- /dev/null +++ b/client/x/signal/testutil/common.go @@ -0,0 +1,191 @@ +package testutil + +import ( + "bytes" + cosmosmath "cosmossdk.io/math" + sdkmath "cosmossdk.io/math" + tmed "github.com/cometbft/cometbft/crypto/ed25519" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + ccrypto "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + gethcommon "github.com/ethereum/go-ethereum/common" + "github.com/stretchr/testify/require" + "testing" +) + +var ( + // TestingStakeParams is a set of staking params for testing + TestingStakeParams = stakingtypes.Params{ + UnbondingTime: 100, + MaxValidators: 10, + MaxEntries: 10, + HistoricalEntries: 10000, + BondDenom: "stake", + MinCommissionRate: cosmosmath.LegacyNewDec(0), + } + + // HardcodedConsensusPrivKeys + FixedConsensusPrivKeys = []tmed.PrivKey{ + tmed.GenPrivKeyFromSecret([]byte("12345678901234567890123456389012")), + tmed.GenPrivKeyFromSecret([]byte("12345678901234567890123456389013")), + tmed.GenPrivKeyFromSecret([]byte("12345678901234567890123456389014")), + tmed.GenPrivKeyFromSecret([]byte("12345678901234567890123456389015")), + tmed.GenPrivKeyFromSecret([]byte("12345678901234567890123456389016")), + } + + FixedNetworkPrivKeys = []tmed.PrivKey{ + tmed.GenPrivKeyFromSecret([]byte("12345678901234567890123456786012")), + tmed.GenPrivKeyFromSecret([]byte("12345678901234567890123456786013")), + tmed.GenPrivKeyFromSecret([]byte("12345678901234567890123456786014")), + tmed.GenPrivKeyFromSecret([]byte("12345678901234567890123456786015")), + tmed.GenPrivKeyFromSecret([]byte("12345678901234567890123456786016")), + } + + // FixedMnemonics is a set of fixed mnemonics for testing. + // Account names are: validator1, validator2, validator3, validator4, validator5 + FixedMnemonics = []string{ + "body world north giggle crop reduce height copper damp next verify orphan lens loan adjust inform utility theory now ranch motion opinion crowd fun", + "body champion street fat bone above office guess waste vivid gift around approve elevator depth fiber alarm usual skirt like organ space antique silk", + "cheap alpha render punch clap prize duty drive steel situate person radar smooth elegant over chronic wait danger thumb soft letter spatial acquire rough", + "outdoor ramp suspect office disagree world attend vanish small wish capable fall wall soon damp session emotion chest toss viable meat host clerk truth", + "ability evidence casino cram weasel chest brush bridge sister blur onion found glad own mansion amateur expect force fun dragon famous alien appear open", + } + + // ConsPrivKeys generate ed25519 ConsPrivKeys to be used for validator operator keys + ConsPrivKeys = []ccrypto.PrivKey{ + ed25519.GenPrivKey(), + ed25519.GenPrivKey(), + ed25519.GenPrivKey(), + ed25519.GenPrivKey(), + ed25519.GenPrivKey(), + } + + // ConsPubKeys holds the consensus public keys to be used for validator operator keys + ConsPubKeys = []ccrypto.PubKey{ + ConsPrivKeys[0].PubKey(), + ConsPrivKeys[1].PubKey(), + ConsPrivKeys[2].PubKey(), + ConsPrivKeys[3].PubKey(), + ConsPrivKeys[4].PubKey(), + } + + // AccPrivKeys generate secp256k1 pubkeys to be used for account pub keys + AccPrivKeys = []ccrypto.PrivKey{ + secp256k1.GenPrivKey(), + secp256k1.GenPrivKey(), + secp256k1.GenPrivKey(), + secp256k1.GenPrivKey(), + secp256k1.GenPrivKey(), + } + + // AccPubKeys holds the pub keys for the account keys + AccPubKeys = []ccrypto.PubKey{ + AccPrivKeys[0].PubKey(), + AccPrivKeys[1].PubKey(), + AccPrivKeys[2].PubKey(), + AccPrivKeys[3].PubKey(), + AccPrivKeys[4].PubKey(), + } + + // AccAddrs holds the sdk.AccAddresses + AccAddrs = []sdk.AccAddress{ + sdk.AccAddress(AccPubKeys[0].Address()), + sdk.AccAddress(AccPubKeys[1].Address()), + sdk.AccAddress(AccPubKeys[2].Address()), + sdk.AccAddress(AccPubKeys[3].Address()), + sdk.AccAddress(AccPubKeys[4].Address()), + } + + // ValAddrs holds the sdk.ValAddresses + ValAddrs = []sdk.ValAddress{ + sdk.ValAddress(AccPubKeys[0].Address()), + sdk.ValAddress(AccPubKeys[1].Address()), + sdk.ValAddress(AccPubKeys[2].Address()), + sdk.ValAddress(AccPubKeys[3].Address()), + sdk.ValAddress(AccPubKeys[4].Address()), + } + + // EVMAddrs holds etheruem addresses + EVMAddrs = initEVMAddrs(100) + + // InitTokens holds the number of tokens to initialize an account with + InitTokens = sdk.TokensFromConsensusPower(110, sdk.DefaultPowerReduction) + + // InitCoins holds the number of coins to initialize an account with + InitCoins = sdk.NewCoins(sdk.NewCoin(TestingStakeParams.BondDenom, InitTokens)) + + // StakingAmount holds the staking power to start a validator with + StakingAmount = sdk.TokensFromConsensusPower(10, sdk.DefaultPowerReduction) +) + +func initEVMAddrs(count int) []gethcommon.Address { + addresses := make([]gethcommon.Address, count) + for i := 0; i < count; i++ { + evmAddr := gethcommon.BytesToAddress(bytes.Repeat([]byte{byte(i + 1)}, gethcommon.AddressLength)) + addresses[i] = evmAddr + } + return addresses +} + +// TestInput stores the various keepers required to test Blobstream +type TestInput struct { + AccountKeeper authkeeper.AccountKeeper + StakingKeeper stakingkeeper.Keeper + Context sdk.Context + Marshaler codec.Codec + LegacyAmino *codec.LegacyAmino +} + +func CreateValidator( + t *testing.T, + input TestInput, + accAddr sdk.AccAddress, + accPubKey ccrypto.PubKey, + accountNumber uint64, + valAddr sdk.ValAddress, + consPubKey ccrypto.PubKey, + stakingAmount cosmosmath.Int, +) { + // Initialize the account for the key + acc := input.AccountKeeper.NewAccount( + input.Context, + authtypes.NewBaseAccount(accAddr, accPubKey, accountNumber, 0), + ) + + // Set the account in state + input.AccountKeeper.SetAccount(input.Context, acc) + + // Create a validator for that account using some tokens in the account + // and the staking handler + msgServer := stakingkeeper.NewMsgServerImpl(&input.StakingKeeper) + _, err := msgServer.CreateValidator(input.Context, NewTestMsgCreateValidator(valAddr, consPubKey, stakingAmount)) + require.NoError(t, err) +} + +func NewTestMsgCreateValidator( + address sdk.ValAddress, + pubKey ccrypto.PubKey, + amt cosmosmath.Int, +) *stakingtypes.MsgCreateValidator { + commission := stakingtypes.NewCommissionRates(sdkmath.LegacyZeroDec(), sdkmath.LegacyZeroDec(), sdkmath.LegacyZeroDec()) + out, err := stakingtypes.NewMsgCreateValidator( + address.String(), pubKey, sdk.NewCoin("stake", amt), + stakingtypes.Description{ + Moniker: "", + Identity: "", + Website: "", + SecurityContact: "", + Details: "", + }, commission, sdkmath.OneInt(), + ) + if err != nil { + panic(err) + } + return out +} diff --git a/client/x/signal/testutil/expected_keepers_mocks.go b/client/x/signal/testutil/expected_keepers_mocks.go new file mode 100644 index 00000000..8dde94cd --- /dev/null +++ b/client/x/signal/testutil/expected_keepers_mocks.go @@ -0,0 +1,232 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: client/x/signal/types/expected_keepers.go +// +// Generated by this command: +// +// mockgen -source=client/x/signal/types/expected_keepers.go -package testutil -destination client/x/signal/testutil/expected_keepers_mocks.go +// + +// Package testutil is a generated GoMock package. +package testutil + +import ( + context "context" + reflect "reflect" + + address "cosmossdk.io/core/address" + math "cosmossdk.io/math" + types "github.com/cosmos/cosmos-sdk/types" + types0 "github.com/cosmos/cosmos-sdk/x/staking/types" + gomock "go.uber.org/mock/gomock" +) + +// MockAccountKeeper is a mock of AccountKeeper interface. +type MockAccountKeeper struct { + ctrl *gomock.Controller + recorder *MockAccountKeeperMockRecorder +} + +// MockAccountKeeperMockRecorder is the mock recorder for MockAccountKeeper. +type MockAccountKeeperMockRecorder struct { + mock *MockAccountKeeper +} + +// NewMockAccountKeeper creates a new mock instance. +func NewMockAccountKeeper(ctrl *gomock.Controller) *MockAccountKeeper { + mock := &MockAccountKeeper{ctrl: ctrl} + mock.recorder = &MockAccountKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAccountKeeper) EXPECT() *MockAccountKeeperMockRecorder { + return m.recorder +} + +// AddressCodec mocks base method. +func (m *MockAccountKeeper) AddressCodec() address.Codec { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddressCodec") + ret0, _ := ret[0].(address.Codec) + return ret0 +} + +// AddressCodec indicates an expected call of AddressCodec. +func (mr *MockAccountKeeperMockRecorder) AddressCodec() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddressCodec", reflect.TypeOf((*MockAccountKeeper)(nil).AddressCodec)) +} + +// GetAccount mocks base method. +func (m *MockAccountKeeper) GetAccount(ctx context.Context, addr types.AccAddress) types.AccountI { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAccount", ctx, addr) + ret0, _ := ret[0].(types.AccountI) + return ret0 +} + +// GetAccount indicates an expected call of GetAccount. +func (mr *MockAccountKeeperMockRecorder) GetAccount(ctx, addr any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetAccount), ctx, addr) +} + +// GetModuleAccount mocks base method. +func (m *MockAccountKeeper) GetModuleAccount(ctx context.Context, moduleName string) types.ModuleAccountI { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetModuleAccount", ctx, moduleName) + ret0, _ := ret[0].(types.ModuleAccountI) + return ret0 +} + +// GetModuleAccount indicates an expected call of GetModuleAccount. +func (mr *MockAccountKeeperMockRecorder) GetModuleAccount(ctx, moduleName any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAccount), ctx, moduleName) +} + +// GetModuleAddress mocks base method. +func (m *MockAccountKeeper) GetModuleAddress(moduleName string) types.AccAddress { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetModuleAddress", moduleName) + ret0, _ := ret[0].(types.AccAddress) + return ret0 +} + +// GetModuleAddress indicates an expected call of GetModuleAddress. +func (mr *MockAccountKeeperMockRecorder) GetModuleAddress(moduleName any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetModuleAddress", reflect.TypeOf((*MockAccountKeeper)(nil).GetModuleAddress), moduleName) +} + +// HasAccount mocks base method. +func (m *MockAccountKeeper) HasAccount(ctx context.Context, addr types.AccAddress) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasAccount", ctx, addr) + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasAccount indicates an expected call of HasAccount. +func (mr *MockAccountKeeperMockRecorder) HasAccount(ctx, addr any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasAccount", reflect.TypeOf((*MockAccountKeeper)(nil).HasAccount), ctx, addr) +} + +// IterateAccounts mocks base method. +func (m *MockAccountKeeper) IterateAccounts(ctx context.Context, process func(types.AccountI) bool) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "IterateAccounts", ctx, process) +} + +// IterateAccounts indicates an expected call of IterateAccounts. +func (mr *MockAccountKeeperMockRecorder) IterateAccounts(ctx, process any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateAccounts", reflect.TypeOf((*MockAccountKeeper)(nil).IterateAccounts), ctx, process) +} + +// NewAccountWithAddress mocks base method. +func (m *MockAccountKeeper) NewAccountWithAddress(ctx context.Context, addr types.AccAddress) types.AccountI { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewAccountWithAddress", ctx, addr) + ret0, _ := ret[0].(types.AccountI) + return ret0 +} + +// NewAccountWithAddress indicates an expected call of NewAccountWithAddress. +func (mr *MockAccountKeeperMockRecorder) NewAccountWithAddress(ctx, addr any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewAccountWithAddress", reflect.TypeOf((*MockAccountKeeper)(nil).NewAccountWithAddress), ctx, addr) +} + +// SetAccount mocks base method. +func (m *MockAccountKeeper) SetAccount(ctx context.Context, acc types.AccountI) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetAccount", ctx, acc) +} + +// SetAccount indicates an expected call of SetAccount. +func (mr *MockAccountKeeperMockRecorder) SetAccount(ctx, acc any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccount", reflect.TypeOf((*MockAccountKeeper)(nil).SetAccount), ctx, acc) +} + +// SetModuleAccount mocks base method. +func (m *MockAccountKeeper) SetModuleAccount(ctx context.Context, modAcc types.ModuleAccountI) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetModuleAccount", ctx, modAcc) +} + +// SetModuleAccount indicates an expected call of SetModuleAccount. +func (mr *MockAccountKeeperMockRecorder) SetModuleAccount(ctx, modAcc any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetModuleAccount", reflect.TypeOf((*MockAccountKeeper)(nil).SetModuleAccount), ctx, modAcc) +} + +// MockStakingKeeper is a mock of StakingKeeper interface. +type MockStakingKeeper struct { + ctrl *gomock.Controller + recorder *MockStakingKeeperMockRecorder +} + +// MockStakingKeeperMockRecorder is the mock recorder for MockStakingKeeper. +type MockStakingKeeperMockRecorder struct { + mock *MockStakingKeeper +} + +// NewMockStakingKeeper creates a new mock instance. +func NewMockStakingKeeper(ctrl *gomock.Controller) *MockStakingKeeper { + mock := &MockStakingKeeper{ctrl: ctrl} + mock.recorder = &MockStakingKeeperMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockStakingKeeper) EXPECT() *MockStakingKeeperMockRecorder { + return m.recorder +} + +// GetLastTotalPower mocks base method. +func (m *MockStakingKeeper) GetLastTotalPower(ctx context.Context) (math.Int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLastTotalPower", ctx) + ret0, _ := ret[0].(math.Int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLastTotalPower indicates an expected call of GetLastTotalPower. +func (mr *MockStakingKeeperMockRecorder) GetLastTotalPower(ctx any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastTotalPower", reflect.TypeOf((*MockStakingKeeper)(nil).GetLastTotalPower), ctx) +} + +// GetLastValidatorPower mocks base method. +func (m *MockStakingKeeper) GetLastValidatorPower(ctx context.Context, addr types.ValAddress) (int64, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLastValidatorPower", ctx, addr) + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetLastValidatorPower indicates an expected call of GetLastValidatorPower. +func (mr *MockStakingKeeperMockRecorder) GetLastValidatorPower(ctx, addr any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastValidatorPower", reflect.TypeOf((*MockStakingKeeper)(nil).GetLastValidatorPower), ctx, addr) +} + +// GetValidator mocks base method. +func (m *MockStakingKeeper) GetValidator(ctx context.Context, addr types.ValAddress) (types0.Validator, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetValidator", ctx, addr) + ret0, _ := ret[0].(types0.Validator) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetValidator indicates an expected call of GetValidator. +func (mr *MockStakingKeeperMockRecorder) GetValidator(ctx, addr any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidator", reflect.TypeOf((*MockStakingKeeper)(nil).GetValidator), ctx, addr) +} From 48960aafab3a9036828d11cff70c94431a42e48c Mon Sep 17 00:00:00 2001 From: Jongwon Park Date: Tue, 17 Sep 2024 22:43:16 -0500 Subject: [PATCH 4/6] feat(app): add signal module in app wiring --- client/app/app.go | 1 + client/app/app_config.go | 11 +++++++++++ client/app/keepers/types.go | 2 ++ 3 files changed, 14 insertions(+) diff --git a/client/app/app.go b/client/app/app.go index 094aafd6..0f401449 100644 --- a/client/app/app.go +++ b/client/app/app.go @@ -86,6 +86,7 @@ func newApp( &app.interfaceRegistry, &app.Keepers.AccountKeeper, &app.Keepers.BankKeeper, + &app.Keepers.SignalKeeper, &app.Keepers.StakingKeeper, &app.Keepers.SlashingKeeper, &app.Keepers.DistrKeeper, diff --git a/client/app/app_config.go b/client/app/app_config.go index faee4920..7a5b12b1 100644 --- a/client/app/app_config.go +++ b/client/app/app_config.go @@ -36,6 +36,8 @@ import ( evmenginetypes "github.com/piplabs/story/client/x/evmengine/types" evmstakingmodule "github.com/piplabs/story/client/x/evmstaking/module" evmstakingtypes "github.com/piplabs/story/client/x/evmstaking/types" + signalmodule "github.com/piplabs/story/client/x/signal/module" + signaltypes "github.com/piplabs/story/client/x/signal/types" ) // Bech32HRP is the human-readable-part of the Bech32 address format. @@ -89,6 +91,7 @@ var ( epochstypes.ModuleName, evmenginetypes.ModuleName, evmstakingtypes.ModuleName, + signaltypes.ModuleName, } // NOTE: upgrade module must come first, as upgrades might break state schema. @@ -106,11 +109,13 @@ var ( distrtypes.ModuleName, // Note: slashing happens after distr.BeginBlocker slashingtypes.ModuleName, stakingtypes.ModuleName, + signaltypes.ModuleName, } endBlockers = []string{ govtypes.ModuleName, evmstakingtypes.ModuleName, // Must be before staking module removes mature unbonding delegations & validators. + signaltypes.ModuleName, } // blocked account addresses. @@ -122,6 +127,7 @@ var ( stakingtypes.NotBondedPoolName, evmstakingtypes.ModuleName, epochstypes.ModuleName, + signaltypes.ModuleName, } moduleAccPerms = []*authmodulev1.ModuleAccountPermission{ @@ -132,6 +138,7 @@ var ( {Account: stakingtypes.NotBondedPoolName, Permissions: []string{authtypes.Burner, authtypes.Staking}}, {Account: evmstakingtypes.ModuleName, Permissions: []string{authtypes.Burner, authtypes.Minter}}, {Account: govtypes.ModuleName, Permissions: []string{authtypes.Burner}}, + {Account: signaltypes.ModuleName}, } // appConfig application configuration (used by depinject). @@ -213,6 +220,10 @@ var ( Name: evmenginetypes.ModuleName, Config: appconfig.WrapAny(&evmenginemodule.Module{}), }, + { + Name: signaltypes.ModuleName, + Config: appconfig.WrapAny(&signalmodule.Module{}), + }, { Name: minttypes.ModuleName, Config: appconfig.WrapAny(&mintmodulev1.Module{}), diff --git a/client/app/keepers/types.go b/client/app/keepers/types.go index 7b21abdc..430dd690 100644 --- a/client/app/keepers/types.go +++ b/client/app/keepers/types.go @@ -18,6 +18,7 @@ import ( epochskeeper "github.com/piplabs/story/client/x/epochs/keeper" evmengkeeper "github.com/piplabs/story/client/x/evmengine/keeper" evmstakingkeeper "github.com/piplabs/story/client/x/evmstaking/keeper" + signalkeeper "github.com/piplabs/story/client/x/signal/keeper" ) // Keepers includes all possible keepers. We separated it into a separate struct to make it easier to scaffold upgrades. @@ -25,6 +26,7 @@ type Keepers struct { // keepers AccountKeeper authkeeper.AccountKeeper BankKeeper bankkeeper.Keeper + SignalKeeper signalkeeper.Keeper SlashingKeeper slashingkeeper.Keeper StakingKeeper *stakingkeeper.Keeper DistrKeeper distrkeeper.Keeper From 8025e15d2169d5090753fe7534213c92706d3d71 Mon Sep 17 00:00:00 2001 From: Jongwon Park Date: Tue, 17 Sep 2024 23:03:15 -0500 Subject: [PATCH 5/6] chore(x/signal): comment and regenerate proto --- client/x/signal/cli/cli_test.go | 47 ----- client/x/signal/keeper/keeper.go | 4 +- client/x/signal/keeper/keeper_test.go | 3 +- client/x/signal/legacy_test.go | 204 --------------------- client/x/signal/module/module.go | 9 +- client/x/signal/types/codec.go | 2 +- client/x/signal/types/query.pb.gw.go | 254 -------------------------- client/x/signal/types/tx.pb.gw.go | 254 -------------------------- client/x/signal/types/tx.proto | 2 +- 9 files changed, 7 insertions(+), 772 deletions(-) delete mode 100644 client/x/signal/cli/cli_test.go delete mode 100644 client/x/signal/legacy_test.go delete mode 100644 client/x/signal/types/query.pb.gw.go delete mode 100644 client/x/signal/types/tx.pb.gw.go diff --git a/client/x/signal/cli/cli_test.go b/client/x/signal/cli/cli_test.go deleted file mode 100644 index 94a7a030..00000000 --- a/client/x/signal/cli/cli_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package cli_test - -import ( - "testing" - - "github.com/celestiaorg/celestia-app/v3/test/util/testnode" - testutil "github.com/cosmos/cosmos-sdk/testutil/cli" - "github.com/piplabs/story/client/x/signal/cli" - "github.com/stretchr/testify/suite" -) - -func TestCLITestSuite(t *testing.T) { - if testing.Short() { - t.Skip("skipping upgrade CLI test in short mode") - } - suite.Run(t, new(CLITestSuite)) -} - -type CLITestSuite struct { - suite.Suite - - ctx testnode.Context -} - -func (s *CLITestSuite) SetupSuite() { - s.T().Log("setting up CLI test suite") - ctx, _, _ := testnode.NewNetwork(s.T(), testnode.DefaultConfig()) - s.ctx = ctx - _, err := s.ctx.WaitForHeight(1) - s.Require().NoError(err) -} - -func (s *CLITestSuite) TestCmdQueryTally() { - cmd := cli.CmdQueryTally() - output, err := testutil.ExecTestCLICmd(s.ctx.Context, cmd, []string{"1"}) - s.Require().NoError(err) - s.Require().Contains(output.String(), "voting_power") - s.Require().Contains(output.String(), "threshold_power") - s.Require().Contains(output.String(), "total_voting_power") -} - -func (s *CLITestSuite) TestCmdGetUpgrade() { - cmd := cli.CmdGetUpgrade() - output, err := testutil.ExecTestCLICmd(s.ctx.Context, cmd, []string{}) - s.Require().NoError(err) - s.Require().Contains(output.String(), "No upgrade is pending.") -} diff --git a/client/x/signal/keeper/keeper.go b/client/x/signal/keeper/keeper.go index 32a5f54f..c7a5dbb4 100644 --- a/client/x/signal/keeper/keeper.go +++ b/client/x/signal/keeper/keeper.go @@ -22,8 +22,8 @@ const DefaultUpgradeHeightDelay = int64(7 * 24 * 60 * 60 / 12) // 7 days * 24 ho // Keeper implements the MsgServer and QueryServer interfaces. var ( - _ types.MsgServer = &Keeper{} - _ types.QueryServer = Keeper{} + _ types.MsgServiceServer = &Keeper{} + _ types.QueryServer = Keeper{} // defaultSignalThreshold is 5/6 or approximately 83.33%. defaultSignalThreshold = sdkmath.LegacyNewDec(5).Quo(sdkmath.LegacyNewDec(6)) diff --git a/client/x/signal/keeper/keeper_test.go b/client/x/signal/keeper/keeper_test.go index 32e75957..fb5998b2 100644 --- a/client/x/signal/keeper/keeper_test.go +++ b/client/x/signal/keeper/keeper_test.go @@ -15,7 +15,6 @@ import ( storetypes "cosmossdk.io/store/types" cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" tmversion "github.com/cometbft/cometbft/proto/tendermint/version" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/codec" @@ -280,7 +279,7 @@ func (s *TestSuite) TestTallyingLogic(t *testing.T) { upgradeKeeper.ResetTally(ctx) // update the version to 2 - ctx = ctx.WithBlockHeader(tmproto.Header{ + ctx = ctx.WithBlockHeader(cmtproto.Header{ Version: tmversion.Consensus{ Block: 1, App: 2, diff --git a/client/x/signal/legacy_test.go b/client/x/signal/legacy_test.go deleted file mode 100644 index 21f2695a..00000000 --- a/client/x/signal/legacy_test.go +++ /dev/null @@ -1,204 +0,0 @@ -package signal_test - -import ( - "context" - "sync" - "testing" - "time" - - "github.com/celestiaorg/celestia-app/v3/app" - "github.com/celestiaorg/celestia-app/v3/app/encoding" - "github.com/celestiaorg/celestia-app/v3/pkg/user" - testutil "github.com/celestiaorg/celestia-app/v3/test/util" - "github.com/celestiaorg/celestia-app/v3/test/util/blobfactory" - "github.com/celestiaorg/celestia-app/v3/test/util/genesis" - "github.com/celestiaorg/celestia-app/v3/test/util/testnode" - "github.com/cosmos/cosmos-sdk/crypto/keyring" - sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" - v1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" - "github.com/cosmos/cosmos-sdk/x/upgrade/types" - ibctypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types" - ibctmtypes "github.com/cosmos/ibc-go/v6/modules/light-clients/07-tendermint/types" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" - tmrand "github.com/tendermint/tendermint/libs/rand" -) - -func TestLegacyUpgrade(t *testing.T) { - if testing.Short() { - t.Skip("skipping x/upgrade SDK integration test in short mode.") - } - suite.Run(t, new(LegacyUpgradeTestSuite)) -} - -// TestRemoval verifies that no handler exists for msg-based software upgrade -// proposals. -func TestRemoval(t *testing.T) { - app, _ := testutil.SetupTestAppWithGenesisValSet(app.DefaultConsensusParams()) - msgSoftwareUpgrade := types.MsgSoftwareUpgrade{} - router := app.MsgServiceRouter() - handler := router.Handler(&msgSoftwareUpgrade) - require.Nil(t, handler) -} - -type LegacyUpgradeTestSuite struct { - suite.Suite - - accounts []string - cctx testnode.Context - ecfg encoding.Config - - govModuleAddress string - - mut sync.Mutex - accountCounter int -} - -// SetupSuite inits a standard chain, with the only exception being a -// dramatically lowered quorum and threshold to pass proposals -func (s *LegacyUpgradeTestSuite) SetupSuite() { - t := s.T() - - s.ecfg = encoding.MakeConfig(app.ModuleBasics) - - // we create an arbitrary number of funded accounts - accounts := make([]string, 3) - for i := 0; i < len(accounts); i++ { - accounts[i] = tmrand.Str(9) - } - - cfg := testnode.DefaultConfig(). - WithFundedAccounts(accounts...). - WithModifiers(genesis.ImmediateProposals(s.ecfg.Codec)) - - cctx, _, _ := testnode.NewNetwork(t, cfg) - - s.accounts = accounts - s.cctx = cctx - require.NoError(t, s.cctx.WaitForNextBlock()) - - // Retrieve the gov module account via grpc - aqc := authtypes.NewQueryClient(s.cctx.GRPCClient) - resp, err := aqc.ModuleAccountByName( - s.cctx.GoContext(), &authtypes.QueryModuleAccountByNameRequest{Name: "gov"}, - ) - s.Require().NoError(err) - var acc authtypes.AccountI - err = s.ecfg.InterfaceRegistry.UnpackAny(resp.Account, &acc) - s.Require().NoError(err) - - // Set the gov module address - s.govModuleAddress = acc.GetAddress().String() -} - -func (s *LegacyUpgradeTestSuite) unusedAccount() string { - s.mut.Lock() - acc := s.accounts[s.accountCounter] - s.accountCounter++ - s.mut.Unlock() - return acc -} - -// TestLegacyGovUpgradeFailure verifies that a transaction with a legacy -// software upgrade proposal fails to execute. -func (s *LegacyUpgradeTestSuite) TestLegacyGovUpgradeFailure() { - t := s.T() - - dep := sdk.NewCoins(sdk.NewCoin(app.BondDenom, sdk.NewInt(1000000000000))) - acc := s.unusedAccount() - accAddr := getAddress(acc, s.cctx.Keyring) - - sftwr := types.NewSoftwareUpgradeProposal("v1", "Social Consensus", types.Plan{ - Name: "v1", - Height: 20, - Info: "rough social consensus", - }) - - msg, err := v1beta1.NewMsgSubmitProposal(sftwr, dep, accAddr) - require.NoError(t, err) - - // submit the transaction and wait a block for it to be included - txClient, err := testnode.NewTxClientFromContext(s.cctx) - require.NoError(t, err) - subCtx, cancel := context.WithTimeout(s.cctx.GoContext(), time.Minute) - defer cancel() - _, err = txClient.SubmitTx(subCtx, []sdk.Msg{msg}, blobfactory.DefaultTxOpts()...) - code := err.(*user.BroadcastTxError).Code - // As the type is not registered, the message will fail with unable to resolve type URL - require.EqualValues(t, 2, code, err.Error()) -} - -// TestNewGovUpgradeFailure verifies that a transaction with a -// MsgSoftwareUpgrade fails to execute. -func (s *LegacyUpgradeTestSuite) TestNewGovUpgradeFailure() { - t := s.T() - sss := types.MsgSoftwareUpgrade{ - Authority: s.govModuleAddress, - Plan: types.Plan{ - Name: "v1", - Height: 20, - Info: "rough social consensus", - }, - } - dep := sdk.NewCoins(sdk.NewCoin(app.BondDenom, sdk.NewInt(1000000000000))) - acc := s.unusedAccount() - accAddr := getAddress(acc, s.cctx.Keyring) - msg, err := v1.NewMsgSubmitProposal([]sdk.Msg{&sss}, dep, accAddr.String(), "") - require.NoError(t, err) - - // submit the transaction and wait a block for it to be included - txClient, err := testnode.NewTxClientFromContext(s.cctx) - require.NoError(t, err) - subCtx, cancel := context.WithTimeout(s.cctx.GoContext(), time.Minute) - defer cancel() - _, err = txClient.SubmitTx(subCtx, []sdk.Msg{msg}, blobfactory.DefaultTxOpts()...) - // As the type is not registered, the message will fail with unable to resolve type URL - require.Error(t, err) - code := err.(*user.BroadcastTxError).Code - require.EqualValues(t, 2, code, err.Error()) -} - -func (s *LegacyUpgradeTestSuite) TestIBCUpgradeFailure() { - t := s.T() - plan := types.Plan{ - Name: "v2", - Height: 20, - Info: "this should not pass", - } - upgradedClientState := &ibctmtypes.ClientState{} - - upgradeMsg, err := ibctypes.NewUpgradeProposal("Upgrade to v2!", "Upgrade to v2!", plan, upgradedClientState) - require.NoError(t, err) - - dep := sdk.NewCoins(sdk.NewCoin(app.BondDenom, sdk.NewInt(1000000000000))) - acc := s.unusedAccount() - accAddr := getAddress(acc, s.cctx.Keyring) - msg, err := v1beta1.NewMsgSubmitProposal(upgradeMsg, dep, accAddr) - require.NoError(t, err) - - // submit the transaction and wait a block for it to be included - txClient, err := testnode.NewTxClientFromContext(s.cctx) - require.NoError(t, err) - subCtx, cancel := context.WithTimeout(s.cctx.GoContext(), time.Minute) - defer cancel() - _, err = txClient.SubmitTx(subCtx, []sdk.Msg{msg}, blobfactory.DefaultTxOpts()...) - require.Error(t, err) - code := err.(*user.ExecutionError).Code - require.EqualValues(t, 9, code) // we're only submitting the tx, so we expect everything to work - assert.Contains(t, err.Error(), "ibc upgrade proposal not supported") -} - -func getAddress(account string, kr keyring.Keyring) sdk.AccAddress { - rec, err := kr.Key(account) - if err != nil { - panic(err) - } - addr, err := rec.GetAddress() - if err != nil { - panic(err) - } - return addr -} diff --git a/client/x/signal/module/module.go b/client/x/signal/module/module.go index a0488724..8225c25d 100644 --- a/client/x/signal/module/module.go +++ b/client/x/signal/module/module.go @@ -1,7 +1,6 @@ package module import ( - "context" "cosmossdk.io/core/appmodule" "encoding/json" "github.com/piplabs/story/client/x/signal/keeper" @@ -54,11 +53,7 @@ func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) } // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the upgrade module. -func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) { - if err := types.RegisterQueryHandlerClient(context.Background(), mux, types.NewQueryClient(clientCtx)); err != nil { - panic(err) - } -} +func (AppModuleBasic) RegisterGRPCGatewayRoutes(_ client.Context, _ *runtime.ServeMux) {} // GetQueryCmd returns the CLI query commands for this module. func (AppModuleBasic) GetQueryCmd() *cobra.Command { @@ -119,7 +114,7 @@ func (AppModule) QuerierRoute() string { // RegisterServices registers module services. func (am AppModule) RegisterServices(cfg module.Configurator) { - types.RegisterMsgServer(cfg.MsgServer(), am.keeper) + types.RegisterMsgServiceServer(cfg.MsgServer(), am.keeper) types.RegisterQueryServer(cfg.QueryServer(), am.keeper) } diff --git a/client/x/signal/types/codec.go b/client/x/signal/types/codec.go index 49a08996..f3887903 100644 --- a/client/x/signal/types/codec.go +++ b/client/x/signal/types/codec.go @@ -19,5 +19,5 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { func RegisterInterfaces(registry codectypes.InterfaceRegistry) { registry.RegisterImplementations((*sdk.Msg)(nil), &MsgTryUpgrade{}) registry.RegisterImplementations((*sdk.Msg)(nil), &MsgSignalVersion{}) - msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) + msgservice.RegisterMsgServiceDesc(registry, &_MsgService_serviceDesc) } diff --git a/client/x/signal/types/query.pb.gw.go b/client/x/signal/types/query.pb.gw.go deleted file mode 100644 index c28aa9a3..00000000 --- a/client/x/signal/types/query.pb.gw.go +++ /dev/null @@ -1,254 +0,0 @@ -// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: celestia/signal/v1/query.proto - -/* -Package types is a reverse proxy. - -It translates gRPC into RESTful JSON APIs. -*/ -package types - -import ( - "context" - "io" - "net/http" - - "github.com/golang/protobuf/descriptor" - "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/utilities" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" -) - -// Suppress "imported and not used" errors -var _ codes.Code -var _ io.Reader -var _ status.Status -var _ = runtime.String -var _ = utilities.NewDoubleArray -var _ = descriptor.ForMessage -var _ = metadata.Join - -func request_Query_VersionTally_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryVersionTallyRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["version"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "version") - } - - protoReq.Version, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "version", err) - } - - msg, err := client.VersionTally(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_VersionTally_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryVersionTallyRequest - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["version"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "version") - } - - protoReq.Version, err = runtime.Uint64(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "version", err) - } - - msg, err := server.VersionTally(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Query_GetUpgrade_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetUpgradeRequest - var metadata runtime.ServerMetadata - - msg, err := client.GetUpgrade(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Query_GetUpgrade_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq QueryGetUpgradeRequest - var metadata runtime.ServerMetadata - - msg, err := server.GetUpgrade(ctx, &protoReq) - return msg, metadata, err - -} - -// RegisterQueryHandlerServer registers the http handlers for service Query to "mux". -// UnaryRPC :call QueryServer directly. -// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterQueryHandlerFromEndpoint instead. -func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, server QueryServer) error { - - mux.Handle("GET", pattern_Query_VersionTally_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_VersionTally_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 { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_VersionTally_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetUpgrade_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Query_GetUpgrade_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 { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Query_GetUpgrade_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -// RegisterQueryHandlerFromEndpoint is same as RegisterQueryHandler but -// automatically dials to "endpoint" and closes the connection when "ctx" gets done. -func RegisterQueryHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.Dial(endpoint, opts...) - if err != nil { - return err - } - defer func() { - if err != nil { - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - return - } - go func() { - <-ctx.Done() - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - }() - }() - - return RegisterQueryHandler(ctx, mux, conn) -} - -// RegisterQueryHandler registers the http handlers for service Query to "mux". -// The handlers forward requests to the grpc endpoint over "conn". -func RegisterQueryHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - return RegisterQueryHandlerClient(ctx, mux, NewQueryClient(conn)) -} - -// RegisterQueryHandlerClient registers the http handlers for service Query -// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "QueryClient". -// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "QueryClient" -// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "QueryClient" to call the correct interceptors. -func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, client QueryClient) error { - - mux.Handle("GET", pattern_Query_VersionTally_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) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_VersionTally_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_VersionTally_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_Query_GetUpgrade_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) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Query_GetUpgrade_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_GetUpgrade_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -var ( - pattern_Query_VersionTally_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"signal", "v1", "tally", "version"}, "", runtime.AssumeColonVerbOpt(false))) - - pattern_Query_GetUpgrade_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"signal", "v1", "upgrade"}, "", runtime.AssumeColonVerbOpt(false))) -) - -var ( - forward_Query_VersionTally_0 = runtime.ForwardResponseMessage - - forward_Query_GetUpgrade_0 = runtime.ForwardResponseMessage -) diff --git a/client/x/signal/types/tx.pb.gw.go b/client/x/signal/types/tx.pb.gw.go deleted file mode 100644 index 9cb53050..00000000 --- a/client/x/signal/types/tx.pb.gw.go +++ /dev/null @@ -1,254 +0,0 @@ -// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. -// source: celestia/signal/v1/tx.proto - -/* -Package types is a reverse proxy. - -It translates gRPC into RESTful JSON APIs. -*/ -package types - -import ( - "context" - "io" - "net/http" - - "github.com/golang/protobuf/descriptor" - "github.com/golang/protobuf/proto" - "github.com/grpc-ecosystem/grpc-gateway/runtime" - "github.com/grpc-ecosystem/grpc-gateway/utilities" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/grpclog" - "google.golang.org/grpc/metadata" - "google.golang.org/grpc/status" -) - -// Suppress "imported and not used" errors -var _ codes.Code -var _ io.Reader -var _ status.Status -var _ = runtime.String -var _ = utilities.NewDoubleArray -var _ = descriptor.ForMessage -var _ = metadata.Join - -var ( - filter_Msg_SignalVersion_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - -func request_Msg_SignalVersion_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq MsgSignalVersion - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_SignalVersion_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.SignalVersion(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Msg_SignalVersion_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq MsgSignalVersion - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_SignalVersion_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.SignalVersion(ctx, &protoReq) - return msg, metadata, err - -} - -var ( - filter_Msg_TryUpgrade_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} -) - -func request_Msg_TryUpgrade_0(ctx context.Context, marshaler runtime.Marshaler, client MsgClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq MsgTryUpgrade - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_TryUpgrade_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := client.TryUpgrade(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Msg_TryUpgrade_0(ctx context.Context, marshaler runtime.Marshaler, server MsgServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq MsgTryUpgrade - var metadata runtime.ServerMetadata - - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Msg_TryUpgrade_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.TryUpgrade(ctx, &protoReq) - return msg, metadata, err - -} - -// RegisterMsgHandlerServer registers the http handlers for service Msg to "mux". -// UnaryRPC :call MsgServer directly. -// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterMsgHandlerFromEndpoint instead. -func RegisterMsgHandlerServer(ctx context.Context, mux *runtime.ServeMux, server MsgServer) error { - - mux.Handle("POST", pattern_Msg_SignalVersion_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Msg_SignalVersion_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 { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Msg_SignalVersion_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_Msg_TryUpgrade_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Msg_TryUpgrade_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 { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Msg_TryUpgrade_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -// RegisterMsgHandlerFromEndpoint is same as RegisterMsgHandler but -// automatically dials to "endpoint" and closes the connection when "ctx" gets done. -func RegisterMsgHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { - conn, err := grpc.Dial(endpoint, opts...) - if err != nil { - return err - } - defer func() { - if err != nil { - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - return - } - go func() { - <-ctx.Done() - if cerr := conn.Close(); cerr != nil { - grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr) - } - }() - }() - - return RegisterMsgHandler(ctx, mux, conn) -} - -// RegisterMsgHandler registers the http handlers for service Msg to "mux". -// The handlers forward requests to the grpc endpoint over "conn". -func RegisterMsgHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { - return RegisterMsgHandlerClient(ctx, mux, NewMsgClient(conn)) -} - -// RegisterMsgHandlerClient registers the http handlers for service Msg -// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "MsgClient". -// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "MsgClient" -// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in -// "MsgClient" to call the correct interceptors. -func RegisterMsgHandlerClient(ctx context.Context, mux *runtime.ServeMux, client MsgClient) error { - - mux.Handle("POST", pattern_Msg_SignalVersion_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) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Msg_SignalVersion_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Msg_SignalVersion_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_Msg_TryUpgrade_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) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Msg_TryUpgrade_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_Msg_TryUpgrade_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - -var ( - pattern_Msg_SignalVersion_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 0}, []string{"signal", "v1"}, "", runtime.AssumeColonVerbOpt(false))) - - pattern_Msg_TryUpgrade_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"signal", "v1", "upgrade"}, "", runtime.AssumeColonVerbOpt(false))) -) - -var ( - forward_Msg_SignalVersion_0 = runtime.ForwardResponseMessage - - forward_Msg_TryUpgrade_0 = runtime.ForwardResponseMessage -) diff --git a/client/x/signal/types/tx.proto b/client/x/signal/types/tx.proto index b46d1981..b5a71ecd 100644 --- a/client/x/signal/types/tx.proto +++ b/client/x/signal/types/tx.proto @@ -6,7 +6,7 @@ import "google/api/annotations.proto"; option go_package = "client/x/signal/types"; -// Msg defines the signal Msg service. +// MsgService defines the signal Msg service. service MsgService { option (cosmos.msg.v1.service) = true; From 1303a6774aeff103eeb6cb6d12be0ff45203488a Mon Sep 17 00:00:00 2001 From: Jongwon Park Date: Tue, 15 Oct 2024 17:31:09 -0500 Subject: [PATCH 6/6] feat: single binary upgrade mods --- client/app/app.go | 142 ++- client/app/app_config.go | 13 - client/app/encoding.go | 50 + client/app/module/configurator.go | 128 +++ client/app/module/module.go | 1011 ++++++++++++++++++ client/app/module/types.go | 12 + client/app/module/utils.go | 43 + client/app/modules.go | 192 ++++ client/app/start.go | 1 + client/app/upgrades.go | 82 -- client/app/upgrades/historical.go | 92 -- client/app/upgrades/types.go | 39 - client/app/upgrades/v0_10_0/constants.go | 16 - client/app/upgrades/v0_10_0/upgrades.go | 64 -- client/pkg/appconsts/v1/app_consts.go | 5 + client/x/evmengine/keeper/keeper.go | 6 +- client/x/evmengine/keeper/upgrades.go | 9 +- client/x/evmengine/types/expected_keepers.go | 7 +- client/x/signal/keeper/keeper.go | 132 +-- client/x/signal/types/query.proto | 17 - client/x/signal/types/tx.proto | 3 - 21 files changed, 1572 insertions(+), 492 deletions(-) create mode 100644 client/app/encoding.go create mode 100644 client/app/module/configurator.go create mode 100644 client/app/module/module.go create mode 100644 client/app/module/types.go create mode 100644 client/app/module/utils.go create mode 100644 client/app/modules.go delete mode 100644 client/app/upgrades.go delete mode 100644 client/app/upgrades/historical.go delete mode 100644 client/app/upgrades/types.go delete mode 100644 client/app/upgrades/v0_10_0/constants.go delete mode 100644 client/app/upgrades/v0_10_0/upgrades.go create mode 100644 client/pkg/appconsts/v1/app_consts.go diff --git a/client/app/app.go b/client/app/app.go index 0f401449..a3b1955f 100644 --- a/client/app/app.go +++ b/client/app/app.go @@ -3,9 +3,8 @@ package app import ( "cosmossdk.io/depinject" "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" upgradekeeper "cosmossdk.io/x/upgrade/keeper" - - abci "github.com/cometbft/cometbft/abci/types" dbm "github.com/cosmos/cosmos-db" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" @@ -14,15 +13,19 @@ import ( "github.com/cosmos/cosmos-sdk/runtime" servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/version" authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + "io" "github.com/piplabs/story/client/app/keepers" + "github.com/piplabs/story/client/app/module" "github.com/piplabs/story/client/comet" + appv1 "github.com/piplabs/story/client/pkg/appconsts/v1" evmstakingkeeper "github.com/piplabs/story/client/x/evmstaking/keeper" "github.com/piplabs/story/lib/errors" "github.com/piplabs/story/lib/ethclient" @@ -43,6 +46,11 @@ import ( const Name = "story" +const ( + v1 = appv1.Version + DefaultInitialVersion = v1 +) + var ( _ runtime.AppI = (*App)(nil) _ servertypes.Application = (*App)(nil) @@ -59,6 +67,13 @@ type App struct { interfaceRegistry codectypes.InterfaceRegistry Keepers keepers.Keepers + + keyVersions map[uint64][]string + keys map[string]*storetypes.KVStoreKey + + // override the runtime baseapp's module manager to use the custom module manager + ModuleManager *module.Manager + configurator module.Configurator } // newApp returns a reference to an initialized App. @@ -66,6 +81,7 @@ func newApp( logger log.Logger, db dbm.DB, engineCl ethclient.EngineClient, + traceStore io.Writer, baseAppOpts ...func(*baseapp.BaseApp), ) (*App, error) { depCfg := depinject.Configs( @@ -75,15 +91,20 @@ func newApp( ), ) + encodingConfig := MakeEncodingConfig(ModuleEncodingRegisters...) + appCodec := encodingConfig.Codec + txConfig := encodingConfig.TxConfig + interfaceRegistry := encodingConfig.InterfaceRegistry + var ( app = new(App) appBuilder = new(runtime.AppBuilder) ) if err := depinject.Inject(depCfg, &appBuilder, - &app.appCodec, - &app.txConfig, - &app.interfaceRegistry, + &appCodec, + &txConfig, + &interfaceRegistry, &app.Keepers.AccountKeeper, &app.Keepers.BankKeeper, &app.Keepers.SignalKeeper, @@ -92,15 +113,16 @@ func newApp( &app.Keepers.DistrKeeper, &app.Keepers.ConsensusParamsKeeper, &app.Keepers.GovKeeper, - &app.Keepers.UpgradeKeeper, + // Story modules &app.Keepers.EpochsKeeper, &app.Keepers.EvmStakingKeeper, &app.Keepers.EVMEngKeeper, + &app.Keepers.SignalKeeper, ); err != nil { return nil, errors.Wrap(err, "dep inject") } - baseAppOpts = append(baseAppOpts, func(bapp *baseapp.BaseApp) { + prepareOpt := func(bapp *baseapp.BaseApp) { // Use evm engine to create block proposals. // Note that we do not check MaxTxBytes since all EngineEVM transaction MUST be included since we cannot // postpone them to the next block. Nit: we could drop some vote extensions though...? @@ -108,40 +130,29 @@ func newApp( // Route proposed messages to keepers for verification and external state updates. bapp.SetProcessProposal(makeProcessProposalHandler(makeProcessProposalRouter(app), app.txConfig)) - }) - - app.App = appBuilder.Build(db, nil, baseAppOpts...) - // Override the preblockers with custom PreBlocker function, which handles forks. - { - app.ModuleManager.SetOrderPreBlockers(preBlockers...) - app.SetPreBlocker(app.PreBlocker) + // This is to set the Cosmos SDK version used by the app. + // The app's version is set with bapp.SetProtocolVersion() + bapp.SetVersion(version.Version) } + baseAppOpts = append(baseAppOpts, prepareOpt) - // Set "OrderEndBlockers" directly instead of using "SetOrderEndBlockers," which will panic since the staking module - // is missing in the "endBlockers", which is an intended behavior in Story. The panic message is: - // `panic: all modules must be defined when setting SetOrderEndBlockers, missing: [staking]` - { - app.ModuleManager.OrderEndBlockers = endBlockers - app.SetEndBlocker(app.EndBlocker) - } + app.App = appBuilder.Build(db, traceStore, baseAppOpts...) + app.keys = storetypes.NewKVStoreKeys(allStoreKeys()...) // TODO: ensure DI injected keys are matched here + app.keyVersions = versionedStoreKeys() - // Need to manually set the module version map, otherwise dep inject will NOT call `SetModuleVersionMap` for - // whatever reason that needs to be investigated. Since `SetModuleVersionMap` is not called, `fromVM` will have - // no entries (i.e. does not know about each module's consensus version) and will try to "add" modules during an - // upgrade. Specifically, the upgrade module will try to add all modules as new from version 0 to the latest version - // of each module since `fromVM` is empty on the very first upgrade. - app.SetInitChainer(func(ctx sdk.Context, req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { - err := app.Keepers.UpgradeKeeper.SetModuleVersionMap(ctx, app.ModuleManager.GetVersionMap()) - if err != nil { - return nil, errors.Wrap(err, "set module version map") - } + //app.ModuleManager.RegisterInvariants(&app.CrisisKeeper) + app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) + app.ModuleManager.RegisterServices(app.configurator) - return app.App.InitChainer(ctx, req) - }) + // NOTE: Modules can't be modified or else must be passed by reference to the module manager + err := app.setupModuleManager() + if err != nil { + panic(err) + } - app.setupUpgradeHandlers() - app.setupUpgradeStoreLoaders() + // override module orders after DI + app.setModuleOrder() if err := app.Load(true); err != nil { return nil, errors.Wrap(err, "load app") @@ -150,14 +161,19 @@ func newApp( return app, nil } -// PreBlocker application updates every pre block. -func (a *App) PreBlocker(ctx sdk.Context, _ *abci.RequestFinalizeBlock) (*sdk.ResponsePreBlock, error) { - // All forks should be executed at their planned upgrade heights before any modules. - a.scheduleForkUpgrade(ctx) - - res, err := a.ModuleManager.PreBlock(ctx) +// EndBlocker executes application updates at the end of every block. +func (a *App) EndBlocker(ctx sdk.Context) (sdk.EndBlock, error) { + res, err := a.ModuleManager.EndBlock(ctx) if err != nil { - return nil, errors.Wrap(err, "module manager preblocker") + return sdk.EndBlock{}, errors.Wrap(err, "module manager endblocker") + } + + currentVersion := a.AppVersion() + if shouldUpgrade, newVersion := a.Keepers.SignalKeeper.ShouldUpgrade(ctx); shouldUpgrade { + // Version changes must be increasing. Downgrades are not permitted + if newVersion > currentVersion { + a.SetProtocolVersion(newVersion) + } } return res, nil @@ -181,6 +197,46 @@ func (a App) SetCometAPI(api comet.API) { a.Keepers.EVMEngKeeper.SetCometAPI(api) } +// LoadHeight loads a particular height +func (a *App) LoadHeight(height int64) error { + return a.LoadVersion(height) +} + +// SupportedVersions returns all the state machines that the +// application supports +func (a *App) SupportedVersions() []uint64 { + return a.ModuleManager.SupportedVersions() +} + +// versionedKeys returns a map from moduleName to KV store key for the given app +// version. +func (a *App) versionedKeys(appVersion uint64) map[string]*storetypes.KVStoreKey { + output := make(map[string]*storetypes.KVStoreKey) + if keys, exists := a.keyVersions[appVersion]; exists { + for _, moduleName := range keys { + if key, exists := a.keys[moduleName]; exists { + output[moduleName] = key + } + } + } + return output +} + +// baseKeys returns the base keys that are mounted to every version +func (app *App) baseKeys() map[string]*storetypes.KVStoreKey { + return map[string]*storetypes.KVStoreKey{ + // we need to know the app version to know what stores to mount + // thus the paramstore must always be a store that is mounted + paramstypes.StoreKey: app.keys[paramstypes.StoreKey], + } +} + +// migrateModules performs migrations on existing modules that have registered migrations +// between versions and initializes the state of new modules for the specified app version. +func (a App) migrateModules(ctx sdk.Context, fromVersion, toVersion uint64) error { + return a.ModuleManager.RunMigrations(ctx, a.configurator, fromVersion, toVersion) +} + func (a App) GetEvmStakingKeeper() *evmstakingkeeper.Keeper { return a.Keepers.EvmStakingKeeper } diff --git a/client/app/app_config.go b/client/app/app_config.go index 7a5b12b1..adcf8330 100644 --- a/client/app/app_config.go +++ b/client/app/app_config.go @@ -13,11 +13,8 @@ import ( slashingmodulev1 "cosmossdk.io/api/cosmos/slashing/module/v1" stakingmodulev1 "cosmossdk.io/api/cosmos/staking/module/v1" txconfigv1 "cosmossdk.io/api/cosmos/tx/config/v1" - upgrademodulev1 "cosmossdk.io/api/cosmos/upgrade/module/v1" "cosmossdk.io/core/appconfig" "cosmossdk.io/depinject" - upgradetypes "cosmossdk.io/x/upgrade/types" - "github.com/cosmos/cosmos-sdk/runtime" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -86,7 +83,6 @@ var ( govtypes.ModuleName, minttypes.ModuleName, genutiltypes.ModuleName, - upgradetypes.ModuleName, // Story modules epochstypes.ModuleName, evmenginetypes.ModuleName, @@ -94,11 +90,6 @@ var ( signaltypes.ModuleName, } - // NOTE: upgrade module must come first, as upgrades might break state schema. - preBlockers = []string{ - upgradetypes.ModuleName, - } - // During begin block slashing happens after distr.BeginBlocker so that // there is nothing left over in the validator fee pool, so as to keep the // CanWithdrawInvariant invariant. @@ -204,10 +195,6 @@ var ( Name: stakingtypes.ModuleName, Config: appconfig.WrapAny(&stakingmodulev1.Module{}), }, - { - Name: upgradetypes.ModuleName, - Config: appconfig.WrapAny(&upgrademodulev1.Module{}), - }, { Name: epochstypes.ModuleName, Config: appconfig.WrapAny(&epochsmodule.Module{}), diff --git a/client/app/encoding.go b/client/app/encoding.go new file mode 100644 index 00000000..caad5224 --- /dev/null +++ b/client/app/encoding.go @@ -0,0 +1,50 @@ +package app + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/std" + "github.com/cosmos/cosmos-sdk/x/auth/tx" +) + +type ModuleRegister interface { + RegisterLegacyAminoCodec(*codec.LegacyAmino) + RegisterInterfaces(codectypes.InterfaceRegistry) +} + +// Config specifies the concrete encoding types to use for a given app. +// This is provided for compatibility between protobuf and amino implementations. +type EncodingConfig struct { + InterfaceRegistry codectypes.InterfaceRegistry + Codec codec.Codec + TxConfig client.TxConfig + Amino *codec.LegacyAmino +} + +// MakeConfig returns an encoding config for the app. +func MakeEncodingConfig(moduleRegisters ...ModuleRegister) EncodingConfig { + interfaceRegistry := codectypes.NewInterfaceRegistry() + amino := codec.NewLegacyAmino() + + // Register the standard types from the Cosmos SDK on interfaceRegistry and + // amino. + std.RegisterInterfaces(interfaceRegistry) + std.RegisterLegacyAminoCodec(amino) + + // Register types from the moduleRegisters on interfaceRegistry and amino. + for _, moduleRegister := range moduleRegisters { + moduleRegister.RegisterInterfaces(interfaceRegistry) + moduleRegister.RegisterLegacyAminoCodec(amino) + } + + protoCodec := codec.NewProtoCodec(interfaceRegistry) + txConfig := tx.NewTxConfig(protoCodec, tx.DefaultSignModes) + + return EncodingConfig{ + InterfaceRegistry: interfaceRegistry, + Codec: protoCodec, + TxConfig: txConfig, + Amino: amino, + } +} diff --git a/client/app/module/configurator.go b/client/app/module/configurator.go new file mode 100644 index 00000000..3378b888 --- /dev/null +++ b/client/app/module/configurator.go @@ -0,0 +1,128 @@ +package module + +import ( + "fmt" + + pbgrpc "github.com/gogo/protobuf/grpc" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/module" +) + +// Configurator implements the module.Configurator interface. +var _ module.Configurator = Configurator{} + +// Configurator is a struct used at startup to register all the message and +// query servers for all modules. It allows the module to register any migrations from +// one consensus version of the module to the next. Finally it maps all the messages +// to the app versions that they are accepted in. This then gets used in the antehandler +// to prevent users from submitting messages that can not yet be executed. +type Configurator struct { + fromVersion, toVersion uint64 + cdc codec.Codec + msgServer pbgrpc.Server + queryServer pbgrpc.Server + // acceptedMessages is a map from appVersion -> msgTypeURL -> struct{}. + acceptedMessages map[uint64]map[string]struct{} + // migrations is a map of moduleName -> fromVersion -> migration script handler. + migrations map[string]map[uint64]module.MigrationHandler +} + +// NewConfigurator returns a new Configurator instance. +func NewConfigurator(cdc codec.Codec, msgServer, queryServer pbgrpc.Server) Configurator { + return Configurator{ + cdc: cdc, + msgServer: msgServer, + queryServer: queryServer, + migrations: map[string]map[uint64]module.MigrationHandler{}, + acceptedMessages: map[uint64]map[string]struct{}{}, + } +} + +func (c *Configurator) WithVersions(fromVersion, toVersion uint64) module.Configurator { + c.fromVersion = fromVersion + c.toVersion = toVersion + return c +} + +// MsgServer implements the Configurator.MsgServer method. +func (c Configurator) MsgServer() pbgrpc.Server { + return &serverWrapper{ + addMessages: c.addMessages, + msgServer: c.msgServer, + } +} + +// GetAcceptedMessages returns the accepted messages for all versions. +// acceptedMessages is a map from appVersion -> msgTypeURL -> struct{}. +func (c Configurator) GetAcceptedMessages() map[uint64]map[string]struct{} { + return c.acceptedMessages +} + +// QueryServer implements the Configurator.QueryServer method. +func (c Configurator) QueryServer() pbgrpc.Server { + return c.queryServer +} + +// RegisterMigration implements the Configurator.RegisterMigration method. +func (c Configurator) RegisterMigration(moduleName string, fromVersion uint64, handler module.MigrationHandler) error { + if fromVersion == 0 { + return sdkerrors.ErrInvalidVersion.Wrap("module migration versions should start at 1") + } + + if c.migrations[moduleName] == nil { + c.migrations[moduleName] = map[uint64]module.MigrationHandler{} + } + + if c.migrations[moduleName][fromVersion] != nil { + return sdkerrors.ErrLogic.Wrapf("another migration for module %s and version %d already exists", moduleName, fromVersion) + } + + c.migrations[moduleName][fromVersion] = handler + + return nil +} + +func (c Configurator) addMessages(msgs []string) { + for version := c.fromVersion; version <= c.toVersion; version++ { + if _, exists := c.acceptedMessages[version]; !exists { + c.acceptedMessages[version] = map[string]struct{}{} + } + for _, msg := range msgs { + c.acceptedMessages[version][msg] = struct{}{} + } + } +} + +// runModuleMigrations runs all in-place store migrations for one given module from a +// version to another version. +func (c Configurator) runModuleMigrations(ctx sdk.Context, moduleName string, fromVersion, toVersion uint64) error { + // No-op if toVersion is the initial version or if the version is unchanged. + if toVersion <= 1 || fromVersion == toVersion { + return nil + } + + moduleMigrationsMap, found := c.migrations[moduleName] + if !found { + return sdkerrors.ErrNotFound.Wrapf("no migrations found for module %s", moduleName) + } + + // Run in-place migrations for the module sequentially until toVersion. + for i := fromVersion; i < toVersion; i++ { + migrateFn, found := moduleMigrationsMap[i] + if !found { + // no migrations needed + continue + } + ctx.Logger().Info(fmt.Sprintf("migrating module %s from version %d to version %d", moduleName, i, i+1)) + + err := migrateFn(ctx) + if err != nil { + return err + } + } + + return nil +} diff --git a/client/app/module/module.go b/client/app/module/module.go new file mode 100644 index 00000000..81a23f46 --- /dev/null +++ b/client/app/module/module.go @@ -0,0 +1,1011 @@ +// Modifications made from https://github.com/cosmos/cosmos-sdk/blob/main/types/module/module.go +// to accommodate the versioned module mapping in the modified Manager. +package module + +import ( + "context" + "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/genesis" + errorsmod "cosmossdk.io/errors" + storetypes "cosmossdk.io/store/types" + "encoding/json" + "fmt" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec/types" + sdkmodule "github.com/cosmos/cosmos-sdk/types/module" + "github.com/grpc-ecosystem/grpc-gateway/runtime" + "github.com/piplabs/story/lib/errors" + "github.com/spf13/cobra" + "slices" + "sort" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" +) + +// AppModuleBasic is the standard form for basic non-dependant elements of an application module. +type AppModuleBasic interface { + HasName + HasConsensusVersion + + RegisterLegacyAminoCodec(*codec.LegacyAmino) + RegisterInterfaces(types.InterfaceRegistry) + RegisterGRPCGatewayRoutes(client.Context, *runtime.ServeMux) +} + +// HasName allows the module to provide its own name for legacy purposes. +// Newer apps should specify the name for their modules using a map +// using NewManagerFromMap. +type HasName interface { + Name() string +} + +// HasGenesisBasics is the legacy interface for stateless genesis methods. +type HasGenesisBasics interface { + DefaultGenesis(codec.JSONCodec) json.RawMessage + ValidateGenesis(codec.JSONCodec, client.TxEncodingConfig, json.RawMessage) error +} + +// BasicManager is a collection of AppModuleBasic +type BasicManager map[string]AppModuleBasic + +// NewBasicManager creates a new BasicManager object +func NewBasicManager(modules ...AppModuleBasic) BasicManager { + moduleMap := make(map[string]AppModuleBasic) + for _, module := range modules { + moduleMap[module.Name()] = module + } + return moduleMap +} + +// NewBasicManagerFromManager creates a new BasicManager from a Manager +// The BasicManager will contain all AppModuleBasic from the AppModule Manager +// Module's AppModuleBasic can be overridden by passing a custom AppModuleBasic map +func NewBasicManagerFromManager(manager *Manager, version uint64, customModuleBasics map[string]AppModuleBasic) BasicManager { + moduleMap := make(map[string]AppModuleBasic) + for name, module := range manager.versionedModules[version] { + if customBasicMod, ok := customModuleBasics[name]; ok { + moduleMap[name] = customBasicMod + continue + } + + if appModule, ok := module.(appmodule.AppModule); ok { + moduleMap[name] = sdkmodule.CoreAppModuleBasicAdaptor(name, appModule) + continue + } + + if basicMod, ok := module.(AppModuleBasic); ok { + moduleMap[name] = basicMod + } + } + + return moduleMap +} + +// RegisterLegacyAminoCodec registers all module codecs +func (bm BasicManager) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { + for _, b := range bm { + b.RegisterLegacyAminoCodec(cdc) + } +} + +// RegisterInterfaces registers all module interface types +func (bm BasicManager) RegisterInterfaces(registry types.InterfaceRegistry) { + for _, m := range bm { + m.RegisterInterfaces(registry) + } +} + +// DefaultGenesis provides default genesis information for all modules +func (bm BasicManager) DefaultGenesis(cdc codec.JSONCodec) map[string]json.RawMessage { + genesisData := make(map[string]json.RawMessage) + for _, b := range bm { + if mod, ok := b.(HasGenesisBasics); ok { + genesisData[b.Name()] = mod.DefaultGenesis(cdc) + } + } + + return genesisData +} + +// ValidateGenesis performs genesis state validation for all modules +func (bm BasicManager) ValidateGenesis(cdc codec.JSONCodec, txEncCfg client.TxEncodingConfig, genesisData map[string]json.RawMessage) error { + for _, b := range bm { + // first check if the module is an adapted Core API Module + if mod, ok := b.(HasGenesisBasics); ok { + if err := mod.ValidateGenesis(cdc, txEncCfg, genesisData[b.Name()]); err != nil { + return err + } + } + } + + return nil +} + +// RegisterGRPCGatewayRoutes registers all module rest routes +func (bm BasicManager) RegisterGRPCGatewayRoutes(clientCtx client.Context, rtr *runtime.ServeMux) { + for _, b := range bm { + b.RegisterGRPCGatewayRoutes(clientCtx, rtr) + } +} + +// AddTxCommands adds all tx commands to the rootTxCmd. +func (bm BasicManager) AddTxCommands(rootTxCmd *cobra.Command) { + for _, b := range bm { + if mod, ok := b.(interface { + GetTxCmd() *cobra.Command + }); ok { + if cmd := mod.GetTxCmd(); cmd != nil { + rootTxCmd.AddCommand(cmd) + } + } + } +} + +// AddQueryCommands adds all query commands to the rootQueryCmd. +func (bm BasicManager) AddQueryCommands(rootQueryCmd *cobra.Command) { + for _, b := range bm { + if mod, ok := b.(interface { + GetQueryCmd() *cobra.Command + }); ok { + if cmd := mod.GetQueryCmd(); cmd != nil { + rootQueryCmd.AddCommand(cmd) + } + } + } +} + +// HasGenesis is the extension interface for stateful genesis methods. +type HasGenesis interface { + HasGenesisBasics + InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) + ExportGenesis(sdk.Context, codec.JSONCodec) json.RawMessage +} + +// HasABCIGenesis is the extension interface for stateful genesis methods which returns validator updates. +type HasABCIGenesis interface { + HasGenesisBasics + InitGenesis(sdk.Context, codec.JSONCodec, json.RawMessage) []abci.ValidatorUpdate + ExportGenesis(sdk.Context, codec.JSONCodec) json.RawMessage +} + +// AppModule is the form for an application module. Most of +// its functionality has been moved to extension interfaces. +// Deprecated: use appmodule.AppModule with a combination of extension interfaes interfaces instead. +type AppModule interface { + appmodule.AppModule + + AppModuleBasic +} + +// HasInvariants is the interface for registering invariants. +type HasInvariants interface { + // RegisterInvariants registers module invariants. + RegisterInvariants(sdk.InvariantRegistry) +} + +// HasServices is the interface for modules to register services. +type HasServices interface { + // RegisterServices allows a module to register services. + RegisterServices(Configurator) +} + +// HasConsensusVersion is the interface for declaring a module consensus version. +type HasConsensusVersion interface { + // ConsensusVersion is a sequence number for state-breaking change of the + // module. It should be incremented on each consensus-breaking change + // introduced by the module. To avoid wrong/empty versions, the initial version + // should be set to 1. + ConsensusVersion() uint64 +} + +// HasABCIEndblock is a released typo of HasABCIEndBlock. +// Deprecated: use HasABCIEndBlock instead. +type HasABCIEndblock HasABCIEndBlock + +// HasABCIEndBlock is the interface for modules that need to run code at the end of the block. +type HasABCIEndBlock interface { + AppModule + EndBlock(context.Context) ([]abci.ValidatorUpdate, error) +} + +var ( + _ appmodule.AppModule = (*GenesisOnlyAppModule)(nil) + _ AppModuleBasic = (*GenesisOnlyAppModule)(nil) +) + +// AppModuleGenesis is the standard form for an application module genesis functions +type AppModuleGenesis interface { + AppModuleBasic + HasABCIGenesis +} + +// GenesisOnlyAppModule is an AppModule that only has import/export functionality +type GenesisOnlyAppModule struct { + AppModuleGenesis +} + +// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object +func NewGenesisOnlyAppModule(amg AppModuleGenesis) GenesisOnlyAppModule { + return GenesisOnlyAppModule{ + AppModuleGenesis: amg, + } +} + +// IsOnePerModuleType implements the depinject.OnePerModuleType interface. +func (GenesisOnlyAppModule) IsOnePerModuleType() {} + +// IsAppModule implements the appmodule.AppModule interface. +func (GenesisOnlyAppModule) IsAppModule() {} + +// RegisterInvariants is a placeholder function register no invariants +func (GenesisOnlyAppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} + +// ConsensusVersion implements AppModule/ConsensusVersion. +func (gam GenesisOnlyAppModule) ConsensusVersion() uint64 { return 1 } + +// Manager defines a module manager that provides the high level utility for +// managing and executing operations for a group of modules. This implementation +// was originally inspired by the module manager defined in Cosmos SDK but this +// implementation maps the state machine version to different versions of the +// module. It also provides a way to run migrations between different versions +// of a module. +type Manager struct { + // versionedModules is a map from app version -> module name -> module. + versionedModules map[uint64]map[string]AppModule + // uniqueModuleVersions is a mapping of module name -> module consensus + // version -> the range of app versions this particular module operates + // over. The first element in the array represent the fromVersion and the + // last the toVersion (this is inclusive). + uniqueModuleVersions map[string]map[uint64][2]uint64 + allModules []AppModule + // firstVersion is the lowest app version supported. + firstVersion uint64 + // lastVersion is the highest app version supported. + lastVersion uint64 + + OrderInitGenesis []string + OrderExportGenesis []string + OrderPreBlockers []string + OrderBeginBlockers []string + OrderEndBlockers []string + OrderPrepareCheckStaters []string + OrderPrecommiters []string + OrderMigrations []string +} + +// NewManager returns a new Manager object. +func NewManager(modules []VersionedModule) (*Manager, error) { + versionedModules := make(map[uint64]map[string]AppModule) + allModules := make([]AppModule, len(modules)) + modulesStr := make([]string, 0, len(modules)) + preBlockModulesStr := make([]string, 0) + uniqueModuleVersions := make(map[string]map[uint64][2]uint64) + for idx, module := range modules { + name := module.Name() + moduleVersion := module.ConsensusVersion() + + if _, ok := module.Module.(sdkmodule.AppModule); !ok { + panic(fmt.Sprintf("module %s does not implement sdkmodule.AppModule", name)) + } + + if module.FromVersion == 0 { + return nil, sdkerrors.ErrInvalidVersion.Wrapf("v0 is not a valid version for module %s", module.Module.Name()) + } + if module.FromVersion > module.ToVersion { + return nil, sdkerrors.ErrLogic.Wrapf("FromVersion cannot be greater than ToVersion for module %s", module.Module.Name()) + } + + for version := module.FromVersion; version <= module.ToVersion; version++ { + if versionedModules[version] == nil { + versionedModules[version] = make(map[string]AppModule) + } + if _, exists := versionedModules[version][name]; exists { + return nil, sdkerrors.ErrLogic.Wrapf("Two different modules with domain %s are registered with the same version %d", name, version) + } + versionedModules[version][name] = module.Module + } + + allModules[idx] = module.Module + modulesStr = append(modulesStr, name) + + if _, ok := module.Module.(appmodule.HasPreBlocker); ok { + preBlockModulesStr = append(preBlockModulesStr, name) + } + + if _, exists := uniqueModuleVersions[name]; !exists { + uniqueModuleVersions[name] = make(map[uint64][2]uint64) + } + uniqueModuleVersions[name][moduleVersion] = [2]uint64{module.FromVersion, module.ToVersion} + } + firstVersion := slices.Min(getKeys(versionedModules)) + lastVersion := slices.Max(getKeys(versionedModules)) + + m := &Manager{ + versionedModules: versionedModules, + uniqueModuleVersions: uniqueModuleVersions, + allModules: allModules, + firstVersion: firstVersion, + lastVersion: lastVersion, + OrderInitGenesis: modulesStr, + OrderExportGenesis: modulesStr, + OrderBeginBlockers: modulesStr, + OrderEndBlockers: modulesStr, + } + if err := m.checkUpgradeSchedule(); err != nil { + return nil, err + } + return m, nil +} + +// NewManagerFromMap creates a new Manager object from a map of module names to module implementations. +// This method should be used for apps and modules which have migrated to the cosmossdk.io/core.appmodule.AppModule API. +func NewManagerFromMap(moduleMap map[string]appmodule.AppModule) *Manager { + simpleModuleMap := make(map[string]interface{}) + modulesStr := make([]string, 0, len(simpleModuleMap)) + preBlockModulesStr := make([]string, 0) + for name, module := range moduleMap { + simpleModuleMap[name] = module + modulesStr = append(modulesStr, name) + if _, ok := module.(appmodule.HasPreBlocker); ok { + preBlockModulesStr = append(preBlockModulesStr, name) + } + } + + // Sort the modules by name. Given that we are using a map above we can't guarantee the order. + sort.Strings(modulesStr) + + return &Manager{ + Modules: simpleModuleMap, + OrderInitGenesis: modulesStr, + OrderExportGenesis: modulesStr, + OrderPreBlockers: preBlockModulesStr, + OrderBeginBlockers: modulesStr, + OrderEndBlockers: modulesStr, + OrderPrecommiters: modulesStr, + OrderPrepareCheckStaters: modulesStr, + } +} + +// SetOrderInitGenesis sets the order of init genesis calls +func (m *Manager) SetOrderInitGenesis(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderInitGenesis", moduleNames, func(moduleName string) bool { + module, found := m.FindModule(moduleName) + if !found { + return false + } + + if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis { + return !hasGenesis + } + + if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis { + return !hasABCIGenesis + } + + _, hasGenesis := module.(HasGenesis) + return !hasGenesis + }) + m.OrderInitGenesis = moduleNames +} + +// SetOrderExportGenesis sets the order of export genesis calls +func (m *Manager) SetOrderExportGenesis(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderExportGenesis", moduleNames, func(moduleName string) bool { + module, found := m.FindModule(moduleName) + if !found { + return false + } + + if _, hasGenesis := module.(appmodule.HasGenesis); hasGenesis { + return !hasGenesis + } + + if _, hasABCIGenesis := module.(HasABCIGenesis); hasABCIGenesis { + return !hasABCIGenesis + } + + _, hasGenesis := module.(HasGenesis) + return !hasGenesis + }) + m.OrderExportGenesis = moduleNames +} + +// SetOrderPreBlockers sets the order of set pre-blocker calls +func (m *Manager) SetOrderPreBlockers(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderPreBlockers", moduleNames, + func(moduleName string) bool { + module, found := m.FindModule(moduleName) + if !found { + return false + } + + _, hasBlock := module.(appmodule.HasPreBlocker) + return !hasBlock + }) + m.OrderPreBlockers = moduleNames +} + +// SetOrderBeginBlockers sets the order of set begin-blocker calls +func (m *Manager) SetOrderBeginBlockers(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderBeginBlockers", moduleNames, + func(moduleName string) bool { + module, found := m.FindModule(moduleName) + if !found { + return false + } + + _, hasBeginBlock := module.(appmodule.HasBeginBlocker) + return !hasBeginBlock + }) + m.OrderBeginBlockers = moduleNames +} + +// SetOrderEndBlockers sets the order of set end-blocker calls +func (m *Manager) SetOrderEndBlockers(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderEndBlockers", moduleNames, + func(moduleName string) bool { + module, found := m.FindModule(moduleName) + if !found { + return false + } + + if _, hasEndBlock := module.(appmodule.HasEndBlocker); hasEndBlock { + return !hasEndBlock + } + + _, hasABCIEndBlock := module.(HasABCIEndBlock) + return !hasABCIEndBlock + }) + m.OrderEndBlockers = moduleNames +} + +// SetOrderPrepareCheckStaters sets the order of set prepare-check-stater calls +func (m *Manager) SetOrderPrepareCheckStaters(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderPrepareCheckStaters", moduleNames, + func(moduleName string) bool { + module, found := m.FindModule(moduleName) + if !found { + return false + } + + _, hasPrepareCheckState := module.(appmodule.HasPrepareCheckState) + return !hasPrepareCheckState + }) + m.OrderPrepareCheckStaters = moduleNames +} + +// SetOrderPrecommiters sets the order of set precommiter calls +func (m *Manager) SetOrderPrecommiters(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderPrecommiters", moduleNames, + func(moduleName string) bool { + module, found := m.FindModule(moduleName) + if !found { + return false + } + + _, hasPrecommit := module.(appmodule.HasPrecommit) + return !hasPrecommit + }) + m.OrderPrecommiters = moduleNames +} + +// SetOrderMigrations sets the order of migrations to be run. If not set +// then migrations will be run with an order defined in `DefaultMigrationsOrder`. +func (m *Manager) SetOrderMigrations(moduleNames ...string) { + m.assertNoForgottenModules("SetOrderMigrations", moduleNames, nil) + m.OrderMigrations = moduleNames +} + +// RegisterInvariants registers all module invariants +func (m *Manager) RegisterInvariants(ir sdk.InvariantRegistry) { + for _, module := range m.allModules { + if module, ok := module.(HasInvariants); ok { + module.RegisterInvariants(ir) + } + } +} + +// RegisterServices registers all module services +func (m *Manager) RegisterServices(cfg Configurator) error { + for _, module := range m.allModules { + if module, ok := module.(HasServices); ok { + module.RegisterServices(cfg) + } + + fromVersion, toVersion := m.getAppVersionsForModule(module.Name(), module.ConsensusVersion()) + + if module, ok := module.(appmodule.HasServices); ok { + err := module.RegisterServices(cfg.WithVersions(fromVersion, toVersion)) + if err != nil { + return err + } + } + + if cfg.Error() != nil { + return cfg.Error() + } + } + + return nil +} + +func (m *Manager) getAppVersionsForModule(moduleName string, moduleVersion uint64) (uint64, uint64) { + return m.uniqueModuleVersions[moduleName][moduleVersion][0], m.uniqueModuleVersions[moduleName][moduleVersion][1] +} + +// InitGenesis performs init genesis functionality for modules. Exactly one +// module must return a non-empty validator set update to correctly initialize +// the chain. +func (m *Manager) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, genesisData map[string]json.RawMessage) (*abci.ResponseInitChain, error) { + var validatorUpdates []abci.ValidatorUpdate + ctx.Logger().Info("initializing blockchain state from genesis.json") + + appVersion := ctx.BlockHeader().Version.App + modules, versionSupported := m.versionedModules[appVersion] + if !versionSupported { + panic(fmt.Sprintf("version %d not supported", appVersion)) + } + + for _, moduleName := range m.OrderInitGenesis { + if genesisData[moduleName] == nil { + continue + } + + mod := modules[moduleName] + // we might get an adapted module, a native core API module or a legacy module + if module, ok := mod.(appmodule.HasGenesis); ok { + ctx.Logger().Debug("running initialization for module", "module", moduleName) + // core API genesis + source, err := genesis.SourceFromRawJSON(genesisData[moduleName]) + if err != nil { + return &abci.ResponseInitChain{}, err + } + + err = module.InitGenesis(ctx, source) + if err != nil { + return &abci.ResponseInitChain{}, err + } + } else if module, ok := mod.(HasGenesis); ok { + ctx.Logger().Debug("running initialization for module", "module", moduleName) + module.InitGenesis(ctx, cdc, genesisData[moduleName]) + } else if module, ok := mod.(HasABCIGenesis); ok { + ctx.Logger().Debug("running initialization for module", "module", moduleName) + moduleValUpdates := module.InitGenesis(ctx, cdc, genesisData[moduleName]) + + // use these validator updates if provided, the module manager assumes + // only one module will update the validator set + if len(moduleValUpdates) > 0 { + if len(validatorUpdates) > 0 { + return &abci.ResponseInitChain{}, errors.New("validator InitGenesis updates already set by a previous module") + } + validatorUpdates = moduleValUpdates + } + } + } + + // a chain must initialize with a non-empty validator set + if len(validatorUpdates) == 0 { + return &abci.ResponseInitChain{}, fmt.Errorf("validator set is empty after InitGenesis, please ensure at least one validator is initialized with a delegation greater than or equal to the DefaultPowerReduction (%d)", sdk.DefaultPowerReduction) + } + + return &abci.ResponseInitChain{ + Validators: validatorUpdates, + }, nil +} + +// ExportGenesis performs export genesis functionality for the modules supported +// in a particular version. +func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec, version uint64) map[string]json.RawMessage { + genesisData := make(map[string]json.RawMessage) + modules := m.versionedModules[version] + moduleNamesForVersion := m.ModuleNames(version) + moduleNamesToExport := filter(m.OrderExportGenesis, func(moduleName string) bool { + // filter out modules that are not supported by this version + return slices.Contains(moduleNamesForVersion, moduleName) + }) + for _, moduleName := range moduleNamesToExport { + if module, ok := modules[moduleName].(HasGenesis); ok { + genesisData[moduleName] = module.ExportGenesis(ctx, cdc) + } + } + + return genesisData +} + +// ExportGenesisForModules performs export genesis functionality for modules +func (m *Manager) ExportGenesisForModules(ctx sdk.Context, cdc codec.JSONCodec, modulesToExport []string) (map[string]json.RawMessage, error) { + modules := m.versionedModules[m.lastVersion] + + if len(modulesToExport) == 0 { + modulesToExport = m.OrderExportGenesis + } + // verify modules exists in app, so that we don't panic in the middle of an export + if err := m.checkModulesExists(modulesToExport); err != nil { + return nil, err + } + + type genesisResult struct { + bz json.RawMessage + err error + } + + channels := make(map[string]chan genesisResult) + for _, moduleName := range modulesToExport { + mod := modules[moduleName] + if module, ok := mod.(appmodule.HasGenesis); ok { + // core API genesis + channels[moduleName] = make(chan genesisResult) + go func(module appmodule.HasGenesis, ch chan genesisResult) { + ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions + target := genesis.RawJSONTarget{} + err := module.ExportGenesis(ctx, target.Target()) + if err != nil { + ch <- genesisResult{nil, err} + return + } + + rawJSON, err := target.JSON() + if err != nil { + ch <- genesisResult{nil, err} + return + } + + ch <- genesisResult{rawJSON, nil} + }(module, channels[moduleName]) + } else if module, ok := mod.(HasGenesis); ok { + channels[moduleName] = make(chan genesisResult) + go func(module HasGenesis, ch chan genesisResult) { + ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions + ch <- genesisResult{module.ExportGenesis(ctx, cdc), nil} + }(module, channels[moduleName]) + } else if module, ok := mod.(HasABCIGenesis); ok { + channels[moduleName] = make(chan genesisResult) + go func(module HasABCIGenesis, ch chan genesisResult) { + ctx := ctx.WithGasMeter(storetypes.NewInfiniteGasMeter()) // avoid race conditions + ch <- genesisResult{module.ExportGenesis(ctx, cdc), nil} + }(module, channels[moduleName]) + } + } + + genesisData := make(map[string]json.RawMessage) + for moduleName := range channels { + res := <-channels[moduleName] + if res.err != nil { + return nil, fmt.Errorf("genesis export error in %s: %w", moduleName, res.err) + } + + genesisData[moduleName] = res.bz + } + + return genesisData, nil +} + +// checkModulesExists verifies that all modules in the list exist in the app +func (m *Manager) checkModulesExists(moduleName []string) error { + modules := m.versionedModules[m.lastVersion] + for _, name := range moduleName { + if _, ok := modules[name]; !ok { + return fmt.Errorf("module %s does not exist", name) + } + } + + return nil +} + +// assertNoForgottenModules checks that we didn't forget any modules in the SetOrder* functions. +// `pass` is a closure which allows one to omit modules from `moduleNames`. +// If you provide non-nil `pass` and it returns true, the module would not be subject of the assertion. +func (m *Manager) assertNoForgottenModules(setOrderFnName string, moduleNames []string, pass func(moduleName string) bool) { + ms := make(map[string]bool) + for _, m := range moduleNames { + ms[m] = true + } + var missing []string + for m := range m.uniqueModuleVersions { + m := m + if pass != nil && pass(m) { + continue + } + + if !ms[m] { + missing = append(missing, m) + } + } + if len(missing) != 0 { + sort.Strings(missing) + panic(fmt.Sprintf( + "all modules must be defined when setting %s, missing: %v", setOrderFnName, missing)) + } +} + +// MigrationHandler is the migration function that each module registers. +type MigrationHandler func(sdk.Context) error + +// VersionMap is a map of moduleName -> version +type VersionMap map[string]uint64 + +// RunMigrations performs in-place store migrations for all modules. This +// function MUST be called when the state machine changes appVersion +func (m Manager) RunMigrations(ctx sdk.Context, cfg sdkmodule.Configurator, fromVersion, toVersion uint64) error { + c, ok := cfg.(Configurator) + if !ok { + return sdkerrors.ErrInvalidType.Wrapf("expected %T, got %T", Configurator{}, cfg) + } + modules := m.OrderMigrations + if modules == nil { + modules = defaultMigrationsOrder(m.ModuleNames(toVersion)) + } + currentVersionModules, exists := m.versionedModules[fromVersion] + if !exists { + return sdkerrors.ErrInvalidVersion.Wrapf("fromVersion %d not supported", fromVersion) + } + nextVersionModules, exists := m.versionedModules[toVersion] + if !exists { + return sdkerrors.ErrInvalidVersion.Wrapf("toVersion %d not supported", toVersion) + } + + for _, moduleName := range modules { + currentModule, currentModuleExists := currentVersionModules[moduleName] + nextModule, nextModuleExists := nextVersionModules[moduleName] + + // if the module exists for both upgrades + if currentModuleExists && nextModuleExists { + // by using consensus version instead of app version we support the SDK's legacy method + // of migrating modules which were made of several versions and consisted of a mapping of + // app version to module version. Now, using go.mod, each module will have only a single + // consensus version and each breaking upgrade will result in a new module and a new consensus + // version. + fromModuleVersion := currentModule.ConsensusVersion() + toModuleVersion := nextModule.ConsensusVersion() + err := c.runModuleMigrations(ctx, moduleName, fromModuleVersion, toModuleVersion) + if err != nil { + return err + } + } else if !currentModuleExists && nextModuleExists { + ctx.Logger().Info(fmt.Sprintf("adding a new module: %s", moduleName)) + + if module, ok := nextModule.(HasGenesis); ok { + module.InitGenesis(ctx, c.cdc, module.DefaultGenesis(c.cdc)) + } + + if module, ok := nextModule.(HasABCIGenesis); ok { + moduleValUpdates := module.InitGenesis(ctx, c.cdc, module.DefaultGenesis(c.cdc)) + // The module manager assumes only one module will update the + // validator set, and it can't be a new module. + if len(moduleValUpdates) > 0 { + return errorsmod.Wrapf(sdkerrors.ErrLogic, "validator InitGenesis update is already set by another module") + } + } + } + // TODO: handle the case where a module is no longer supported (i.e. removed from the state machine) + } + + return nil +} + +// PreBlock performs begin block functionality for upgrade module. +// It takes the current context as a parameter and returns a boolean value +// indicating whether the migration was successfully executed or not. +func (m *Manager) PreBlock(ctx sdk.Context) (*sdk.ResponsePreBlock, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + modules := m.MustGetCurrentVersionModules(ctx) + paramsChanged := false + for _, moduleName := range m.OrderPreBlockers { + if module, ok := modules[moduleName].(appmodule.HasPreBlocker); ok { + rsp, err := module.PreBlock(ctx) + if err != nil { + return nil, err + } + if rsp.IsConsensusParamsChanged() { + paramsChanged = true + } + } + } + return &sdk.ResponsePreBlock{ + ConsensusParamsChanged: paramsChanged, + }, nil +} + +// BeginBlock performs begin block functionality for all modules. It creates a +// child context with an event manager to aggregate events emitted from all +// modules. +func (m *Manager) BeginBlock(ctx sdk.Context) (sdk.BeginBlock, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + modules := m.MustGetCurrentVersionModules(ctx) + for _, moduleName := range m.OrderBeginBlockers { + if module, ok := modules[moduleName].(appmodule.HasBeginBlocker); ok { + if err := module.BeginBlock(ctx); err != nil { + return sdk.BeginBlock{}, err + } + } + } + + return sdk.BeginBlock{ + Events: ctx.EventManager().ABCIEvents(), + }, nil +} + +// EndBlock performs end block functionality for all modules. It creates a +// child context with an event manager to aggregate events emitted from all +// modules. +func (m *Manager) EndBlock(ctx sdk.Context) (sdk.EndBlock, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + validatorUpdates := []abci.ValidatorUpdate{} + + modules := m.MustGetCurrentVersionModules(ctx) + for _, moduleName := range m.OrderEndBlockers { + if module, ok := modules[moduleName].(appmodule.HasEndBlocker); ok { + err := module.EndBlock(ctx) + if err != nil { + return sdk.EndBlock{}, err + } + } else if module, ok := modules[moduleName].(HasABCIEndBlock); ok { + moduleValUpdates, err := module.EndBlock(ctx) + if err != nil { + return sdk.EndBlock{}, err + } + // use these validator updates if provided, the module manager assumes + // only one module will update the validator set + if len(moduleValUpdates) > 0 { + if len(validatorUpdates) > 0 { + return sdk.EndBlock{}, errors.New("validator EndBlock updates already set by a previous module") + } + + for _, updates := range moduleValUpdates { + validatorUpdates = append(validatorUpdates, abci.ValidatorUpdate{PubKey: updates.PubKey, Power: updates.Power}) + } + } + } else { + continue + } + } + + return sdk.EndBlock{ + ValidatorUpdates: validatorUpdates, + Events: ctx.EventManager().ABCIEvents(), + }, nil +} + +// Precommit performs precommit functionality for all modules. +func (m *Manager) Precommit(ctx sdk.Context) error { + modules := m.MustGetCurrentVersionModules(ctx) + for _, moduleName := range m.OrderPrecommiters { + module, ok := modules[moduleName].(appmodule.HasPrecommit) + if !ok { + continue + } + if err := module.Precommit(ctx); err != nil { + return err + } + } + return nil +} + +// PrepareCheckState performs functionality for preparing the check state for all modules. +func (m *Manager) PrepareCheckState(ctx sdk.Context) error { + modules := m.MustGetCurrentVersionModules(ctx) + for _, moduleName := range m.OrderPrepareCheckStaters { + module, ok := modules[moduleName].(appmodule.HasPrepareCheckState) + if !ok { + continue + } + if err := module.PrepareCheckState(ctx); err != nil { + return err + } + } + return nil +} + +// GetVersionMap gets consensus version from all modules +func (m *Manager) GetVersionMap(version uint64) sdkmodule.VersionMap { + vermap := make(sdkmodule.VersionMap) + if version > m.lastVersion || version < m.firstVersion { + return vermap + } + + for _, v := range m.versionedModules[version] { + version := v.ConsensusVersion() + name := v.Name() + vermap[name] = version + } + + return vermap +} + +// ModuleNames returns the list of module names that are supported for a +// particular version in no particular order. +func (m *Manager) ModuleNames(version uint64) []string { + modules, ok := m.versionedModules[version] + if !ok { + return []string{} + } + + names := make([]string, 0, len(modules)) + for name := range modules { + names = append(names, name) + } + return names +} + +// DefaultMigrationsOrder returns a default migrations order: ascending alphabetical by module name, +// except x/auth which will run last, see: +// https://github.com/cosmos/cosmos-sdk/issues/10591 +func DefaultMigrationsOrder(modules []string) []string { + const authName = "auth" + out := make([]string, 0, len(modules)) + hasAuth := false + for _, m := range modules { + if m == authName { + hasAuth = true + } else { + out = append(out, m) + } + } + sort.Strings(out) + if hasAuth { + out = append(out, authName) + } + return out +} + +// SupportedVersions returns all the supported versions for the module manager +func (m *Manager) SupportedVersions() []uint64 { + return getKeys(m.versionedModules) +} + +// checkUpgradeSchedule performs a dry run of all the upgrades in all versions and asserts that the consensus version +// for a module domain i.e. auth, always increments for each module that uses the auth domain name +func (m *Manager) checkUpgradeSchedule() error { + if m.firstVersion == m.lastVersion { + // there are no upgrades to check + return nil + } + for _, moduleName := range m.OrderInitGenesis { + lastConsensusVersion := uint64(0) + for appVersion := m.firstVersion; appVersion <= m.lastVersion; appVersion++ { + module, exists := m.versionedModules[appVersion][moduleName] + if !exists { + continue + } + moduleVersion := module.ConsensusVersion() + if moduleVersion < lastConsensusVersion { + return fmt.Errorf("error: module %s in appVersion %d goes from moduleVersion %d to %d", moduleName, appVersion, lastConsensusVersion, moduleVersion) + } + lastConsensusVersion = moduleVersion + } + } + return nil +} + +// assertMatchingModules performs a sanity check that the basic module manager +// contains all the same modules present in the module manager +func (m *Manager) AssertMatchingModules(basicModuleManager sdkmodule.BasicManager) error { + for _, module := range m.allModules { + if _, exists := basicModuleManager[module.Name()]; !exists { + return fmt.Errorf("module %s not found in basic module manager", module.Name()) + } + } + return nil +} + +func (m *Manager) MustGetCurrentVersionModules(ctx sdk.Context) map[string]AppModule { + modules := m.versionedModules[ctx.BlockHeader().Version.App] + if modules == nil { + panic(fmt.Sprintf("no modules for version %d", ctx.BlockHeader().Version.App)) + } + + return modules +} + +func (m *Manager) FindModule(moduleName string) (AppModule, bool) { + for _, module := range m.allModules { + if module.Name() == moduleName { + return module, true + } + } + + return nil, false +} diff --git a/client/app/module/types.go b/client/app/module/types.go new file mode 100644 index 00000000..2790e778 --- /dev/null +++ b/client/app/module/types.go @@ -0,0 +1,12 @@ +package module + +type VersionedModule struct { + AppModuleBasic + + Module AppModule + // FromVersion and ToVersion indicate the continuous range of app versions + // that this particular module is part of. The range is inclusive. + // FromVersion should not be smaller than ToVersion. 0 is not a valid app + // version. + FromVersion, ToVersion uint64 +} diff --git a/client/app/module/utils.go b/client/app/module/utils.go new file mode 100644 index 00000000..113b017d --- /dev/null +++ b/client/app/module/utils.go @@ -0,0 +1,43 @@ +package module + +import ( + "slices" + "sort" + + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// defaultMigrationsOrder returns a default migrations order. The order is +// ascending alphabetical by module name except "auth" will be last. See: +// https://github.com/cosmos/cosmos-sdk/issues/10591 +func defaultMigrationsOrder(modules []string) []string { + result := filter(modules, isNotAuth) + sort.Strings(result) + + if hasAuth := slices.Contains(modules, authtypes.ModuleName); hasAuth { + return append(result, authtypes.ModuleName) + } + return result +} + +func filter(elements []string, filter func(string) bool) (filtered []string) { + for _, element := range elements { + if filter(element) { + filtered = append(filtered, element) + } + } + return filtered +} + +func isNotAuth(name string) bool { + return name != authtypes.ModuleName +} + +func getKeys(m map[uint64]map[string]AppModule) []uint64 { + keys := make([]uint64, 0, len(m)) + for key := range m { + keys = append(keys, key) + } + slices.Sort(keys) + return keys +} diff --git a/client/app/modules.go b/client/app/modules.go new file mode 100644 index 00000000..05437f06 --- /dev/null +++ b/client/app/modules.go @@ -0,0 +1,192 @@ +package app + +import ( + "fmt" + sdkmodule "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/auth/vesting" + "github.com/cosmos/cosmos-sdk/x/bank" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/distribution" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/gov" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/mint" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/cosmos/cosmos-sdk/x/params" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/cosmos/cosmos-sdk/x/slashing" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + "github.com/cosmos/cosmos-sdk/x/staking" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/piplabs/story/client/app/module" + epochsmodule "github.com/piplabs/story/client/x/epochs/module" + epochstypes "github.com/piplabs/story/client/x/epochs/types" + evmenginemodule "github.com/piplabs/story/client/x/evmengine/module" + evmenginetypes "github.com/piplabs/story/client/x/evmengine/types" + evmstakingmodule "github.com/piplabs/story/client/x/evmstaking/module" + evmstakingtypes "github.com/piplabs/story/client/x/evmstaking/types" + signalmodule "github.com/piplabs/story/client/x/signal/module" + signaltypes "github.com/piplabs/story/client/x/signal/types" +) + +var ( + // ModuleBasics defines the module BasicManager is in charge of setting up basic, + // non-dependant module elements, such as codec registration and genesis verification. + ModuleBasics = sdkmodule.NewBasicManager( + auth.AppModuleBasic{}, + genutil.AppModuleBasic{}, + bank.AppModuleBasic{}, + staking.AppModuleBasic{}, + mint.AppModuleBasic{}, + distribution.AppModuleBasic{}, + gov.AppModuleBasic{}, + params.AppModuleBasic{}, + slashing.AppModule{}, + vesting.AppModuleBasic{}, + // Story modules + epochsmodule.AppModuleBasic{}, + evmenginemodule.AppModuleBasic{}, + evmstakingmodule.AppModuleBasic{}, + signalmodule.AppModuleBasic{}, + ) + + // ModuleEncodingRegisters keeps track of all the module methods needed to + // register interfaces and specific type to encoding config + ModuleEncodingRegisters = extractRegisters(ModuleBasics) +) + +func (a *App) setupModuleManager() error { + var err error + a.ModuleManager, err = module.NewManager([]module.VersionedModule{ + { + Module: genutil.NewAppModule(a.Keepers.AccountKeeper, a.Keepers.StakingKeeper, a.BaseApp.DeliverTx, a.txConfig), + FromVersion: v1, ToVersion: v1, + }, + { + Module: auth.NewAppModule(a.appCodec, a.Keepers.AccountKeeper, nil, nil), + FromVersion: v1, ToVersion: v1, + }, + { + Module: vesting.NewAppModule(a.Keepers.AccountKeeper, a.Keepers.BankKeeper), + FromVersion: v1, ToVersion: v1, + }, + { + Module: bank.NewAppModule(a.appCodec, a.Keepers.BankKeeper, a.Keepers.AccountKeeper), + FromVersion: v1, ToVersion: v1, + }, + { + Module: gov.NewAppModule(a.appCodec, a.Keepers.GovKeeper, a.Keepers.AccountKeeper, a.Keepers.BankKeeper), + FromVersion: v1, ToVersion: v1, + }, + { + Module: mint.NewAppModule(a.appCodec, a.Keepers.MintKeeper, a.Keepers.AccountKeeper), + FromVersion: v1, ToVersion: v1, + }, + { + Module: slashing.NewAppModule(a.appCodec, a.Keepers.SlashingKeeper, a.Keepers.AccountKeeper, a.Keepers.BankKeeper, a.Keepers.StakingKeeper), + FromVersion: v1, ToVersion: v1, + }, + { + Module: distribution.NewAppModule(a.appCodec, a.Keepers.DistrKeeper, a.Keepers.AccountKeeper, a.Keepers.BankKeeper, a.Keepers.StakingKeeper), + FromVersion: v1, ToVersion: v1, + }, + { + Module: staking.NewAppModule(a.appCodec, a.Keepers.StakingKeeper, a.Keepers.AccountKeeper, a.Keepers.BankKeeper), + FromVersion: v1, ToVersion: v1, + }, + { + Module: signalmodule.NewAppModule(a.Keepers.SignalKeeper), + FromVersion: v1, ToVersion: v1, + }, + }) + if err != nil { + return err + } + return a.ModuleManager.AssertMatchingModules(ModuleBasics) +} + +func (a *App) setModuleOrder() { + // Set "OrderEndBlockers" directly instead of using "SetOrderEndBlockers," which will panic since the staking module + // is missing in the "endBlockers", which is an intended behavior in Story. The panic message is: + // `panic: all modules must be defined when setting SetOrderEndBlockers, missing: [staking]` + a.ModuleManager.OrderEndBlockers = endBlockers + a.SetEndBlocker(a.EndBlocker) +} + +func allStoreKeys() []string { + return []string{ + authtypes.StoreKey, + banktypes.StoreKey, + distrtypes.StoreKey, + govtypes.StoreKey, + minttypes.StoreKey, + paramstypes.StoreKey, + slashingtypes.StoreKey, + stakingtypes.StoreKey, + // Story modules + epochstypes.StoreKey, + evmenginetypes.StoreKey, + evmstakingtypes.StoreKey, + signaltypes.StoreKey, + } +} + +// versionedStoreKeys returns the store keys for each app version. +func versionedStoreKeys() map[uint64][]string { + return map[uint64][]string{ + 1: { + authtypes.StoreKey, + banktypes.StoreKey, + distrtypes.StoreKey, + govtypes.StoreKey, + minttypes.StoreKey, + paramstypes.StoreKey, + slashingtypes.StoreKey, + stakingtypes.StoreKey, + // Story modules + epochstypes.StoreKey, + evmenginetypes.StoreKey, + evmstakingtypes.StoreKey, + signaltypes.StoreKey, + }, + } +} + +// assertAllKeysArePresent performs a couple sanity checks on startup to ensure each versions key names have +// a key and that all versions supported by the module manager have a respective versioned key +func (a *App) assertAllKeysArePresent() { + supportedAppVersions := a.SupportedVersions() + supportedVersionsMap := make(map[uint64]bool, len(supportedAppVersions)) + for _, version := range supportedAppVersions { + supportedVersionsMap[version] = false + } + + for appVersion, keys := range a.keyVersions { + if _, exists := supportedVersionsMap[appVersion]; exists { + supportedVersionsMap[appVersion] = true + } else { + panic(fmt.Sprintf("keys %v for app version %d are not supported by the module manager", keys, appVersion)) + } + for _, key := range keys { + if _, ok := a.keys[key]; !ok { + panic(fmt.Sprintf("key %s is not present", key)) + } + } + } + for appVersion, supported := range supportedVersionsMap { + if !supported { + panic(fmt.Sprintf("app version %d is supported by the module manager but has no keys", appVersion)) + } + } +} + +// extractRegisters returns the encoding module registers from the basic manager. +func extractRegisters(manager sdkmodule.BasicManager) (modules []ModuleRegister) { + for _, m := range manager { + modules = append(modules, m) + } + return modules +} diff --git a/client/app/start.go b/client/app/start.go index ed9c8f36..7b7a1ad6 100644 --- a/client/app/start.go +++ b/client/app/start.go @@ -116,6 +116,7 @@ func Start(ctx context.Context, cfg Config) (func(context.Context) error, error) newSDKLogger(ctx), db, engineCl, + nil, // traceStore baseAppOpts..., ) if err != nil { diff --git a/client/app/upgrades.go b/client/app/upgrades.go deleted file mode 100644 index 9a4c089d..00000000 --- a/client/app/upgrades.go +++ /dev/null @@ -1,82 +0,0 @@ -package app - -import ( - "fmt" - - upgradetypes "cosmossdk.io/x/upgrade/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - - "github.com/piplabs/story/client/app/upgrades" - "github.com/piplabs/story/client/app/upgrades/v0_10_0" -) - -var ( - // `Upgrades` defines the upgrade handlers and store loaders for the application. - // New upgrades should be added to this slice after they are implemented. - Upgrades = []upgrades.Upgrade{ - v0_10_0.Upgrade, - } - // Forks are for hard forks that breaks backward compatibility. - Forks = []upgrades.Fork{} -) - -func (a *App) setupUpgradeHandlers() { - for _, upgrade := range Upgrades { - a.Keepers.UpgradeKeeper.SetUpgradeHandler( - upgrade.UpgradeName, - upgrade.CreateUpgradeHandler(a.ModuleManager, a.Configurator(), &a.Keepers), - ) - } -} - -// setUpgradeStoreLoaders sets custom store loaders to customize the rootMultiStore initialization for software upgrades. -func (a *App) setupUpgradeStoreLoaders() { - upgradeInfo, err := a.Keepers.UpgradeKeeper.ReadUpgradeInfoFromDisk() - if err != nil { - panic(fmt.Sprintf("failed to read upgrade info from disk %s", err)) - } - - if a.Keepers.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { - return - } - - for _, upgrade := range Upgrades { - if upgradeInfo.Name == upgrade.UpgradeName { - a.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &upgrade.StoreUpgrades)) - } - } -} - -// ScheduleForkUpgrade executes any necessary fork logic for based upon the current block height. It sets an upgrade -// plan once the chain reaches the pre-defined upgrade height. -// -// CONTRACT: for this logic to work properly it is required to: -// 1. Release a non-breaking patch version so that the chain can set the scheduled upgrade plan at upgrade-height. -// 2. Release the software defined in the upgrade-info. -func (a *App) scheduleForkUpgrade(ctx sdk.Context) { - currentBlockHeight := ctx.BlockHeight() - for _, fork := range Forks { - if currentBlockHeight == fork.UpgradeHeight { - upgradePlan := upgradetypes.Plan{ - Height: currentBlockHeight, - Name: fork.UpgradeName, - Info: fork.UpgradeInfo, - } - - // schedule the upgrade plan to the current block height, effectively performing - // a hard fork that uses the upgrade handler to manage the migration. - if err := a.Keepers.UpgradeKeeper.ScheduleUpgrade(ctx, upgradePlan); err != nil { - panic( - //nolint:errorlint // use "%v" to obfuscate the underlying error - fmt.Errorf( - "hard fork: failed to schedule upgrade %s during BeginBlock at height %d: %v", - upgradePlan.Name, - ctx.BlockHeight(), - err, - ), - ) - } - } - } -} diff --git a/client/app/upgrades/historical.go b/client/app/upgrades/historical.go deleted file mode 100644 index 923692d9..00000000 --- a/client/app/upgrades/historical.go +++ /dev/null @@ -1,92 +0,0 @@ -package upgrades - -// This file is intended to keep old, historical upgrades in one place. It is advised to keep the future upgrades in the -// separate file, and then move them to `historical.go` after a successful upgrade so the new nodes can still sync from -// the genesis. - -// TODO_CONSIDERATION: after we verify `State Sync` is fully functional, we can hypothetically remove old upgrades from -// the codebase, as the nodes won't have to execute upgrades and will download the "snapshot" instead. Some other -// blockchain networks do that (such as `evmos`: https://github.com/evmos/evmos/tree/main/app/upgrades). -// Note that this may inhibit a full state sync from genesis. - -import ( - "context" - - storetypes "cosmossdk.io/store/types" - upgradetypes "cosmossdk.io/x/upgrade/types" - - "github.com/cosmos/cosmos-sdk/types/module" - consensusparamtypes "github.com/cosmos/cosmos-sdk/x/consensus/types" - - "github.com/piplabs/story/client/app/keepers" - "github.com/piplabs/story/lib/errors" -) - -// defaultUpgradeHandler should be used for upgrades that only update the `ConsensusVersion`. -// If an upgrade involves state changes, parameter updates, data migrations, authz authorisation, etc, -// a new version-specific upgrade handler must be created. -func defaultUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - _ *keepers.Keepers, -) upgradetypes.UpgradeHandler { - return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - return mm.RunMigrations(ctx, configurator, vm) - } -} - -// An example of an upgrade that uses the default upgrade handler and also performs additional state changes. -// For example, even if `ConsensusVersion` is not modified for any modules, it still might be beneficial to create -// an upgrade so node runners are signaled to start utilizing `Cosmovisor` for new binaries. -var UpgradeExample = Upgrade{ - UpgradeName: "v0.0.0-Example", - CreateUpgradeHandler: defaultUpgradeHandler, - - // We can also add, rename and delete KVStores. - // More info in cosmos-sdk docs: https://docs.cosmos.network/v0.50/learn/advanced/upgrade#add-storeupgrades-for-new-modules - StoreUpgrades: storetypes.StoreUpgrades{ - // Added: []string{"newmodule"}, - }, -} - -// Upgrade0_0_4 is an example of an upgrade that increases the block size. -// This example demonstrates how to change the block size using an upgrade. -var Upgrade0_0_4 = Upgrade{ - UpgradeName: "v0.0.4", - CreateUpgradeHandler: func( - mm *module.Manager, - configurator module.Configurator, - keepers *keepers.Keepers, - ) upgradetypes.UpgradeHandler { - return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - // Get current consensus module parameters - currentParams, err := keepers.ConsensusParamsKeeper.ParamsStore.Get(ctx) - if err != nil { - return vm, errors.Wrap(err, "failed to get consensus params") - } - - // Supply all params even when changing just one, as `ToProtoConsensusParams` requires them to be present. - newParams := consensusparamtypes.MsgUpdateParams{ - Authority: keepers.ConsensusParamsKeeper.GetAuthority(), - Block: currentParams.Block, - Evidence: currentParams.Evidence, - Validator: currentParams.Validator, - - // This seems to be deprecated/not needed, but it's fine as we're copying the existing data. - Abci: currentParams.Abci, - } - - // Increase block size two-fold, 22020096 is the default value. - newParams.Block.MaxBytes = 22020096 * 2 - - // Update the chain state - if _, err = keepers.ConsensusParamsKeeper.UpdateParams(ctx, &newParams); err != nil { - return vm, errors.Wrap(err, "failed to update consensus params") - } - - return mm.RunMigrations(ctx, configurator, vm) - } - }, - // No changes to the KVStore in this upgrade. - StoreUpgrades: storetypes.StoreUpgrades{}, -} diff --git a/client/app/upgrades/types.go b/client/app/upgrades/types.go deleted file mode 100644 index 93684a1d..00000000 --- a/client/app/upgrades/types.go +++ /dev/null @@ -1,39 +0,0 @@ -package upgrades - -import ( - store "cosmossdk.io/store/types" - upgradetypes "cosmossdk.io/x/upgrade/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/module" - - "github.com/piplabs/story/client/app/keepers" -) - -// Upgrade defines a struct containing necessary fields that a MsgSoftwareUpgrade -// must have written, in order for the state migration to go smoothly. -// An upgrade must implement this struct, and then set it in the app.go. -// The app.go will then define the handler. -type Upgrade struct { - // Upgrade version name, for the upgrade handler, e.g. `v7` - UpgradeName string - - // CreateUpgradeHandler defines the function that creates an upgrade handler - CreateUpgradeHandler func(*module.Manager, module.Configurator, *keepers.Keepers) upgradetypes.UpgradeHandler - - // Store upgrades, should be used for any new modules introduced, new modules deleted, or store names renamed. - StoreUpgrades store.StoreUpgrades -} - -// Fork defines a struct containing the requisite fields for a non-software upgrade proposal -// Hard Fork at a given height to implement. -type Fork struct { - // Upgrade version name, for the upgrade handler, e.g. `v7` - UpgradeName string - // Height the upgrade occurs at. - UpgradeHeight int64 - // Upgrade info for this fork. - UpgradeInfo string - // Function that runs some custom state transition code at the beginning of a fork. - BeginForkLogic func(ctx sdk.Context, keepers *keepers.Keepers) -} diff --git a/client/app/upgrades/v0_10_0/constants.go b/client/app/upgrades/v0_10_0/constants.go deleted file mode 100644 index 3cb1acd2..00000000 --- a/client/app/upgrades/v0_10_0/constants.go +++ /dev/null @@ -1,16 +0,0 @@ -//nolint:revive,stylecheck // version underscores -package v0_10_0 - -import ( - storetypes "cosmossdk.io/store/types" - - "github.com/piplabs/story/client/app/upgrades" -) - -const UpgradeName = "v0.10.0" - -var Upgrade = upgrades.Upgrade{ - UpgradeName: UpgradeName, - CreateUpgradeHandler: CreateUpgradeHandler, - StoreUpgrades: storetypes.StoreUpgrades{}, -} diff --git a/client/app/upgrades/v0_10_0/upgrades.go b/client/app/upgrades/v0_10_0/upgrades.go deleted file mode 100644 index bc950dbf..00000000 --- a/client/app/upgrades/v0_10_0/upgrades.go +++ /dev/null @@ -1,64 +0,0 @@ -//nolint:revive,stylecheck // version underscores -package v0_10_0 - -import ( - "context" - - upgradetypes "cosmossdk.io/x/upgrade/types" - - "github.com/cosmos/cosmos-sdk/types/module" - - "github.com/piplabs/story/client/app/keepers" - "github.com/piplabs/story/lib/errors" - clog "github.com/piplabs/story/lib/log" -) - -const ( - NewMaxSweepPerBlock = 1024 -) - -func CreateUpgradeHandler( - mm *module.Manager, - configurator module.Configurator, - keepers *keepers.Keepers, -) upgradetypes.UpgradeHandler { - return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { - clog.Info(ctx, "Starting module migrations...") - - vm, err := mm.RunMigrations(ctx, configurator, vm) - if err != nil { - return vm, errors.Wrap(err, "run migrations") - } - - clog.Info(ctx, "Setting NextValidatorDelegationSweepIndex parameter...") - nextValIndex, err := keepers.EvmStakingKeeper.GetOldValidatorSweepIndex(ctx) - if err != nil { - return vm, errors.Wrap(err, "get old validator sweep index") - } - - nextValDelIndex := uint64(0) - if err := keepers.EvmStakingKeeper.SetValidatorSweepIndex( - ctx, - nextValIndex, - nextValDelIndex, - ); err != nil { - return vm, errors.Wrap(err, "set evmstaking NextValidatorDelegationSweepIndex") - } - - // Update MaxSweepPerBlock - clog.Info(ctx, "Updating MaxSweepPerBlock parameter...") - params, err := keepers.EvmStakingKeeper.GetParams(ctx) - if err != nil { - return vm, errors.Wrap(err, "get evmstaking params") - } - - params.MaxSweepPerBlock = NewMaxSweepPerBlock - if err = keepers.EvmStakingKeeper.SetParams(ctx, params); err != nil { - return vm, errors.Wrap(err, "set evmstaking params") - } - - clog.Info(ctx, "Upgrade v0.10.0 complete") - - return vm, nil - } -} diff --git a/client/pkg/appconsts/v1/app_consts.go b/client/pkg/appconsts/v1/app_consts.go new file mode 100644 index 00000000..66a63201 --- /dev/null +++ b/client/pkg/appconsts/v1/app_consts.go @@ -0,0 +1,5 @@ +package v1 + +const ( + Version uint64 = 1 +) diff --git a/client/x/evmengine/keeper/keeper.go b/client/x/evmengine/keeper/keeper.go index f3b3086c..67a20079 100644 --- a/client/x/evmengine/keeper/keeper.go +++ b/client/x/evmengine/keeper/keeper.go @@ -40,7 +40,7 @@ type Keeper struct { accountKeeper types.AccountKeeper evmstakingKeeper types.EvmStakingKeeper - upgradeKeeper types.UpgradeKeeper + signalKeeper types.SignalKeeper upgradeContract *bindings.UpgradeEntrypoint @@ -63,7 +63,7 @@ func NewKeeper( txConfig client.TxConfig, ak types.AccountKeeper, esk types.EvmStakingKeeper, - uk types.UpgradeKeeper, + sk types.SignalKeeper, ) (*Keeper, error) { schema := &ormv1alpha1.ModuleSchemaDescriptor{SchemaFile: []*ormv1alpha1.ModuleSchemaDescriptor_FileEntry{ {Id: 1, ProtoFileName: File_client_x_evmengine_keeper_evmengine_proto.Path()}, @@ -92,7 +92,7 @@ func NewKeeper( txConfig: txConfig, accountKeeper: ak, evmstakingKeeper: esk, - upgradeKeeper: uk, + signalKeeper: sk, upgradeContract: upgradeContract, }, nil } diff --git a/client/x/evmengine/keeper/upgrades.go b/client/x/evmengine/keeper/upgrades.go index 7239b07c..f6d0e4e6 100644 --- a/client/x/evmengine/keeper/upgrades.go +++ b/client/x/evmengine/keeper/upgrades.go @@ -3,7 +3,7 @@ package keeper import ( "context" - upgradetypes "cosmossdk.io/x/upgrade/types" + signaltypes "github.com/piplabs/story/client/x/signal/types" "github.com/piplabs/story/client/x/evmengine/types" "github.com/piplabs/story/contracts/bindings" @@ -39,10 +39,9 @@ func (k *Keeper) ProcessUpgradeEvents(ctx context.Context, height uint64, logs [ } func (k *Keeper) ProcessSoftwareUpgrade(ctx context.Context, ev *bindings.UpgradeEntrypointSoftwareUpgrade) error { - err := k.upgradeKeeper.ScheduleUpgrade(ctx, upgradetypes.Plan{ - Name: ev.Name, - Info: ev.Info, - Height: ev.Height, + err := k.signalKeeper.ScheduleUpgrade(ctx, signaltypes.Upgrade{ + AppVersion: ev.AppVersion, + UpgradeHeight: ev.UpgradeHeight, }) if err != nil { return errors.Wrap(err, "process software upgrade: schedule upgrade") diff --git a/client/x/evmengine/types/expected_keepers.go b/client/x/evmengine/types/expected_keepers.go index 59ca321f..eee41975 100644 --- a/client/x/evmengine/types/expected_keepers.go +++ b/client/x/evmengine/types/expected_keepers.go @@ -2,8 +2,7 @@ package types import ( "context" - - upgradetypes "cosmossdk.io/x/upgrade/types" + signaltypes "github.com/piplabs/story/client/x/signal/types" sdk "github.com/cosmos/cosmos-sdk/types" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -25,6 +24,6 @@ type EvmStakingKeeper interface { PeekEligibleWithdrawals(ctx context.Context) (withdrawals ethtypes.Withdrawals, err error) } -type UpgradeKeeper interface { - ScheduleUpgrade(ctx context.Context, plan upgradetypes.Plan) error +type SignalKeeper interface { + ScheduleUpgrade(ctx context.Context, upgrade signaltypes.Upgrade) } diff --git a/client/x/signal/keeper/keeper.go b/client/x/signal/keeper/keeper.go index c7a5dbb4..ac4bf186 100644 --- a/client/x/signal/keeper/keeper.go +++ b/client/x/signal/keeper/keeper.go @@ -9,8 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - "github.com/piplabs/story/client/x/signal/types" "github.com/piplabs/story/lib/log" ) @@ -73,33 +71,6 @@ func NewKeeper( } } -// SignalVersion is a method required by the MsgServer interface. -func (k Keeper) SignalVersion(ctx context.Context, req *types.MsgSignalVersion) (*types.MsgSignalVersionResponse, error) { - sdkCtx := sdk.UnwrapSDKContext(ctx) - - if k.IsUpgradePending(sdkCtx) { - return &types.MsgSignalVersionResponse{}, types.ErrUpgradePending.Wrapf("can not signal version") - } - - valAddr, err := sdk.ValAddressFromBech32(req.ValidatorAddress) - if err != nil { - return nil, err - } - - // The signaled version can not be less than the current version. - currentVersion := sdkCtx.BlockHeader().Version.App - if req.Version < currentVersion { - return nil, types.ErrInvalidSignalVersion.Wrapf("signaled version %d, current version %d", req.Version, currentVersion) - } - - if _, err := k.stakingKeeper.GetValidator(sdkCtx, valAddr); err != nil { - return nil, stakingtypes.ErrNoValidatorFound - } - - k.SetValidatorVersion(sdkCtx, valAddr, req.Version) - return &types.MsgSignalVersionResponse{}, nil -} - // TryUpgrade is a method required by the MsgServer interface. It tallies the // voting power that has voted on each version. If one version has reached a // quorum, an upgrade is persisted to the store. The upgrade is used by the @@ -111,7 +82,6 @@ func (k *Keeper) TryUpgrade(ctx context.Context, _ *types.MsgTryUpgrade) (*types return &types.MsgTryUpgradeResponse{}, types.ErrUpgradePending.Wrapf("can not try upgrade") } - threshold := k.GetVotingPowerThreshold(sdkCtx) hasQuorum, version := k.TallyVotingPower(sdkCtx, threshold.Int64()) if hasQuorum { if version <= sdkCtx.BlockHeader().Version.App { @@ -123,68 +93,14 @@ func (k *Keeper) TryUpgrade(ctx context.Context, _ *types.MsgTryUpgrade) (*types } k.setUpgrade(sdkCtx, upgrade) } - return &types.MsgTryUpgradeResponse{}, nil -} - -// VersionTally enables a client to query for the tally of voting power has -// signaled for a particular version. -func (k Keeper) VersionTally(ctx context.Context, req *types.QueryVersionTallyRequest) (*types.QueryVersionTallyResponse, error) { - sdkCtx := sdk.UnwrapSDKContext(ctx) - totalVotingPower, err := k.stakingKeeper.GetLastTotalPower(ctx) - if err != nil { - return &types.QueryVersionTallyResponse{}, err - } - currentVotingPower := sdkmath.NewInt(0) - stores := k.storeService.OpenKVStore(ctx) - iterator, err := stores.Iterator(types.FirstSignalKey, nil) - if err != nil { - return &types.QueryVersionTallyResponse{}, err - } - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - valAddress := sdk.ValAddress(iterator.Key()) - power, err := k.stakingKeeper.GetLastValidatorPower(sdkCtx, valAddress) - if err != nil { - log.Error(ctx, "Failed to get last validator power", err) - continue - } - version := VersionFromBytes(iterator.Value()) - if version == req.Version { - currentVotingPower = currentVotingPower.AddRaw(power) - } - } - - threshold := k.GetVotingPowerThreshold(sdkCtx) - - return &types.QueryVersionTallyResponse{ - VotingPower: currentVotingPower.Uint64(), - ThresholdPower: threshold.Uint64(), - TotalVotingPower: totalVotingPower.Uint64(), - }, nil -} - -// SetValidatorVersion saves a signaled version for a validator. -func (k Keeper) SetValidatorVersion(ctx sdk.Context, valAddress sdk.ValAddress, version uint64) { - stores := k.storeService.OpenKVStore(ctx) - if err := stores.Set(valAddress, VersionToBytes(version)); err != nil { - panic(err) - } -} - -// DeleteValidatorVersion deletes a signaled version for a validator. -func (k Keeper) DeleteValidatorVersion(ctx sdk.Context, valAddress sdk.ValAddress) { - stores := k.storeService.OpenKVStore(ctx) - if err := stores.Delete(valAddress); err != nil { - panic(err) - } + return &types.MsgTryUpgradeResponse{}, nil } // TallyVotingPower tallies the voting power for each version and returns true // and the version if any version has reached the quorum in voting power. // Returns false and 0 otherwise. -func (k Keeper) TallyVotingPower(ctx sdk.Context, threshold int64) (bool, uint64) { +func (k Keeper) TallyVotingPower(ctx sdk.Context) (bool, uint64) { stores := k.storeService.OpenKVStore(ctx) iterator, err := stores.Iterator(types.FirstSignalKey, nil) if err != nil { @@ -224,15 +140,20 @@ func (k Keeper) TallyVotingPower(ctx sdk.Context, threshold int64) (bool, uint64 return false, 0 } -// GetVotingPowerThreshold returns the voting power threshold required to -// upgrade to a new version. -func (k Keeper) GetVotingPowerThreshold(ctx sdk.Context) sdkmath.Int { - totalVotingPower, err := k.stakingKeeper.GetLastTotalPower(ctx) - if err != nil { +// SetValidatorVersion saves a signaled version for a validator. +func (k Keeper) SetValidatorVersion(ctx sdk.Context, valAddress sdk.ValAddress, version uint64) { + stores := k.storeService.OpenKVStore(ctx) + if err := stores.Set(valAddress, VersionToBytes(version)); err != nil { + panic(err) + } +} + +// DeleteValidatorVersion deletes a signaled version for a validator. +func (k Keeper) DeleteValidatorVersion(ctx sdk.Context, valAddress sdk.ValAddress) { + stores := k.storeService.OpenKVStore(ctx) + if err := stores.Delete(valAddress); err != nil { panic(err) } - thresholdFraction := Threshold(ctx.BlockHeader().Version.App) - return thresholdFraction.MulInt(totalVotingPower).Ceil().TruncateInt() } // ShouldUpgrade returns whether the signaling mechanism has concluded that the @@ -251,24 +172,6 @@ func (k *Keeper) ShouldUpgrade(ctx sdk.Context) (isQuorumVersion bool, version u return false, 0 } -// ResetTally resets the tally after a version change. It iterates over the -// store and deletes all versions. It also resets the quorumVersion and -// upgradeHeight to 0. -func (k *Keeper) ResetTally(ctx sdk.Context) { - stores := k.storeService.OpenKVStore(ctx) - iterator, err := stores.Iterator(nil, nil) - if err != nil { - panic(err) - } - defer iterator.Close() - // delete the value in the upgrade key and all signals. - for ; iterator.Valid(); iterator.Next() { - if err := stores.Delete(iterator.Key()); err != nil { - panic(err) - } - } -} - func VersionToBytes(version uint64) []byte { return binary.BigEndian.AppendUint64(nil, version) } @@ -286,6 +189,13 @@ func (k Keeper) GetUpgrade(ctx context.Context, _ *types.QueryGetUpgradeRequest) return &types.QueryGetUpgradeResponse{Upgrade: &upgrade}, nil } +func (k Keeper) ScheduleUpgrade(ctx sdk.Context, upgrade types.Upgrade) { + if k.IsUpgradePending(ctx) { + return + } + k.setUpgrade(ctx, upgrade) +} + // IsUpgradePending returns true if an app version has reached quorum and the // chain should upgrade to the app version at the upgrade height. While the // keeper has an upgrade pending the SignalVersion and TryUpgrade messages will diff --git a/client/x/signal/types/query.proto b/client/x/signal/types/query.proto index e1ebe046..24337108 100644 --- a/client/x/signal/types/query.proto +++ b/client/x/signal/types/query.proto @@ -8,13 +8,6 @@ option go_package = "client/x/signal/types"; // Query defines the signal Query service. service Query { - // VersionTally enables a client to query for the tally of voting power that - // has signalled for a particular version. - rpc VersionTally(QueryVersionTallyRequest) - returns (QueryVersionTallyResponse) { - option (google.api.http).get = "/signal/tally/{version}"; - } - // GetUpgrade enables a client to query for upgrade information if an upgrade is pending. // The response will be empty if no upgrade is pending. rpc GetUpgrade(QueryGetUpgradeRequest) @@ -23,16 +16,6 @@ service Query { } } -// QueryVersionTallyRequest is the request type for the VersionTally query. -message QueryVersionTallyRequest { uint64 version = 1; } - -// QueryVersionTallyResponse is the response type for the VersionTally query. -message QueryVersionTallyResponse { - uint64 voting_power = 1; - uint64 threshold_power = 2; - uint64 total_voting_power = 3; -} - // QueryGetUpgradeRequest is the request type for the GetUpgrade query. message QueryGetUpgradeRequest {} diff --git a/client/x/signal/types/tx.proto b/client/x/signal/types/tx.proto index b5a71ecd..73dcff3f 100644 --- a/client/x/signal/types/tx.proto +++ b/client/x/signal/types/tx.proto @@ -28,9 +28,6 @@ message MsgSignalVersion { uint64 version = 2; } -// MsgSignalVersionResponse is the response type for the SignalVersion method. -message MsgSignalVersionResponse {} - // MsgTryUpgrade tries to upgrade the chain. message MsgTryUpgrade { string signer = 1; }