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 }