github.com/cosmos/cosmos-sdk@v0.50.10/x/gov/module.go (about)

     1  package gov
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"sort"
     8  	"strings"
     9  
    10  	gwruntime "github.com/grpc-ecosystem/grpc-gateway/runtime"
    11  	"github.com/spf13/cobra"
    12  	"golang.org/x/exp/maps"
    13  	"golang.org/x/exp/slices"
    14  
    15  	modulev1 "cosmossdk.io/api/cosmos/gov/module/v1"
    16  	"cosmossdk.io/core/address"
    17  	"cosmossdk.io/core/appmodule"
    18  	store "cosmossdk.io/core/store"
    19  	"cosmossdk.io/depinject"
    20  
    21  	"github.com/cosmos/cosmos-sdk/baseapp"
    22  	"github.com/cosmos/cosmos-sdk/client"
    23  	"github.com/cosmos/cosmos-sdk/codec"
    24  	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
    25  	sdk "github.com/cosmos/cosmos-sdk/types"
    26  	"github.com/cosmos/cosmos-sdk/types/module"
    27  	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
    28  	authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
    29  	govclient "github.com/cosmos/cosmos-sdk/x/gov/client"
    30  	"github.com/cosmos/cosmos-sdk/x/gov/client/cli"
    31  	"github.com/cosmos/cosmos-sdk/x/gov/keeper"
    32  	"github.com/cosmos/cosmos-sdk/x/gov/simulation"
    33  	govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
    34  	v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
    35  	"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
    36  	paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
    37  )
    38  
    39  const ConsensusVersion = 5
    40  
    41  var (
    42  	_ module.AppModuleBasic      = AppModuleBasic{}
    43  	_ module.AppModuleSimulation = AppModule{}
    44  	_ module.HasGenesis          = AppModule{}
    45  	_ module.HasServices         = AppModule{}
    46  	_ module.HasInvariants       = AppModule{}
    47  
    48  	_ appmodule.AppModule     = AppModule{}
    49  	_ appmodule.HasEndBlocker = AppModule{}
    50  )
    51  
    52  // AppModuleBasic defines the basic application module used by the gov module.
    53  type AppModuleBasic struct {
    54  	cdc                    codec.Codec
    55  	legacyProposalHandlers []govclient.ProposalHandler // legacy proposal handlers which live in governance cli and rest
    56  	ac                     address.Codec
    57  }
    58  
    59  // NewAppModuleBasic creates a new AppModuleBasic object
    60  func NewAppModuleBasic(legacyProposalHandlers []govclient.ProposalHandler) AppModuleBasic {
    61  	return AppModuleBasic{
    62  		legacyProposalHandlers: legacyProposalHandlers,
    63  	}
    64  }
    65  
    66  // Name returns the gov module's name.
    67  func (AppModuleBasic) Name() string {
    68  	return govtypes.ModuleName
    69  }
    70  
    71  // RegisterLegacyAminoCodec registers the gov module's types for the given codec.
    72  func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
    73  	v1beta1.RegisterLegacyAminoCodec(cdc)
    74  	v1.RegisterLegacyAminoCodec(cdc)
    75  }
    76  
    77  // DefaultGenesis returns default genesis state as raw bytes for the gov
    78  // module.
    79  func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
    80  	return cdc.MustMarshalJSON(v1.DefaultGenesisState())
    81  }
    82  
    83  // ValidateGenesis performs genesis state validation for the gov module.
    84  func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error {
    85  	var data v1.GenesisState
    86  	if err := cdc.UnmarshalJSON(bz, &data); err != nil {
    87  		return fmt.Errorf("failed to unmarshal %s genesis state: %w", govtypes.ModuleName, err)
    88  	}
    89  
    90  	return v1.ValidateGenesis(&data)
    91  }
    92  
    93  // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the gov module.
    94  func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *gwruntime.ServeMux) {
    95  	if err := v1.RegisterQueryHandlerClient(context.Background(), mux, v1.NewQueryClient(clientCtx)); err != nil {
    96  		panic(err)
    97  	}
    98  	if err := v1beta1.RegisterQueryHandlerClient(context.Background(), mux, v1beta1.NewQueryClient(clientCtx)); err != nil {
    99  		panic(err)
   100  	}
   101  }
   102  
   103  // GetTxCmd returns the root tx command for the gov module.
   104  func (ab AppModuleBasic) GetTxCmd() *cobra.Command {
   105  	legacyProposalCLIHandlers := getProposalCLIHandlers(ab.legacyProposalHandlers)
   106  
   107  	return cli.NewTxCmd(legacyProposalCLIHandlers)
   108  }
   109  
   110  func getProposalCLIHandlers(handlers []govclient.ProposalHandler) []*cobra.Command {
   111  	proposalCLIHandlers := make([]*cobra.Command, 0, len(handlers))
   112  	for _, proposalHandler := range handlers {
   113  		proposalCLIHandlers = append(proposalCLIHandlers, proposalHandler.CLIHandler())
   114  	}
   115  	return proposalCLIHandlers
   116  }
   117  
   118  // RegisterInterfaces implements InterfaceModule.RegisterInterfaces
   119  func (AppModuleBasic) RegisterInterfaces(registry codectypes.InterfaceRegistry) {
   120  	v1.RegisterInterfaces(registry)
   121  	v1beta1.RegisterInterfaces(registry)
   122  }
   123  
   124  // AppModule implements an application module for the gov module.
   125  type AppModule struct {
   126  	AppModuleBasic
   127  
   128  	keeper        *keeper.Keeper
   129  	accountKeeper govtypes.AccountKeeper
   130  	bankKeeper    govtypes.BankKeeper
   131  
   132  	// legacySubspace is used solely for migration of x/params managed parameters
   133  	legacySubspace govtypes.ParamSubspace
   134  }
   135  
   136  // NewAppModule creates a new AppModule object
   137  func NewAppModule(
   138  	cdc codec.Codec, keeper *keeper.Keeper,
   139  	ak govtypes.AccountKeeper, bk govtypes.BankKeeper, ss govtypes.ParamSubspace,
   140  ) AppModule {
   141  	return AppModule{
   142  		AppModuleBasic: AppModuleBasic{cdc: cdc, ac: ak.AddressCodec()},
   143  		keeper:         keeper,
   144  		accountKeeper:  ak,
   145  		bankKeeper:     bk,
   146  		legacySubspace: ss,
   147  	}
   148  }
   149  
   150  // IsOnePerModuleType implements the depinject.OnePerModuleType interface.
   151  func (am AppModule) IsOnePerModuleType() {}
   152  
   153  // IsAppModule implements the appmodule.AppModule interface.
   154  func (am AppModule) IsAppModule() {}
   155  
   156  func init() {
   157  	appmodule.Register(
   158  		&modulev1.Module{},
   159  		appmodule.Provide(ProvideModule, ProvideKeyTable),
   160  		appmodule.Invoke(InvokeAddRoutes, InvokeSetHooks))
   161  }
   162  
   163  type ModuleInputs struct {
   164  	depinject.In
   165  
   166  	Config           *modulev1.Module
   167  	Cdc              codec.Codec
   168  	StoreService     store.KVStoreService
   169  	ModuleKey        depinject.OwnModuleKey
   170  	MsgServiceRouter baseapp.MessageRouter
   171  
   172  	AccountKeeper      govtypes.AccountKeeper
   173  	BankKeeper         govtypes.BankKeeper
   174  	StakingKeeper      govtypes.StakingKeeper
   175  	DistributionKeeper govtypes.DistributionKeeper
   176  
   177  	// LegacySubspace is used solely for migration of x/params managed parameters
   178  	LegacySubspace govtypes.ParamSubspace `optional:"true"`
   179  }
   180  
   181  type ModuleOutputs struct {
   182  	depinject.Out
   183  
   184  	Module       appmodule.AppModule
   185  	Keeper       *keeper.Keeper
   186  	HandlerRoute v1beta1.HandlerRoute
   187  }
   188  
   189  func ProvideModule(in ModuleInputs) ModuleOutputs {
   190  	defaultConfig := govtypes.DefaultConfig()
   191  	if in.Config.MaxMetadataLen != 0 {
   192  		defaultConfig.MaxMetadataLen = in.Config.MaxMetadataLen
   193  	}
   194  
   195  	// default to governance authority if not provided
   196  	authority := authtypes.NewModuleAddress(govtypes.ModuleName)
   197  	if in.Config.Authority != "" {
   198  		authority = authtypes.NewModuleAddressOrBech32Address(in.Config.Authority)
   199  	}
   200  
   201  	k := keeper.NewKeeper(
   202  		in.Cdc,
   203  		in.StoreService,
   204  		in.AccountKeeper,
   205  		in.BankKeeper,
   206  		in.StakingKeeper,
   207  		in.DistributionKeeper,
   208  		in.MsgServiceRouter,
   209  		defaultConfig,
   210  		authority.String(),
   211  	)
   212  	m := NewAppModule(in.Cdc, k, in.AccountKeeper, in.BankKeeper, in.LegacySubspace)
   213  	hr := v1beta1.HandlerRoute{Handler: v1beta1.ProposalHandler, RouteKey: govtypes.RouterKey}
   214  
   215  	return ModuleOutputs{Module: m, Keeper: k, HandlerRoute: hr}
   216  }
   217  
   218  func ProvideKeyTable() paramtypes.KeyTable {
   219  	return v1.ParamKeyTable() //nolint:staticcheck // we still need this for upgrades
   220  }
   221  
   222  func InvokeAddRoutes(keeper *keeper.Keeper, routes []v1beta1.HandlerRoute) {
   223  	if keeper == nil || routes == nil {
   224  		return
   225  	}
   226  
   227  	// Default route order is a lexical sort by RouteKey.
   228  	// Explicit ordering can be added to the module config if required.
   229  	slices.SortFunc(routes, func(x, y v1beta1.HandlerRoute) int {
   230  		return strings.Compare(x.RouteKey, y.RouteKey)
   231  	})
   232  
   233  	router := v1beta1.NewRouter()
   234  	for _, r := range routes {
   235  		router.AddRoute(r.RouteKey, r.Handler)
   236  	}
   237  	keeper.SetLegacyRouter(router)
   238  }
   239  
   240  func InvokeSetHooks(keeper *keeper.Keeper, govHooks map[string]govtypes.GovHooksWrapper) error {
   241  	if keeper == nil || govHooks == nil {
   242  		return nil
   243  	}
   244  
   245  	// Default ordering is lexical by module name.
   246  	// Explicit ordering can be added to the module config if required.
   247  	modNames := maps.Keys(govHooks)
   248  	order := modNames
   249  	sort.Strings(order)
   250  
   251  	var multiHooks govtypes.MultiGovHooks
   252  	for _, modName := range order {
   253  		hook, ok := govHooks[modName]
   254  		if !ok {
   255  			return fmt.Errorf("can't find staking hooks for module %s", modName)
   256  		}
   257  		multiHooks = append(multiHooks, hook)
   258  	}
   259  
   260  	keeper.SetHooks(multiHooks)
   261  	return nil
   262  }
   263  
   264  // RegisterInvariants registers module invariants
   265  func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {
   266  	keeper.RegisterInvariants(ir, am.keeper, am.bankKeeper)
   267  }
   268  
   269  // RegisterServices registers module services.
   270  func (am AppModule) RegisterServices(cfg module.Configurator) {
   271  	msgServer := keeper.NewMsgServerImpl(am.keeper)
   272  	v1beta1.RegisterMsgServer(cfg.MsgServer(), keeper.NewLegacyMsgServerImpl(am.accountKeeper.GetModuleAddress(govtypes.ModuleName).String(), msgServer))
   273  	v1.RegisterMsgServer(cfg.MsgServer(), msgServer)
   274  
   275  	legacyQueryServer := keeper.NewLegacyQueryServer(am.keeper)
   276  	v1beta1.RegisterQueryServer(cfg.QueryServer(), legacyQueryServer)
   277  	v1.RegisterQueryServer(cfg.QueryServer(), keeper.NewQueryServer(am.keeper))
   278  
   279  	m := keeper.NewMigrator(am.keeper, am.legacySubspace)
   280  	if err := cfg.RegisterMigration(govtypes.ModuleName, 1, m.Migrate1to2); err != nil {
   281  		panic(fmt.Sprintf("failed to migrate x/gov from version 1 to 2: %v", err))
   282  	}
   283  
   284  	if err := cfg.RegisterMigration(govtypes.ModuleName, 2, m.Migrate2to3); err != nil {
   285  		panic(fmt.Sprintf("failed to migrate x/gov from version 2 to 3: %v", err))
   286  	}
   287  
   288  	if err := cfg.RegisterMigration(govtypes.ModuleName, 3, m.Migrate3to4); err != nil {
   289  		panic(fmt.Sprintf("failed to migrate x/gov from version 3 to 4: %v", err))
   290  	}
   291  
   292  	if err := cfg.RegisterMigration(govtypes.ModuleName, 4, m.Migrate4to5); err != nil {
   293  		panic(fmt.Sprintf("failed to migrate x/gov from version 4 to 5: %v", err))
   294  	}
   295  }
   296  
   297  // InitGenesis performs genesis initialization for the gov module. It returns
   298  // no validator updates.
   299  func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) {
   300  	var genesisState v1.GenesisState
   301  	cdc.MustUnmarshalJSON(data, &genesisState)
   302  	InitGenesis(ctx, am.accountKeeper, am.bankKeeper, am.keeper, &genesisState)
   303  }
   304  
   305  // ExportGenesis returns the exported genesis state as raw bytes for the gov
   306  // module.
   307  func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
   308  	gs, err := ExportGenesis(ctx, am.keeper)
   309  	if err != nil {
   310  		panic(err)
   311  	}
   312  	return cdc.MustMarshalJSON(gs)
   313  }
   314  
   315  // ConsensusVersion implements AppModule/ConsensusVersion.
   316  func (AppModule) ConsensusVersion() uint64 { return ConsensusVersion }
   317  
   318  // EndBlock returns the end blocker for the gov module. It returns no validator
   319  // updates.
   320  func (am AppModule) EndBlock(ctx context.Context) error {
   321  	c := sdk.UnwrapSDKContext(ctx)
   322  	return EndBlocker(c, am.keeper)
   323  }
   324  
   325  // AppModuleSimulation functions
   326  
   327  // GenerateGenesisState creates a randomized GenState of the gov module.
   328  func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
   329  	simulation.RandomizedGenState(simState)
   330  }
   331  
   332  // ProposalContents returns all the gov content functions used to
   333  // simulate governance proposals.
   334  func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { //nolint:staticcheck // used for legacy testing
   335  	return simulation.ProposalContents()
   336  }
   337  
   338  // ProposalMsgs returns all the gov msgs used to simulate governance proposals.
   339  func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg {
   340  	return simulation.ProposalMsgs()
   341  }
   342  
   343  // RegisterStoreDecoder registers a decoder for gov module's types
   344  func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) {
   345  	sdr[govtypes.StoreKey] = simtypes.NewStoreDecoderFuncFromCollectionsSchema(am.keeper.Schema)
   346  }
   347  
   348  // WeightedOperations returns the all the gov module operations with their respective weights.
   349  func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
   350  	return simulation.WeightedOperations(
   351  		simState.AppParams, simState.TxConfig,
   352  		am.accountKeeper, am.bankKeeper, am.keeper,
   353  		simState.ProposalMsgs, simState.LegacyProposalContents,
   354  	)
   355  }