274 lines
9.4 KiB
Go
274 lines
9.4 KiB
Go
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/tendermint/tendermint/crypto"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
)
|
|
|
|
// special governance addresses
|
|
var (
|
|
// TODO: Find another way to implement this without using accounts, or find a cleaner way to implement it using accounts.
|
|
DepositedCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govDepositedCoins")))
|
|
BurnedDepositCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins")))
|
|
)
|
|
|
|
// 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 reference to the CoinKeeper to modify balances
|
|
ck BankKeeper
|
|
|
|
// 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,
|
|
ck BankKeeper, sk StakingKeeper, codespace sdk.CodespaceType, rtr Router,
|
|
) Keeper {
|
|
|
|
// 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()),
|
|
ck: ck,
|
|
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))
|
|
}
|
|
|
|
// 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)))
|
|
}
|