package gov import ( "fmt" "time" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/supply/exported" "github.com/tendermint/tendermint/libs/log" ) // Governance Keeper type Keeper struct { // The reference to the Param Keeper to get and set Global Params paramsKeeper params.Keeper // The reference to the Paramstore to get and set gov specific params paramSpace params.Subspace // The SupplyKeeper to reduce the supply of the network supplyKeeper SupplyKeeper // The reference to the DelegationSet and ValidatorSet to get information about validators and delegators sk StakingKeeper // The (unexposed) keys used to access the stores from the Context. storeKey sdk.StoreKey // The codec codec for binary encoding/decoding. cdc *codec.Codec // Reserved codespace codespace sdk.CodespaceType // Proposal router router Router } // 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. func NewKeeper( cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper, paramSpace params.Subspace, supplyKeeper SupplyKeeper, sk StakingKeeper, codespace sdk.CodespaceType, rtr Router, ) Keeper { // ensure governance module account is set if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil { panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) } // 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. rtr.Seal() return Keeper{ storeKey: key, paramsKeeper: paramsKeeper, paramSpace: paramSpace.WithKeyTable(ParamKeyTable()), supplyKeeper: supplyKeeper, sk: sk, cdc: cdc, codespace: codespace, router: rtr, } } // Logger returns a module-specific logger. func (keeper Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", fmt.Sprintf("x/%s", types.ModuleName)) } // GetGovernanceAccount returns the governance ModuleAccount func (keeper Keeper) GetGovernanceAccount(ctx sdk.Context) exported.ModuleAccountI { return keeper.supplyKeeper.GetModuleAccount(ctx, types.ModuleName) } // Params // Returns the current DepositParams from the global param store func (keeper Keeper) GetDepositParams(ctx sdk.Context) DepositParams { var depositParams DepositParams keeper.paramSpace.Get(ctx, ParamStoreKeyDepositParams, &depositParams) return depositParams } // Returns the current VotingParams from the global param store func (keeper Keeper) GetVotingParams(ctx sdk.Context) VotingParams { var votingParams VotingParams keeper.paramSpace.Get(ctx, ParamStoreKeyVotingParams, &votingParams) return votingParams } // Returns the current TallyParam from the global param store func (keeper Keeper) GetTallyParams(ctx sdk.Context) TallyParams { var tallyParams TallyParams keeper.paramSpace.Get(ctx, ParamStoreKeyTallyParams, &tallyParams) return tallyParams } func (keeper Keeper) setDepositParams(ctx sdk.Context, depositParams DepositParams) { keeper.paramSpace.Set(ctx, ParamStoreKeyDepositParams, &depositParams) } func (keeper Keeper) setVotingParams(ctx sdk.Context, votingParams VotingParams) { keeper.paramSpace.Set(ctx, ParamStoreKeyVotingParams, &votingParams) } func (keeper Keeper) setTallyParams(ctx sdk.Context, tallyParams TallyParams) { keeper.paramSpace.Set(ctx, ParamStoreKeyTallyParams, &tallyParams) } // ProposalQueues // InsertActiveProposalQueue inserts a ProposalID into the active proposal queue at endTime func (keeper Keeper) InsertActiveProposalQueue(ctx sdk.Context, proposalID uint64, endTime time.Time) { store := ctx.KVStore(keeper.storeKey) bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID) store.Set(types.ActiveProposalQueueKey(proposalID, endTime), bz) } // RemoveFromActiveProposalQueue removes a proposalID from the Active Proposal Queue func (keeper Keeper) RemoveFromActiveProposalQueue(ctx sdk.Context, proposalID uint64, endTime time.Time) { store := ctx.KVStore(keeper.storeKey) store.Delete(types.ActiveProposalQueueKey(proposalID, endTime)) } // InsertInactiveProposalQueue Inserts a ProposalID into the inactive proposal queue at endTime func (keeper Keeper) InsertInactiveProposalQueue(ctx sdk.Context, proposalID uint64, endTime time.Time) { store := ctx.KVStore(keeper.storeKey) bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID) store.Set(types.InactiveProposalQueueKey(proposalID, endTime), bz) } // RemoveFromInactiveProposalQueue removes a proposalID from the Inactive Proposal Queue func (keeper Keeper) RemoveFromInactiveProposalQueue(ctx sdk.Context, proposalID uint64, endTime time.Time) { store := ctx.KVStore(keeper.storeKey) store.Delete(types.InactiveProposalQueueKey(proposalID, endTime)) } // Iterators // IterateProposals iterates over the all the proposals and performs a callback function func (keeper Keeper) IterateProposals(ctx sdk.Context, cb func(proposal types.Proposal) (stop bool)) { store := ctx.KVStore(keeper.storeKey) iterator := sdk.KVStorePrefixIterator(store, types.ProposalsKeyPrefix) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var proposal types.Proposal keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &proposal) if cb(proposal) { break } } } // IterateActiveProposalsQueue iterates over the proposals in the active proposal queue // and performs a callback function func (keeper Keeper) IterateActiveProposalsQueue(ctx sdk.Context, endTime time.Time, cb func(proposal types.Proposal) (stop bool)) { iterator := keeper.ActiveProposalQueueIterator(ctx, endTime) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { proposalID, _ := types.SplitActiveProposalQueueKey(iterator.Key()) proposal, found := keeper.GetProposal(ctx, proposalID) if !found { panic(fmt.Sprintf("proposal %d does not exist", proposalID)) } if cb(proposal) { break } } } // IterateInactiveProposalsQueue iterates over the proposals in the inactive proposal queue // and performs a callback function func (keeper Keeper) IterateInactiveProposalsQueue(ctx sdk.Context, endTime time.Time, cb func(proposal types.Proposal) (stop bool)) { iterator := keeper.InactiveProposalQueueIterator(ctx, endTime) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { proposalID, _ := types.SplitInactiveProposalQueueKey(iterator.Key()) proposal, found := keeper.GetProposal(ctx, proposalID) if !found { panic(fmt.Sprintf("proposal %d does not exist", proposalID)) } if cb(proposal) { break } } } // IterateAllDeposits iterates over the all the stored deposits and performs a callback function func (keeper Keeper) IterateAllDeposits(ctx sdk.Context, cb func(deposit types.Deposit) (stop bool)) { store := ctx.KVStore(keeper.storeKey) iterator := sdk.KVStorePrefixIterator(store, types.DepositsKeyPrefix) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var deposit types.Deposit keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &deposit) if cb(deposit) { break } } } // IterateDeposits iterates over the all the proposals deposits and performs a callback function func (keeper Keeper) IterateDeposits(ctx sdk.Context, proposalID uint64, cb func(deposit types.Deposit) (stop bool)) { iterator := keeper.GetDepositsIterator(ctx, proposalID) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var deposit types.Deposit keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &deposit) if cb(deposit) { break } } } // IterateAllVotes iterates over the all the stored votes and performs a callback function func (keeper Keeper) IterateAllVotes(ctx sdk.Context, cb func(vote types.Vote) (stop bool)) { store := ctx.KVStore(keeper.storeKey) iterator := sdk.KVStorePrefixIterator(store, types.VotesKeyPrefix) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var vote types.Vote keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &vote) if cb(vote) { break } } } // IterateVotes iterates over the all the proposals votes and performs a callback function func (keeper Keeper) IterateVotes(ctx sdk.Context, proposalID uint64, cb func(vote types.Vote) (stop bool)) { iterator := keeper.GetVotesIterator(ctx, proposalID) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { var vote types.Vote keeper.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &vote) if cb(vote) { break } } } // ActiveProposalQueueIterator returns an sdk.Iterator for all the proposals in the Active Queue that expire by endTime func (keeper Keeper) ActiveProposalQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { store := ctx.KVStore(keeper.storeKey) return store.Iterator(ActiveProposalQueuePrefix, sdk.PrefixEndBytes(types.ActiveProposalByTimeKey(endTime))) } // InactiveProposalQueueIterator returns an sdk.Iterator for all the proposals in the Inactive Queue that expire by endTime func (keeper Keeper) InactiveProposalQueueIterator(ctx sdk.Context, endTime time.Time) sdk.Iterator { store := ctx.KVStore(keeper.storeKey) return store.Iterator(InactiveProposalQueuePrefix, sdk.PrefixEndBytes(types.InactiveProposalByTimeKey(endTime))) }