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

     1  package keeper
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	"cosmossdk.io/collections"
     9  	corestoretypes "cosmossdk.io/core/store"
    10  	"cosmossdk.io/log"
    11  
    12  	"github.com/cosmos/cosmos-sdk/baseapp"
    13  	"github.com/cosmos/cosmos-sdk/codec"
    14  	sdk "github.com/cosmos/cosmos-sdk/types"
    15  	"github.com/cosmos/cosmos-sdk/x/gov/types"
    16  	v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
    17  	"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
    18  )
    19  
    20  // Keeper defines the governance module Keeper
    21  type Keeper struct {
    22  	authKeeper  types.AccountKeeper
    23  	bankKeeper  types.BankKeeper
    24  	distrKeeper types.DistributionKeeper
    25  
    26  	// The reference to the DelegationSet and ValidatorSet to get information about validators and delegators
    27  	sk types.StakingKeeper
    28  
    29  	// GovHooks
    30  	hooks types.GovHooks
    31  
    32  	// The (unexposed) keys used to access the stores from the Context.
    33  	storeService corestoretypes.KVStoreService
    34  
    35  	// The codec for binary encoding/decoding.
    36  	cdc codec.Codec
    37  
    38  	// Legacy Proposal router
    39  	legacyRouter v1beta1.Router
    40  
    41  	// Msg server router
    42  	router baseapp.MessageRouter
    43  
    44  	config types.Config
    45  
    46  	// the address capable of executing a MsgUpdateParams message. Typically, this
    47  	// should be the x/gov module account.
    48  	authority string
    49  
    50  	Schema                 collections.Schema
    51  	Constitution           collections.Item[string]
    52  	Params                 collections.Item[v1.Params]
    53  	Deposits               collections.Map[collections.Pair[uint64, sdk.AccAddress], v1.Deposit]
    54  	Votes                  collections.Map[collections.Pair[uint64, sdk.AccAddress], v1.Vote]
    55  	ProposalID             collections.Sequence
    56  	Proposals              collections.Map[uint64, v1.Proposal]
    57  	ActiveProposalsQueue   collections.Map[collections.Pair[time.Time, uint64], uint64] // TODO(tip): this should be simplified and go into an index.
    58  	InactiveProposalsQueue collections.Map[collections.Pair[time.Time, uint64], uint64] // TODO(tip): this should be simplified and go into an index.
    59  	VotingPeriodProposals  collections.Map[uint64, []byte]                              // TODO(tip): this could be a keyset or index.
    60  }
    61  
    62  // GetAuthority returns the x/gov module's authority.
    63  func (k Keeper) GetAuthority() string {
    64  	return k.authority
    65  }
    66  
    67  // NewKeeper returns a governance keeper. It handles:
    68  // - submitting governance proposals
    69  // - depositing funds into proposals, and activating upon sufficient funds being deposited
    70  // - users voting on proposals, with weight proportional to stake in the system
    71  // - and tallying the result of the vote.
    72  //
    73  // CONTRACT: the parameter Subspace must have the param key table already initialized
    74  func NewKeeper(
    75  	cdc codec.Codec, storeService corestoretypes.KVStoreService, authKeeper types.AccountKeeper,
    76  	bankKeeper types.BankKeeper, sk types.StakingKeeper, distrKeeper types.DistributionKeeper,
    77  	router baseapp.MessageRouter, config types.Config, authority string,
    78  ) *Keeper {
    79  	// ensure governance module account is set
    80  	if addr := authKeeper.GetModuleAddress(types.ModuleName); addr == nil {
    81  		panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
    82  	}
    83  
    84  	if _, err := authKeeper.AddressCodec().StringToBytes(authority); err != nil {
    85  		panic(fmt.Sprintf("invalid authority address: %s", authority))
    86  	}
    87  
    88  	// If MaxMetadataLen not set by app developer, set to default value.
    89  	if config.MaxMetadataLen == 0 {
    90  		config.MaxMetadataLen = types.DefaultConfig().MaxMetadataLen
    91  	}
    92  
    93  	sb := collections.NewSchemaBuilder(storeService)
    94  	k := &Keeper{
    95  		storeService:           storeService,
    96  		authKeeper:             authKeeper,
    97  		bankKeeper:             bankKeeper,
    98  		distrKeeper:            distrKeeper,
    99  		sk:                     sk,
   100  		cdc:                    cdc,
   101  		router:                 router,
   102  		config:                 config,
   103  		authority:              authority,
   104  		Constitution:           collections.NewItem(sb, types.ConstitutionKey, "constitution", collections.StringValue),
   105  		Params:                 collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[v1.Params](cdc)),
   106  		Deposits:               collections.NewMap(sb, types.DepositsKeyPrefix, "deposits", collections.PairKeyCodec(collections.Uint64Key, sdk.LengthPrefixedAddressKey(sdk.AccAddressKey)), codec.CollValue[v1.Deposit](cdc)), // nolint: staticcheck // sdk.LengthPrefixedAddressKey is needed to retain state compatibility
   107  		Votes:                  collections.NewMap(sb, types.VotesKeyPrefix, "votes", collections.PairKeyCodec(collections.Uint64Key, sdk.LengthPrefixedAddressKey(sdk.AccAddressKey)), codec.CollValue[v1.Vote](cdc)),          // nolint: staticcheck // sdk.LengthPrefixedAddressKey is needed to retain state compatibility
   108  		ProposalID:             collections.NewSequence(sb, types.ProposalIDKey, "proposal_id"),
   109  		Proposals:              collections.NewMap(sb, types.ProposalsKeyPrefix, "proposals", collections.Uint64Key, codec.CollValue[v1.Proposal](cdc)),
   110  		ActiveProposalsQueue:   collections.NewMap(sb, types.ActiveProposalQueuePrefix, "active_proposals_queue", collections.PairKeyCodec(sdk.TimeKey, collections.Uint64Key), collections.Uint64Value),     // sdk.TimeKey is needed to retain state compatibility
   111  		InactiveProposalsQueue: collections.NewMap(sb, types.InactiveProposalQueuePrefix, "inactive_proposals_queue", collections.PairKeyCodec(sdk.TimeKey, collections.Uint64Key), collections.Uint64Value), // sdk.TimeKey is needed to retain state compatibility
   112  		VotingPeriodProposals:  collections.NewMap(sb, types.VotingPeriodProposalKeyPrefix, "voting_period_proposals", collections.Uint64Key, collections.BytesValue),
   113  	}
   114  	schema, err := sb.Build()
   115  	if err != nil {
   116  		panic(err)
   117  	}
   118  	k.Schema = schema
   119  	return k
   120  }
   121  
   122  // Hooks gets the hooks for governance *Keeper {
   123  func (k *Keeper) Hooks() types.GovHooks {
   124  	if k.hooks == nil {
   125  		// return a no-op implementation if no hooks are set
   126  		return types.MultiGovHooks{}
   127  	}
   128  
   129  	return k.hooks
   130  }
   131  
   132  // SetHooks sets the hooks for governance
   133  func (k *Keeper) SetHooks(gh types.GovHooks) *Keeper {
   134  	if k.hooks != nil {
   135  		panic("cannot set governance hooks twice")
   136  	}
   137  
   138  	k.hooks = gh
   139  
   140  	return k
   141  }
   142  
   143  // SetLegacyRouter sets the legacy router for governance
   144  func (k *Keeper) SetLegacyRouter(router v1beta1.Router) {
   145  	// It is vital to seal the governance proposal router here as to not allow
   146  	// further handlers to be registered after the keeper is created since this
   147  	// could create invalid or non-deterministic behavior.
   148  	router.Seal()
   149  	k.legacyRouter = router
   150  }
   151  
   152  // Logger returns a module-specific logger.
   153  func (k Keeper) Logger(ctx context.Context) log.Logger {
   154  	sdkCtx := sdk.UnwrapSDKContext(ctx)
   155  	return sdkCtx.Logger().With("module", "x/"+types.ModuleName)
   156  }
   157  
   158  // Router returns the gov keeper's router
   159  func (k Keeper) Router() baseapp.MessageRouter {
   160  	return k.router
   161  }
   162  
   163  // LegacyRouter returns the gov keeper's legacy router
   164  func (k Keeper) LegacyRouter() v1beta1.Router {
   165  	return k.legacyRouter
   166  }
   167  
   168  // GetGovernanceAccount returns the governance ModuleAccount
   169  func (k Keeper) GetGovernanceAccount(ctx context.Context) sdk.ModuleAccountI {
   170  	return k.authKeeper.GetModuleAccount(ctx, types.ModuleName)
   171  }
   172  
   173  // ModuleAccountAddress returns gov module account address
   174  func (k Keeper) ModuleAccountAddress() sdk.AccAddress {
   175  	return k.authKeeper.GetModuleAddress(types.ModuleName)
   176  }
   177  
   178  // assertMetadataLength returns an error if given metadata length
   179  // is greater than a pre-defined MaxMetadataLen.
   180  func (k Keeper) assertMetadataLength(metadata string) error {
   181  	if metadata != "" && uint64(len(metadata)) > k.config.MaxMetadataLen {
   182  		return types.ErrMetadataTooLong.Wrapf("got metadata with length %d", len(metadata))
   183  	}
   184  	return nil
   185  }
   186  
   187  // assertSummaryLength returns an error if given summary length
   188  // is greater than a pre-defined 40*MaxMetadataLen.
   189  func (k Keeper) assertSummaryLength(summary string) error {
   190  	if summary != "" && uint64(len(summary)) > 40*k.config.MaxMetadataLen {
   191  		return types.ErrSummaryTooLong.Wrapf("got summary with length %d", len(summary))
   192  	}
   193  	return nil
   194  }