cosmos-sdk/x/gov/keeper/keeper.go
mergify[bot] 983c9f7aec
chore: cherry-pick some inj changes (backport #17109) (#17110)
Co-authored-by: Julien Robert <julien@rbrt.fr>
2023-07-24 13:36:24 +00:00

195 lines
7.7 KiB
Go

package keeper
import (
"context"
"fmt"
"time"
"cosmossdk.io/collections"
corestoretypes "cosmossdk.io/core/store"
"cosmossdk.io/log"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov/types"
v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
"github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1"
)
// Keeper defines the governance module Keeper
type Keeper struct {
authKeeper types.AccountKeeper
bankKeeper types.BankKeeper
distrKeeper types.DistributionKeeper
// The reference to the DelegationSet and ValidatorSet to get information about validators and delegators
sk types.StakingKeeper
// GovHooks
hooks types.GovHooks
// The (unexposed) keys used to access the stores from the Context.
storeService corestoretypes.KVStoreService
// The codec for binary encoding/decoding.
cdc codec.Codec
// Legacy Proposal router
legacyRouter v1beta1.Router
// Msg server router
router baseapp.MessageRouter
config types.Config
// the address capable of executing a MsgUpdateParams message. Typically, this
// should be the x/gov module account.
authority string
Schema collections.Schema
Constitution collections.Item[string]
Params collections.Item[v1.Params]
Deposits collections.Map[collections.Pair[uint64, sdk.AccAddress], v1.Deposit]
Votes collections.Map[collections.Pair[uint64, sdk.AccAddress], v1.Vote]
ProposalID collections.Sequence
Proposals collections.Map[uint64, v1.Proposal]
ActiveProposalsQueue collections.Map[collections.Pair[time.Time, uint64], uint64] // TODO(tip): this should be simplified and go into an index.
InactiveProposalsQueue collections.Map[collections.Pair[time.Time, uint64], uint64] // TODO(tip): this should be simplified and go into an index.
VotingPeriodProposals collections.Map[uint64, []byte] // TODO(tip): this could be a keyset or index.
}
// GetAuthority returns the x/gov module's authority.
func (k Keeper) GetAuthority() string {
return k.authority
}
// NewKeeper returns a governance keeper. It handles:
// - submitting governance proposals
// - depositing funds into proposals, and activating upon sufficient funds being deposited
// - users voting on proposals, with weight proportional to stake in the system
// - and tallying the result of the vote.
//
// CONTRACT: the parameter Subspace must have the param key table already initialized
func NewKeeper(
cdc codec.Codec, storeService corestoretypes.KVStoreService, authKeeper types.AccountKeeper,
bankKeeper types.BankKeeper, sk types.StakingKeeper, distrKeeper types.DistributionKeeper,
router baseapp.MessageRouter, config types.Config, authority string,
) *Keeper {
// ensure governance module account is set
if addr := authKeeper.GetModuleAddress(types.ModuleName); addr == nil {
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
}
if _, err := authKeeper.AddressCodec().StringToBytes(authority); err != nil {
panic(fmt.Sprintf("invalid authority address: %s", authority))
}
// If MaxMetadataLen not set by app developer, set to default value.
if config.MaxMetadataLen == 0 {
config.MaxMetadataLen = types.DefaultConfig().MaxMetadataLen
}
sb := collections.NewSchemaBuilder(storeService)
k := &Keeper{
storeService: storeService,
authKeeper: authKeeper,
bankKeeper: bankKeeper,
distrKeeper: distrKeeper,
sk: sk,
cdc: cdc,
router: router,
config: config,
authority: authority,
Constitution: collections.NewItem(sb, types.ConstitutionKey, "constitution", collections.StringValue),
Params: collections.NewItem(sb, types.ParamsKey, "params", codec.CollValue[v1.Params](cdc)),
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
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
ProposalID: collections.NewSequence(sb, types.ProposalIDKey, "proposal_id"),
Proposals: collections.NewMap(sb, types.ProposalsKeyPrefix, "proposals", collections.Uint64Key, codec.CollValue[v1.Proposal](cdc)),
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
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
VotingPeriodProposals: collections.NewMap(sb, types.VotingPeriodProposalKeyPrefix, "voting_period_proposals", collections.Uint64Key, collections.BytesValue),
}
schema, err := sb.Build()
if err != nil {
panic(err)
}
k.Schema = schema
return k
}
// Hooks gets the hooks for governance *Keeper {
func (k *Keeper) Hooks() types.GovHooks {
if k.hooks == nil {
// return a no-op implementation if no hooks are set
return types.MultiGovHooks{}
}
return k.hooks
}
// SetHooks sets the hooks for governance
func (k *Keeper) SetHooks(gh types.GovHooks) *Keeper {
if k.hooks != nil {
panic("cannot set governance hooks twice")
}
k.hooks = gh
return k
}
// SetLegacyRouter sets the legacy router for governance
func (k *Keeper) SetLegacyRouter(router v1beta1.Router) {
// It is vital to seal the governance proposal router here as to not allow
// further handlers to be registered after the keeper is created since this
// could create invalid or non-deterministic behavior.
router.Seal()
k.legacyRouter = router
}
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx context.Context) log.Logger {
sdkCtx := sdk.UnwrapSDKContext(ctx)
return sdkCtx.Logger().With("module", "x/"+types.ModuleName)
}
// Router returns the gov keeper's router
func (k Keeper) Router() baseapp.MessageRouter {
return k.router
}
// LegacyRouter returns the gov keeper's legacy router
func (k Keeper) LegacyRouter() v1beta1.Router {
return k.legacyRouter
}
// GetGovernanceAccount returns the governance ModuleAccount
func (k Keeper) GetGovernanceAccount(ctx context.Context) sdk.ModuleAccountI {
return k.authKeeper.GetModuleAccount(ctx, types.ModuleName)
}
// ModuleAccountAddress returns gov module account address
func (k Keeper) ModuleAccountAddress() sdk.AccAddress {
return k.authKeeper.GetModuleAddress(types.ModuleName)
}
// assertMetadataLength returns an error if given metadata length
// is greater than a pre-defined MaxMetadataLen.
func (k Keeper) assertMetadataLength(metadata string) error {
if metadata != "" && uint64(len(metadata)) > k.config.MaxMetadataLen {
return types.ErrMetadataTooLong.Wrapf("got metadata with length %d", len(metadata))
}
return nil
}
// assertSummaryLength returns an error if given summary length
// is greater than a pre-defined 40*MaxMetadataLen.
func (k Keeper) assertSummaryLength(summary string) error {
if summary != "" && uint64(len(summary)) > 40*k.config.MaxMetadataLen {
return types.ErrSummaryTooLong.Wrapf("got summary with length %d", len(summary))
}
return nil
}