2018-06-21 17:19:14 -07:00
|
|
|
package gov
|
|
|
|
|
|
|
|
import (
|
2018-11-06 23:33:18 -08:00
|
|
|
"time"
|
|
|
|
|
2018-09-13 11:17:32 -07:00
|
|
|
codec "github.com/cosmos/cosmos-sdk/codec"
|
2018-06-21 17:19:14 -07:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2018-07-26 18:24:41 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/params"
|
2018-11-06 23:33:18 -08:00
|
|
|
|
|
|
|
"github.com/tendermint/tendermint/crypto"
|
2018-07-26 18:24:41 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2019-02-08 18:33:06 -08:00
|
|
|
// ModuleKey is the name of the module
|
|
|
|
ModuleName = "gov"
|
|
|
|
|
2018-12-19 11:58:30 -08:00
|
|
|
// StoreKey is the store key string for gov
|
2019-02-08 18:33:06 -08:00
|
|
|
StoreKey = ModuleName
|
2018-12-19 11:58:30 -08:00
|
|
|
|
|
|
|
// RouterKey is the message route for gov
|
2019-02-08 18:33:06 -08:00
|
|
|
RouterKey = ModuleName
|
2018-12-19 11:58:30 -08:00
|
|
|
|
|
|
|
// QuerierRoute is the querier route for gov
|
2019-02-08 18:33:06 -08:00
|
|
|
QuerierRoute = ModuleName
|
2018-12-19 11:58:30 -08:00
|
|
|
|
|
|
|
// Parameter store default namestore
|
2019-02-08 18:33:06 -08:00
|
|
|
DefaultParamspace = ModuleName
|
2018-08-31 02:03:43 -07:00
|
|
|
)
|
|
|
|
|
2018-09-17 08:28:13 -07:00
|
|
|
// Parameter store key
|
2018-09-27 11:52:29 -07:00
|
|
|
var (
|
2018-11-06 23:33:18 -08:00
|
|
|
ParamStoreKeyDepositParams = []byte("depositparams")
|
|
|
|
ParamStoreKeyVotingParams = []byte("votingparams")
|
|
|
|
ParamStoreKeyTallyParams = []byte("tallyparams")
|
|
|
|
|
2019-02-08 18:33:06 -08:00
|
|
|
// TODO: Find another way to implement this without using accounts, or find a cleaner way to implement it using accounts.
|
2018-11-06 23:33:18 -08:00
|
|
|
DepositedCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govDepositedCoins")))
|
|
|
|
BurnedDepositCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins")))
|
2018-06-21 17:19:14 -07:00
|
|
|
)
|
|
|
|
|
2019-02-04 18:13:04 -08:00
|
|
|
// Key declaration for parameters
|
|
|
|
func ParamKeyTable() params.KeyTable {
|
|
|
|
return params.NewKeyTable(
|
2018-11-06 23:33:18 -08:00
|
|
|
ParamStoreKeyDepositParams, DepositParams{},
|
|
|
|
ParamStoreKeyVotingParams, VotingParams{},
|
|
|
|
ParamStoreKeyTallyParams, TallyParams{},
|
2018-10-06 08:32:41 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2018-06-21 17:19:14 -07:00
|
|
|
// Governance Keeper
|
|
|
|
type Keeper struct {
|
2018-08-31 02:03:43 -07:00
|
|
|
// The reference to the Param Keeper to get and set Global Params
|
2018-10-06 06:50:58 -07:00
|
|
|
paramsKeeper params.Keeper
|
2018-08-31 02:03:43 -07:00
|
|
|
|
|
|
|
// The reference to the Paramstore to get and set gov specific params
|
2018-10-10 13:01:30 -07:00
|
|
|
paramSpace params.Subspace
|
2018-07-26 18:24:41 -07:00
|
|
|
|
2018-06-21 17:19:14 -07:00
|
|
|
// The reference to the CoinKeeper to modify balances
|
2019-02-13 15:01:50 -08:00
|
|
|
ck BankKeeper
|
2018-06-21 17:19:14 -07:00
|
|
|
|
|
|
|
// The ValidatorSet to get information about validators
|
|
|
|
vs sdk.ValidatorSet
|
|
|
|
|
|
|
|
// The reference to the DelegationSet to get information about delegators
|
|
|
|
ds sdk.DelegationSet
|
|
|
|
|
|
|
|
// The (unexposed) keys used to access the stores from the Context.
|
|
|
|
storeKey sdk.StoreKey
|
|
|
|
|
2018-09-13 11:17:32 -07:00
|
|
|
// The codec codec for binary encoding/decoding.
|
|
|
|
cdc *codec.Codec
|
2018-06-21 17:19:14 -07:00
|
|
|
|
2018-09-18 10:16:51 -07:00
|
|
|
// Reserved codespace
|
|
|
|
codespace sdk.CodespaceType
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-09-24 18:42:51 -07:00
|
|
|
// 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.
|
2019-02-13 15:01:50 -08:00
|
|
|
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramsKeeper params.Keeper,
|
|
|
|
paramSpace params.Subspace, ck BankKeeper, ds sdk.DelegationSet, codespace sdk.CodespaceType) Keeper {
|
|
|
|
|
2018-06-21 17:19:14 -07:00
|
|
|
return Keeper{
|
2018-10-06 06:50:58 -07:00
|
|
|
storeKey: key,
|
|
|
|
paramsKeeper: paramsKeeper,
|
2019-02-04 18:13:04 -08:00
|
|
|
paramSpace: paramSpace.WithKeyTable(ParamKeyTable()),
|
2018-10-06 06:50:58 -07:00
|
|
|
ck: ck,
|
|
|
|
ds: ds,
|
|
|
|
vs: ds.GetValidatorSet(),
|
|
|
|
cdc: cdc,
|
|
|
|
codespace: codespace,
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Proposals
|
|
|
|
|
|
|
|
// Creates a NewProposal
|
2018-07-10 17:59:07 -07:00
|
|
|
func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description string, proposalType ProposalKind) Proposal {
|
2018-06-21 17:19:14 -07:00
|
|
|
proposalID, err := keeper.getNewProposalID(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
var proposal Proposal = &TextProposal{
|
2019-01-10 07:02:55 -08:00
|
|
|
ProposalID: proposalID,
|
|
|
|
Title: title,
|
|
|
|
Description: description,
|
|
|
|
ProposalType: proposalType,
|
|
|
|
Status: StatusDepositPeriod,
|
|
|
|
FinalTallyResult: EmptyTallyResult(),
|
|
|
|
TotalDeposit: sdk.Coins{},
|
|
|
|
SubmitTime: ctx.BlockHeader().Time,
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
2018-11-06 23:33:18 -08:00
|
|
|
|
|
|
|
depositPeriod := keeper.GetDepositParams(ctx).MaxDepositPeriod
|
|
|
|
proposal.SetDepositEndTime(proposal.GetSubmitTime().Add(depositPeriod))
|
|
|
|
|
2018-06-21 17:19:14 -07:00
|
|
|
keeper.SetProposal(ctx, proposal)
|
2018-11-06 23:33:18 -08:00
|
|
|
keeper.InsertInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposalID)
|
2018-06-21 17:19:14 -07:00
|
|
|
return proposal
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get Proposal from store by ProposalID
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) Proposal {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
bz := store.Get(KeyProposal(proposalID))
|
|
|
|
if bz == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
var proposal Proposal
|
2018-11-04 18:28:38 -08:00
|
|
|
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposal)
|
2018-06-21 17:19:14 -07:00
|
|
|
return proposal
|
|
|
|
}
|
|
|
|
|
2018-10-20 23:22:48 -07:00
|
|
|
// Implements sdk.AccountKeeper.
|
2018-06-21 17:19:14 -07:00
|
|
|
func (keeper Keeper) SetProposal(ctx sdk.Context, proposal Proposal) {
|
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
2018-11-04 18:28:38 -08:00
|
|
|
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposal)
|
2018-06-21 17:19:14 -07:00
|
|
|
store.Set(KeyProposal(proposal.GetProposalID()), bz)
|
|
|
|
}
|
|
|
|
|
2018-10-20 23:22:48 -07:00
|
|
|
// Implements sdk.AccountKeeper.
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposalID uint64) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
2018-11-06 23:33:18 -08:00
|
|
|
proposal := keeper.GetProposal(ctx, proposalID)
|
|
|
|
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposalID)
|
|
|
|
keeper.RemoveFromActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposalID)
|
|
|
|
store.Delete(KeyProposal(proposalID))
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-08-03 12:55:00 -07:00
|
|
|
// Get Proposal from store by ProposalID
|
2019-02-08 18:33:06 -08:00
|
|
|
// voterAddr will filter proposals by whether or not that address has voted on them
|
|
|
|
// depositorAddr will filter proposals by whether or not that address has deposited to them
|
|
|
|
// status will filter proposals by status
|
|
|
|
// numLatest will fetch a specified number of the most recent proposals, or 0 for all proposals
|
2018-11-21 15:53:33 -08:00
|
|
|
func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddress, depositorAddr sdk.AccAddress, status ProposalStatus, numLatest uint64) []Proposal {
|
2018-08-03 12:55:00 -07:00
|
|
|
|
|
|
|
maxProposalID, err := keeper.peekCurrentProposalID(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
matchingProposals := []Proposal{}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
if numLatest == 0 {
|
2018-08-03 12:55:00 -07:00
|
|
|
numLatest = maxProposalID
|
|
|
|
}
|
|
|
|
|
|
|
|
for proposalID := maxProposalID - numLatest; proposalID < maxProposalID; proposalID++ {
|
|
|
|
if voterAddr != nil && len(voterAddr) != 0 {
|
|
|
|
_, found := keeper.GetVote(ctx, proposalID, voterAddr)
|
|
|
|
if !found {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-21 15:53:33 -08:00
|
|
|
if depositorAddr != nil && len(depositorAddr) != 0 {
|
|
|
|
_, found := keeper.GetDeposit(ctx, proposalID, depositorAddr)
|
2018-08-03 12:55:00 -07:00
|
|
|
if !found {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
proposal := keeper.GetProposal(ctx, proposalID)
|
|
|
|
if proposal == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if validProposalStatus(status) {
|
|
|
|
if proposal.GetStatus() != status {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
matchingProposals = append(matchingProposals, proposal)
|
|
|
|
}
|
|
|
|
return matchingProposals
|
|
|
|
}
|
|
|
|
|
2019-02-08 18:33:06 -08:00
|
|
|
// Set the initial proposal ID
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) setInitialProposalID(ctx sdk.Context, proposalID uint64) sdk.Error {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
bz := store.Get(KeyNextProposalID)
|
|
|
|
if bz != nil {
|
2018-09-18 10:16:51 -07:00
|
|
|
return ErrInvalidGenesis(keeper.codespace, "Initial ProposalID already set")
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
2018-11-04 18:28:38 -08:00
|
|
|
bz = keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID)
|
2018-06-21 17:19:14 -07:00
|
|
|
store.Set(KeyNextProposalID, bz)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-08-16 08:36:15 -07:00
|
|
|
// Get the last used proposal ID
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) GetLastProposalID(ctx sdk.Context) (proposalID uint64) {
|
2018-08-22 00:17:37 -07:00
|
|
|
proposalID, err := keeper.peekCurrentProposalID(ctx)
|
|
|
|
if err != nil {
|
2018-08-16 08:36:15 -07:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
proposalID--
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-08-03 12:55:00 -07:00
|
|
|
// Gets the next available ProposalID and increments it
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) getNewProposalID(ctx sdk.Context) (proposalID uint64, err sdk.Error) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
bz := store.Get(KeyNextProposalID)
|
|
|
|
if bz == nil {
|
2018-11-06 23:33:18 -08:00
|
|
|
return 0, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set")
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
2018-11-04 18:28:38 -08:00
|
|
|
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
|
|
|
|
bz = keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID + 1)
|
2018-08-03 12:55:00 -07:00
|
|
|
store.Set(KeyNextProposalID, bz)
|
|
|
|
return proposalID, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Peeks the next available ProposalID without incrementing it
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID uint64, err sdk.Error) {
|
2018-08-03 12:55:00 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
bz := store.Get(KeyNextProposalID)
|
|
|
|
if bz == nil {
|
2018-11-06 23:33:18 -08:00
|
|
|
return 0, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set")
|
2018-08-03 12:55:00 -07:00
|
|
|
}
|
2018-11-04 18:28:38 -08:00
|
|
|
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
|
2018-06-21 17:19:14 -07:00
|
|
|
return proposalID, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
|
2018-09-20 07:53:52 -07:00
|
|
|
proposal.SetVotingStartTime(ctx.BlockHeader().Time)
|
2018-11-06 23:33:18 -08:00
|
|
|
votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod
|
|
|
|
proposal.SetVotingEndTime(proposal.GetVotingStartTime().Add(votingPeriod))
|
2018-06-21 17:19:14 -07:00
|
|
|
proposal.SetStatus(StatusVotingPeriod)
|
|
|
|
keeper.SetProposal(ctx, proposal)
|
2018-11-06 23:33:18 -08:00
|
|
|
|
|
|
|
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposal.GetProposalID())
|
|
|
|
keeper.InsertActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposal.GetProposalID())
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
// Params
|
2018-06-21 17:19:14 -07:00
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
// 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
|
2018-07-26 18:24:41 -07:00
|
|
|
}
|
2018-07-16 10:08:22 -07:00
|
|
|
|
2018-11-13 15:45:37 -08:00
|
|
|
// Returns the current VotingParams from the global param store
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) GetVotingParams(ctx sdk.Context) VotingParams {
|
|
|
|
var votingParams VotingParams
|
|
|
|
keeper.paramSpace.Get(ctx, ParamStoreKeyVotingParams, &votingParams)
|
|
|
|
return votingParams
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-11-13 15:45:37 -08:00
|
|
|
// Returns the current TallyParam from the global param store
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) GetTallyParams(ctx sdk.Context) TallyParams {
|
|
|
|
var tallyParams TallyParams
|
|
|
|
keeper.paramSpace.Get(ctx, ParamStoreKeyTallyParams, &tallyParams)
|
|
|
|
return tallyParams
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) setDepositParams(ctx sdk.Context, depositParams DepositParams) {
|
|
|
|
keeper.paramSpace.Set(ctx, ParamStoreKeyDepositParams, &depositParams)
|
2018-07-26 18:24:41 -07:00
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) setVotingParams(ctx sdk.Context, votingParams VotingParams) {
|
|
|
|
keeper.paramSpace.Set(ctx, ParamStoreKeyVotingParams, &votingParams)
|
2018-07-26 18:24:41 -07:00
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) setTallyParams(ctx sdk.Context, tallyParams TallyParams) {
|
|
|
|
keeper.paramSpace.Set(ctx, ParamStoreKeyTallyParams, &tallyParams)
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Votes
|
|
|
|
|
|
|
|
// Adds a vote on a specific proposal
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, option VoteOption) sdk.Error {
|
2018-06-21 17:19:14 -07:00
|
|
|
proposal := keeper.GetProposal(ctx, proposalID)
|
|
|
|
if proposal == nil {
|
2018-09-18 10:16:51 -07:00
|
|
|
return ErrUnknownProposal(keeper.codespace, proposalID)
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
if proposal.GetStatus() != StatusVotingPeriod {
|
2018-09-18 10:16:51 -07:00
|
|
|
return ErrInactiveProposal(keeper.codespace, proposalID)
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-07-10 17:59:07 -07:00
|
|
|
if !validVoteOption(option) {
|
2018-09-18 10:16:51 -07:00
|
|
|
return ErrInvalidVote(keeper.codespace, option)
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
vote := Vote{
|
|
|
|
ProposalID: proposalID,
|
|
|
|
Voter: voterAddr,
|
|
|
|
Option: option,
|
|
|
|
}
|
|
|
|
keeper.setVote(ctx, proposalID, voterAddr, vote)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gets the vote of a specific voter on a specific proposal
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) GetVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) (Vote, bool) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
bz := store.Get(KeyVote(proposalID, voterAddr))
|
|
|
|
if bz == nil {
|
|
|
|
return Vote{}, false
|
|
|
|
}
|
|
|
|
var vote Vote
|
2018-11-04 18:28:38 -08:00
|
|
|
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &vote)
|
2018-06-21 17:19:14 -07:00
|
|
|
return vote, true
|
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) setVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, vote Vote) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
2018-11-04 18:28:38 -08:00
|
|
|
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(vote)
|
2018-06-21 17:19:14 -07:00
|
|
|
store.Set(KeyVote(proposalID, voterAddr), bz)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Gets all the votes on a specific proposal
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) GetVotes(ctx sdk.Context, proposalID uint64) sdk.Iterator {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
return sdk.KVStorePrefixIterator(store, KeyVotesSubspace(proposalID))
|
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) deleteVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
store.Delete(KeyVote(proposalID, voterAddr))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deposits
|
|
|
|
|
2018-11-21 15:53:33 -08:00
|
|
|
// Gets the deposit of a specific depositor on a specific proposal
|
|
|
|
func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress) (Deposit, bool) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
2018-11-21 15:53:33 -08:00
|
|
|
bz := store.Get(KeyDeposit(proposalID, depositorAddr))
|
2018-06-21 17:19:14 -07:00
|
|
|
if bz == nil {
|
|
|
|
return Deposit{}, false
|
|
|
|
}
|
|
|
|
var deposit Deposit
|
2018-11-04 18:28:38 -08:00
|
|
|
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &deposit)
|
2018-06-21 17:19:14 -07:00
|
|
|
return deposit, true
|
|
|
|
}
|
|
|
|
|
2018-11-21 15:53:33 -08:00
|
|
|
func (keeper Keeper) setDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, deposit Deposit) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
2018-11-04 18:28:38 -08:00
|
|
|
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(deposit)
|
2018-11-21 15:53:33 -08:00
|
|
|
store.Set(KeyDeposit(proposalID, depositorAddr), bz)
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-11-21 15:53:33 -08:00
|
|
|
// Adds or updates a deposit of a specific depositor on a specific proposal
|
2018-06-21 17:19:14 -07:00
|
|
|
// Activates voting period when appropriate
|
2018-11-21 15:53:33 -08:00
|
|
|
func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositorAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) {
|
2018-06-21 17:19:14 -07:00
|
|
|
// Checks to see if proposal exists
|
|
|
|
proposal := keeper.GetProposal(ctx, proposalID)
|
|
|
|
if proposal == nil {
|
2018-09-18 10:16:51 -07:00
|
|
|
return ErrUnknownProposal(keeper.codespace, proposalID), false
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check if proposal is still depositable
|
|
|
|
if (proposal.GetStatus() != StatusDepositPeriod) && (proposal.GetStatus() != StatusVotingPeriod) {
|
2018-09-18 10:16:51 -07:00
|
|
|
return ErrAlreadyFinishedProposal(keeper.codespace, proposalID), false
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-11-21 15:53:33 -08:00
|
|
|
// Send coins from depositor's account to DepositedCoinsAccAddr account
|
2019-02-08 18:33:06 -08:00
|
|
|
// TODO: Don't use an account for this purpose; it's clumsy and prone to misuse.
|
2018-11-21 15:53:33 -08:00
|
|
|
_, err := keeper.ck.SendCoins(ctx, depositorAddr, DepositedCoinsAccAddr, depositAmount)
|
2018-06-21 17:19:14 -07:00
|
|
|
if err != nil {
|
|
|
|
return err, false
|
|
|
|
}
|
|
|
|
|
2019-02-08 18:33:06 -08:00
|
|
|
// Update proposal
|
2019-02-21 09:35:55 -08:00
|
|
|
proposal.SetTotalDeposit(proposal.GetTotalDeposit().Add(depositAmount))
|
2018-06-21 17:19:14 -07:00
|
|
|
keeper.SetProposal(ctx, proposal)
|
|
|
|
|
2019-02-08 18:33:06 -08:00
|
|
|
// Check if deposit has provided sufficient total funds to transition the proposal into the voting period
|
2018-06-21 17:19:14 -07:00
|
|
|
activatedVotingPeriod := false
|
2018-11-07 00:14:48 -08:00
|
|
|
if proposal.GetStatus() == StatusDepositPeriod && proposal.GetTotalDeposit().IsAllGTE(keeper.GetDepositParams(ctx).MinDeposit) {
|
2018-06-21 17:19:14 -07:00
|
|
|
keeper.activateVotingPeriod(ctx, proposal)
|
|
|
|
activatedVotingPeriod = true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add or update deposit object
|
2018-11-21 15:53:33 -08:00
|
|
|
currDeposit, found := keeper.GetDeposit(ctx, proposalID, depositorAddr)
|
2018-06-21 17:19:14 -07:00
|
|
|
if !found {
|
2018-11-21 15:53:33 -08:00
|
|
|
newDeposit := Deposit{depositorAddr, proposalID, depositAmount}
|
|
|
|
keeper.setDeposit(ctx, proposalID, depositorAddr, newDeposit)
|
2018-06-21 17:19:14 -07:00
|
|
|
} else {
|
2019-02-21 09:35:55 -08:00
|
|
|
currDeposit.Amount = currDeposit.Amount.Add(depositAmount)
|
2018-11-21 15:53:33 -08:00
|
|
|
keeper.setDeposit(ctx, proposalID, depositorAddr, currDeposit)
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil, activatedVotingPeriod
|
|
|
|
}
|
|
|
|
|
2019-02-08 18:33:06 -08:00
|
|
|
// Gets all the deposits on a specific proposal as an sdk.Iterator
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) GetDeposits(ctx sdk.Context, proposalID uint64) sdk.Iterator {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
return sdk.KVStorePrefixIterator(store, KeyDepositsSubspace(proposalID))
|
|
|
|
}
|
|
|
|
|
2019-02-08 18:33:06 -08:00
|
|
|
// Refunds and deletes all the deposits on a specific proposal
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
depositsIterator := keeper.GetDeposits(ctx, proposalID)
|
2019-01-25 03:13:17 -08:00
|
|
|
defer depositsIterator.Close()
|
2018-06-21 17:19:14 -07:00
|
|
|
for ; depositsIterator.Valid(); depositsIterator.Next() {
|
|
|
|
deposit := &Deposit{}
|
2018-11-04 18:28:38 -08:00
|
|
|
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit)
|
2018-06-21 17:19:14 -07:00
|
|
|
|
2018-11-21 15:53:33 -08:00
|
|
|
_, err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, deposit.Depositor, deposit.Amount)
|
2018-06-21 17:19:14 -07:00
|
|
|
if err != nil {
|
|
|
|
panic("should not happen")
|
|
|
|
}
|
|
|
|
|
|
|
|
store.Delete(depositsIterator.Key())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deletes all the deposits on a specific proposal without refunding them
|
2018-11-06 23:33:18 -08:00
|
|
|
func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
depositsIterator := keeper.GetDeposits(ctx, proposalID)
|
2019-01-25 03:13:17 -08:00
|
|
|
defer depositsIterator.Close()
|
2018-06-21 17:19:14 -07:00
|
|
|
for ; depositsIterator.Valid(); depositsIterator.Next() {
|
2018-11-06 23:33:18 -08:00
|
|
|
deposit := &Deposit{}
|
|
|
|
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit)
|
|
|
|
|
2019-02-08 18:33:06 -08:00
|
|
|
// TODO: Find a way to do this without using accounts.
|
2018-11-06 23:33:18 -08:00
|
|
|
_, err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, BurnedDepositCoinsAccAddr, deposit.Amount)
|
|
|
|
if err != nil {
|
|
|
|
panic("should not happen")
|
|
|
|
}
|
|
|
|
|
2018-06-21 17:19:14 -07:00
|
|
|
store.Delete(depositsIterator.Key())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ProposalQueues
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
// Returns an 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 {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
2018-11-06 23:33:18 -08:00
|
|
|
return store.Iterator(PrefixActiveProposalQueue, sdk.PrefixEndBytes(PrefixActiveProposalQueueTime(endTime)))
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
// Inserts a ProposalID into the active proposal queue at endTime
|
|
|
|
func (keeper Keeper) InsertActiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
2018-11-06 23:33:18 -08:00
|
|
|
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID)
|
|
|
|
store.Set(KeyActiveProposalQueueProposal(endTime, proposalID), bz)
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
// removes a proposalID from the Active Proposal Queue
|
|
|
|
func (keeper Keeper) RemoveFromActiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
2018-11-06 23:33:18 -08:00
|
|
|
store.Delete(KeyActiveProposalQueueProposal(endTime, proposalID))
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
// Returns an 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 {
|
2018-06-21 17:19:14 -07:00
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
2018-11-06 23:33:18 -08:00
|
|
|
return store.Iterator(PrefixInactiveProposalQueue, sdk.PrefixEndBytes(PrefixInactiveProposalQueueTime(endTime)))
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
// Inserts a ProposalID into the inactive proposal queue at endTime
|
|
|
|
func (keeper Keeper) InsertInactiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
|
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID)
|
|
|
|
store.Set(KeyInactiveProposalQueueProposal(endTime, proposalID), bz)
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|
|
|
|
|
2018-11-06 23:33:18 -08:00
|
|
|
// removes a proposalID from the Inactive Proposal Queue
|
|
|
|
func (keeper Keeper) RemoveFromInactiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
|
|
|
|
store := ctx.KVStore(keeper.storeKey)
|
|
|
|
store.Delete(KeyInactiveProposalQueueProposal(endTime, proposalID))
|
2018-06-21 17:19:14 -07:00
|
|
|
}
|