Switch gov proposal-queues to use iterators (#2638)

* switched gov proposals queue to use iterators
* update gov spec
* update proposal.Equal
* Amino api change
* switched proposalID to uint64
* renamed Gov Procedures to Params
* s/ActiveProposalQueueProposalKey/KeyActiveProposalQueueProposal/g
* numLatestProposals -> Limit
* fixed staking invariant breakage because of gov deposits
* Send deposits to DepositedCoinsAccAddr or BurnedDepositCoinsAccAddr
This commit is contained in:
Sunny Aggarwal 2018-11-06 23:33:18 -08:00 committed by Jae Kwon
parent 10e8e0312e
commit 1d3a04a61c
28 changed files with 488 additions and 519 deletions

8
Gopkg.lock generated
View File

@ -165,13 +165,12 @@
version = "v1.2.0" version = "v1.2.0"
[[projects]] [[projects]]
digest = "1:c0d19ab64b32ce9fe5cf4ddceba78d5bc9807f0016db6b1183599da3dcc24d10" digest = "1:ea40c24cdbacd054a6ae9de03e62c5f252479b96c716375aace5c120d68647c8"
name = "github.com/hashicorp/hcl" name = "github.com/hashicorp/hcl"
packages = [ packages = [
".", ".",
"hcl/ast", "hcl/ast",
"hcl/parser", "hcl/parser",
"hcl/printer",
"hcl/scanner", "hcl/scanner",
"hcl/strconv", "hcl/strconv",
"hcl/token", "hcl/token",
@ -435,7 +434,7 @@
version = "v0.11.1" version = "v0.11.1"
[[projects]] [[projects]]
digest = "1:92d7d1678577fd1a6f3348168cef87880bbc710ef5f4e9a1216f45c56567d734" digest = "1:395820b381043b9d2204e181ddf0f9147397c4a7b8f5dc3162de4cfcddf4589a"
name = "github.com/tendermint/tendermint" name = "github.com/tendermint/tendermint"
packages = [ packages = [
"abci/client", "abci/client",
@ -501,7 +500,8 @@
"version", "version",
] ]
pruneopts = "UT" pruneopts = "UT"
revision = "ebee4377b15f2958b08994485375dd2ee8a649ac" revision = "03e42d2e3866f01a00625f608e3bbfaeb30690de"
version = "v0.26.1-rc0"
[[projects]] [[projects]]
digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666" digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666"

View File

@ -36,7 +36,7 @@
[[override]] [[override]]
name = "github.com/tendermint/tendermint" name = "github.com/tendermint/tendermint"
revision = "ebee4377b15f2958b08994485375dd2ee8a649ac" # TODO replace w/ 0.26.1 version = "v0.26.1-rc0" # TODO replace w/ 0.26.1
## deps without releases: ## deps without releases:
@ -84,4 +84,3 @@
[prune] [prune]
go-tests = true go-tests = true
unused-packages = true unused-packages = true

View File

@ -40,6 +40,7 @@ IMPROVEMENTS
* Gaia CLI (`gaiacli`) * Gaia CLI (`gaiacli`)
* Gaia * Gaia
- #2637 [x/gov] Switched inactive and active proposal queues to an iterator based queue
* SDK * SDK
- \#2573 [x/distribution] add accum invariance - \#2573 [x/distribution] add accum invariance

View File

@ -628,8 +628,8 @@ func TestSubmitProposal(t *testing.T) {
require.Equal(t, uint32(0), resultTx.CheckTx.Code) require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code) require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
var proposalID int64 var proposalID uint64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID) cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
// query proposal // query proposal
proposal := getProposal(t, port, proposalID) proposal := getProposal(t, port, proposalID)
@ -650,8 +650,8 @@ func TestDeposit(t *testing.T) {
require.Equal(t, uint32(0), resultTx.CheckTx.Code) require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code) require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
var proposalID int64 var proposalID uint64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID) cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
// query proposal // query proposal
proposal := getProposal(t, port, proposalID) proposal := getProposal(t, port, proposalID)
@ -684,8 +684,8 @@ func TestVote(t *testing.T) {
require.Equal(t, uint32(0), resultTx.CheckTx.Code) require.Equal(t, uint32(0), resultTx.CheckTx.Code)
require.Equal(t, uint32(0), resultTx.DeliverTx.Code) require.Equal(t, uint32(0), resultTx.DeliverTx.Code)
var proposalID int64 var proposalID uint64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID) cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID)
// query proposal // query proposal
proposal := getProposal(t, port, proposalID) proposal := getProposal(t, port, proposalID)
@ -732,18 +732,18 @@ func TestProposalsQuery(t *testing.T) {
// Addr1 proposes (and deposits) proposals #1 and #2 // Addr1 proposes (and deposits) proposals #1 and #2
resultTx := doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], 5) resultTx := doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], 5)
var proposalID1 int64 var proposalID1 uint64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID1) cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID1)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
resultTx = doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], 5) resultTx = doSubmitProposal(t, port, seeds[0], names[0], passwords[0], addrs[0], 5)
var proposalID2 int64 var proposalID2 uint64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID2) cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID2)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
// Addr2 proposes (and deposits) proposals #3 // Addr2 proposes (and deposits) proposals #3
resultTx = doSubmitProposal(t, port, seeds[1], names[1], passwords[1], addrs[1], 5) resultTx = doSubmitProposal(t, port, seeds[1], names[1], passwords[1], addrs[1], 5)
var proposalID3 int64 var proposalID3 uint64
cdc.UnmarshalBinaryBare(resultTx.DeliverTx.GetData(), &proposalID3) cdc.MustUnmarshalBinaryLengthPrefixed(resultTx.DeliverTx.GetData(), &proposalID3)
tests.WaitForHeight(resultTx.Height+1, port) tests.WaitForHeight(resultTx.Height+1, port)
// Addr2 deposits on proposals #2 & #3 // Addr2 deposits on proposals #2 & #3
@ -1230,7 +1230,7 @@ func getValidatorRedelegations(t *testing.T, port string, validatorAddr sdk.ValA
// ============= Governance Module ================ // ============= Governance Module ================
func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal { func getProposal(t *testing.T, port string, proposalID uint64) gov.Proposal {
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d", proposalID), nil) res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d", proposalID), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
var proposal gov.Proposal var proposal gov.Proposal
@ -1239,7 +1239,7 @@ func getProposal(t *testing.T, port string, proposalID int64) gov.Proposal {
return proposal return proposal
} }
func getDeposits(t *testing.T, port string, proposalID int64) []gov.Deposit { func getDeposits(t *testing.T, port string, proposalID uint64) []gov.Deposit {
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), nil) res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits", proposalID), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
var deposits []gov.Deposit var deposits []gov.Deposit
@ -1248,7 +1248,7 @@ func getDeposits(t *testing.T, port string, proposalID int64) []gov.Deposit {
return deposits return deposits
} }
func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.AccAddress) gov.Deposit { func getDeposit(t *testing.T, port string, proposalID uint64, depositerAddr sdk.AccAddress) gov.Deposit {
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, depositerAddr), nil) res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/deposits/%s", proposalID, depositerAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
var deposit gov.Deposit var deposit gov.Deposit
@ -1257,7 +1257,7 @@ func getDeposit(t *testing.T, port string, proposalID int64, depositerAddr sdk.A
return deposit return deposit
} }
func getVote(t *testing.T, port string, proposalID int64, voterAddr sdk.AccAddress) gov.Vote { func getVote(t *testing.T, port string, proposalID uint64, voterAddr sdk.AccAddress) gov.Vote {
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/votes/%s", proposalID, voterAddr), nil) res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/votes/%s", proposalID, voterAddr), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
var vote gov.Vote var vote gov.Vote
@ -1266,7 +1266,7 @@ func getVote(t *testing.T, port string, proposalID int64, voterAddr sdk.AccAddre
return vote return vote
} }
func getVotes(t *testing.T, port string, proposalID int64) []gov.Vote { func getVotes(t *testing.T, port string, proposalID uint64) []gov.Vote {
res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), nil) res, body := Request(t, port, "GET", fmt.Sprintf("/gov/proposals/%d/votes", proposalID), nil)
require.Equal(t, http.StatusOK, res.StatusCode, body) require.Equal(t, http.StatusOK, res.StatusCode, body)
var votes []gov.Vote var votes []gov.Vote
@ -1358,7 +1358,7 @@ func doSubmitProposal(t *testing.T, port, seed, name, password string, proposerA
return results return results
} }
func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) { func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64, amount int64) (resultTx ctypes.ResultBroadcastTxCommit) {
acc := getAccount(t, port, proposerAddr) acc := getAccount(t, port, proposerAddr)
accnum := acc.GetAccountNumber() accnum := acc.GetAccountNumber()
@ -1388,7 +1388,7 @@ func doDeposit(t *testing.T, port, seed, name, password string, proposerAddr sdk
return results return results
} }
func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID int64) (resultTx ctypes.ResultBroadcastTxCommit) { func doVote(t *testing.T, port, seed, name, password string, proposerAddr sdk.AccAddress, proposalID uint64) (resultTx ctypes.ResultBroadcastTxCommit) {
// get the account to get the sequence // get the account to get the sequence
acc := getAccount(t, port, proposerAddr) acc := getAccount(t, port, proposerAddr)
accnum := acc.GetAccountNumber() accnum := acc.GetAccountNumber()

View File

@ -65,6 +65,20 @@ func ParseInt64OrReturnBadRequest(w http.ResponseWriter, s string) (n int64, ok
return n, true return n, true
} }
// ParseUint64OrReturnBadRequest converts s to a uint64 value.
func ParseUint64OrReturnBadRequest(w http.ResponseWriter, s string) (n uint64, ok bool) {
var err error
n, err = strconv.ParseUint(s, 10, 64)
if err != nil {
err := fmt.Errorf("'%s' is not a valid uint64", s)
WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return n, false
}
return n, true
}
// ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a // ParseFloat64OrReturnBadRequest converts s to a float64 value. It returns a
// default value, defaultIfEmpty, if the string is empty. // default value, defaultIfEmpty, if the string is empty.
func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEmpty float64) (n float64, ok bool) { func ParseFloat64OrReturnBadRequest(w http.ResponseWriter, s string, defaultIfEmpty float64) (n float64, ok bool) {

View File

@ -70,15 +70,15 @@ func appStateFn(r *rand.Rand, accs []simulation.Account) json.RawMessage {
// Random genesis states // Random genesis states
govGenesis := gov.GenesisState{ govGenesis := gov.GenesisState{
StartingProposalID: int64(r.Intn(100)), StartingProposalID: uint64(r.Intn(100)),
DepositProcedure: gov.DepositProcedure{ DepositParams: gov.DepositParams{
MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", int64(r.Intn(1e3)))}, MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", int64(r.Intn(1e3)))},
MaxDepositPeriod: time.Duration(r.Intn(2*172800)) * time.Second, MaxDepositPeriod: time.Duration(r.Intn(2*172800)) * time.Second,
}, },
VotingProcedure: gov.VotingProcedure{ VotingParams: gov.VotingParams{
VotingPeriod: time.Duration(r.Intn(2*172800)) * time.Second, VotingPeriod: time.Duration(r.Intn(2*172800)) * time.Second,
}, },
TallyingProcedure: gov.TallyingProcedure{ TallyParams: gov.TallyParams{
Threshold: sdk.NewDecWithPrec(5, 1), Threshold: sdk.NewDecWithPrec(5, 1),
Veto: sdk.NewDecWithPrec(334, 3), Veto: sdk.NewDecWithPrec(334, 3),
GovernancePenalty: sdk.NewDecWithPrec(1, 2), GovernancePenalty: sdk.NewDecWithPrec(1, 2),
@ -166,7 +166,7 @@ func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
{50, distrsim.SimulateMsgWithdrawDelegatorReward(app.accountKeeper, app.distrKeeper)}, {50, distrsim.SimulateMsgWithdrawDelegatorReward(app.accountKeeper, app.distrKeeper)},
{50, distrsim.SimulateMsgWithdrawValidatorRewardsAll(app.accountKeeper, app.distrKeeper)}, {50, distrsim.SimulateMsgWithdrawValidatorRewardsAll(app.accountKeeper, app.distrKeeper)},
{5, govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, app.stakeKeeper)}, {5, govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, app.stakeKeeper)},
{100, govsim.SimulateMsgDeposit(app.govKeeper, app.stakeKeeper)}, {100, govsim.SimulateMsgDeposit(app.govKeeper)},
{100, stakesim.SimulateMsgCreateValidator(app.accountKeeper, app.stakeKeeper)}, {100, stakesim.SimulateMsgCreateValidator(app.accountKeeper, app.stakeKeeper)},
{5, stakesim.SimulateMsgEditValidator(app.stakeKeeper)}, {5, stakesim.SimulateMsgEditValidator(app.stakeKeeper)},
{100, stakesim.SimulateMsgDelegate(app.accountKeeper, app.stakeKeeper)}, {100, stakesim.SimulateMsgDelegate(app.accountKeeper, app.stakeKeeper)},

View File

@ -5,13 +5,14 @@ package clitest
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/tendermint/tendermint/types"
"io/ioutil" "io/ioutil"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/tendermint/tendermint/types"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
@ -348,7 +349,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64()) require.Equal(t, int64(45), fooAcc.GetCoins().AmountOf("steak").Int64())
proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags)) proposal1 := executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags))
require.Equal(t, int64(1), proposal1.GetProposalID()) require.Equal(t, uint64(1), proposal1.GetProposalID())
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus()) require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "") proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "")
@ -391,7 +392,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags)) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64()) require.Equal(t, int64(35), fooAcc.GetCoins().AmountOf("steak").Int64())
proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags)) proposal1 = executeGetProposal(t, fmt.Sprintf("gaiacli query proposal --proposal-id=1 --output=json %v", flags))
require.Equal(t, int64(1), proposal1.GetProposalID()) require.Equal(t, uint64(1), proposal1.GetProposalID())
require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus()) require.Equal(t, gov.StatusVotingPeriod, proposal1.GetStatus())
voteStr := fmt.Sprintf("gaiacli tx vote %v", flags) voteStr := fmt.Sprintf("gaiacli tx vote %v", flags)
@ -413,12 +414,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
tests.WaitForNextNBlocksTM(2, port) tests.WaitForNextNBlocksTM(2, port)
vote := executeGetVote(t, fmt.Sprintf("gaiacli query vote --proposal-id=1 --voter=%s --output=json %v", fooAddr, flags)) vote := executeGetVote(t, fmt.Sprintf("gaiacli query vote --proposal-id=1 --voter=%s --output=json %v", fooAddr, flags))
require.Equal(t, int64(1), vote.ProposalID) require.Equal(t, uint64(1), vote.ProposalID)
require.Equal(t, gov.OptionYes, vote.Option) require.Equal(t, gov.OptionYes, vote.Option)
votes := executeGetVotes(t, fmt.Sprintf("gaiacli query votes --proposal-id=1 --output=json %v", flags)) votes := executeGetVotes(t, fmt.Sprintf("gaiacli query votes --proposal-id=1 --output=json %v", flags))
require.Len(t, votes, 1) require.Len(t, votes, 1)
require.Equal(t, int64(1), votes[0].ProposalID) require.Equal(t, uint64(1), votes[0].ProposalID)
require.Equal(t, gov.OptionYes, votes[0].Option) require.Equal(t, gov.OptionYes, votes[0].Option)
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --status=DepositPeriod %v", flags), "") proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --status=DepositPeriod %v", flags), "")
@ -438,7 +439,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
executeWrite(t, spStr, app.DefaultKeyPass) executeWrite(t, spStr, app.DefaultKeyPass)
tests.WaitForNextNBlocksTM(2, port) tests.WaitForNextNBlocksTM(2, port)
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --latest=1 %v", flags), "") proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --limit=1 %v", flags), "")
require.Equal(t, " 2 - Apples", proposalsQuery) require.Equal(t, " 2 - Apples", proposalsQuery)
} }

View File

@ -97,9 +97,11 @@ type Proposal struct {
TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit
Deposits []Deposit // List of deposits on the proposal Deposits []Deposit // List of deposits on the proposal
SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included
Submitter sdk.Address // Address of the submitter DepositEndTime time.Time // Time that the DepositPeriod of a proposal would expire
Submitter sdk.AccAddress // Address of the submitter
VotingStartTime time.Time // Time of the block where MinDeposit was reached. time.Time{} if MinDeposit is not reached VotingStartTime time.Time // Time of the block where MinDeposit was reached. time.Time{} if MinDeposit is not reached
VotingEndTime time.Time // Time of the block that the VotingPeriod for a proposal will end.
CurrentStatus ProposalStatus // Current status of the proposal CurrentStatus ProposalStatus // Current status of the proposal
YesVotes sdk.Dec YesVotes sdk.Dec
@ -134,46 +136,26 @@ For pseudocode purposes, here are the two function we will use to read or write
**Store:** **Store:**
* `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the * `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the
`ProposalIDs` of proposals that reached `MinDeposit`. Each round, the oldest `ProposalIDs` of proposals that reached `MinDeposit`. Each `EndBlock`, all the proposals
element of `ProposalProcessingQueue` is checked during `BeginBlock` to see if that have reached the end of their voting period are processed.
`CurrentTime == VotingStartTime + activeProcedure.VotingPeriod`. If it is, To process a finished proposal, the application tallies the votes, compute the votes of
then the application tallies the votes, compute the votes of each validator and checks if every validator in the valdiator set have voted each validator and checks if every validator in the valdiator set have voted.
and, if not, applies `GovernancePenalty`. If the proposal is accepted, deposits are refunded. If the proposal is accepted, deposits are refunded.
After that proposal is ejected from `ProposalProcessingQueue` and the next element of the queue is evaluated.
And the pseudocode for the `ProposalProcessingQueue`: And the pseudocode for the `ProposalProcessingQueue`:
```go ```go
in EndBlock do in EndBlock do
checkProposal() // First call of the recursive function for finishedProposalID in GetAllFinishedProposalIDs(block.Time)
// Recursive function. First call in BeginBlock
func checkProposal()
proposalID = ProposalProcessingQueue.Peek()
if (proposalID == nil)
return
proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key
votingProcedure = load(GlobalParams, 'VotingProcedure')
if (CurrentTime == proposal.VotingStartTime + votingProcedure.VotingPeriod && proposal.CurrentStatus == ProposalStatusActive) validators = Keeper.getAllValidators()
tmpValMap := map(sdk.AccAddress)ValidatorGovInfo
// End of voting period, tally // Initiate mapping at 0. This is the amount of shares of the validator's vote that will be overridden by their delegator's votes
ProposalProcessingQueue.pop()
validators =
Keeper.getAllValidators()
tmpValMap := map(sdk.Address)ValidatorGovInfo
// Initiate mapping at 0. Validators that remain at 0 at the end of tally will be punished
for each validator in validators for each validator in validators
tmpValMap(validator).Minus = 0 tmpValMap(validator.OperatorAddr).Minus = 0
// Tally // Tally
voterIterator = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal voterIterator = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal
@ -212,5 +194,4 @@ And the pseudocode for the `ProposalProcessingQueue`:
proposal.CurrentStatus = ProposalStatusRejected proposal.CurrentStatus = ProposalStatusRejected
store(Governance, <proposalID|'proposal'>, proposal) store(Governance, <proposalID|'proposal'>, proposal)
checkProposal()
``` ```

View File

@ -46,6 +46,8 @@ upon receiving txGovSubmitProposal from sender do
sender.AtomBalance -= initialDeposit.Atoms sender.AtomBalance -= initialDeposit.Atoms
depositProcedure = load(GlobalParams, 'DepositProcedure')
proposalID = generate new proposalID proposalID = generate new proposalID
proposal = NewProposal() proposal = NewProposal()
@ -53,28 +55,16 @@ upon receiving txGovSubmitProposal from sender do
proposal.Description = txGovSubmitProposal.Description proposal.Description = txGovSubmitProposal.Description
proposal.Type = txGovSubmitProposal.Type proposal.Type = txGovSubmitProposal.Type
proposal.TotalDeposit = initialDeposit proposal.TotalDeposit = initialDeposit
proposal.SubmitBlock = CurrentBlock proposal.SubmitTime = <CurrentTime>
proposal.DepositEndTime = <CurrentTime>.Add(depositProcedure.MaxDepositPeriod)
proposal.Deposits.append({initialDeposit, sender}) proposal.Deposits.append({initialDeposit, sender})
proposal.Submitter = sender proposal.Submitter = sender
proposal.YesVotes = 0 proposal.YesVotes = 0
proposal.NoVotes = 0 proposal.NoVotes = 0
proposal.NoWithVetoVotes = 0 proposal.NoWithVetoVotes = 0
proposal.AbstainVotes = 0 proposal.AbstainVotes = 0
depositProcedure = load(GlobalParams, 'DepositProcedure')
if (initialDeposit < depositProcedure.MinDeposit)
// MinDeposit is not reached
proposal.CurrentStatus = ProposalStatusOpen proposal.CurrentStatus = ProposalStatusOpen
else
// MinDeposit is reached
proposal.CurrentStatus = ProposalStatusActive
proposal.VotingStartBlock = CurrentBlock
ProposalProcessingQueue.push(proposalID)
store(Proposals, <proposalID|'proposal'>, proposal) // Store proposal in Proposals mapping store(Proposals, <proposalID|'proposal'>, proposal) // Store proposal in Proposals mapping
return proposalID return proposalID
``` ```

View File

@ -1,6 +1,7 @@
package types package types
import ( import (
"encoding/binary"
"encoding/json" "encoding/json"
"time" "time"
@ -36,6 +37,13 @@ func MustSortJSON(toSortJSON []byte) []byte {
return js return js
} }
// Uint64ToBigEndian - marshals uint64 to a bigendian byte slice so it can be sorted
func Uint64ToBigEndian(i uint64) []byte {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, i)
return b
}
// Slight modification of the RFC3339Nano but it right pads all zeros and drops the time zone info // Slight modification of the RFC3339Nano but it right pads all zeros and drops the time zone info
const SortableTimeFormat = "2006-01-02T15:04:05.000000000" const SortableTimeFormat = "2006-01-02T15:04:05.000000000"

View File

@ -30,7 +30,7 @@ const (
flagOption = "option" flagOption = "option"
flagDepositer = "depositer" flagDepositer = "depositer"
flagStatus = "status" flagStatus = "status"
flagLatestProposalIDs = "latest" flagNumLimit = "limit"
flagProposal = "proposal" flagProposal = "proposal"
) )
@ -170,7 +170,7 @@ func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
return err return err
} }
proposalID := viper.GetInt64(flagProposalID) proposalID := uint64(viper.GetInt64(flagProposalID))
amount, err := sdk.ParseCoins(viper.GetString(flagDeposit)) amount, err := sdk.ParseCoins(viper.GetString(flagDeposit))
if err != nil { if err != nil {
@ -215,7 +215,7 @@ func GetCmdVote(cdc *codec.Codec) *cobra.Command {
return err return err
} }
proposalID := viper.GetInt64(flagProposalID) proposalID := uint64(viper.GetInt64(flagProposalID))
option := viper.GetString(flagOption) option := viper.GetString(flagOption)
byteVoteOption, err := gov.VoteOptionFromString(client.NormalizeVoteOption(option)) byteVoteOption, err := gov.VoteOptionFromString(client.NormalizeVoteOption(option))
@ -256,7 +256,7 @@ func GetCmdQueryProposal(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query details of a single proposal", Short: "Query details of a single proposal",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID) proposalID := uint64(viper.GetInt64(flagProposalID))
params := gov.QueryProposalParams{ params := gov.QueryProposalParams{
ProposalID: proposalID, ProposalID: proposalID,
@ -291,10 +291,10 @@ func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command {
bechDepositerAddr := viper.GetString(flagDepositer) bechDepositerAddr := viper.GetString(flagDepositer)
bechVoterAddr := viper.GetString(flagVoter) bechVoterAddr := viper.GetString(flagVoter)
strProposalStatus := viper.GetString(flagStatus) strProposalStatus := viper.GetString(flagStatus)
latestProposalsIDs := viper.GetInt64(flagLatestProposalIDs) numLimit := uint64(viper.GetInt64(flagNumLimit))
params := gov.QueryProposalsParams{ params := gov.QueryProposalsParams{
NumLatestProposals: latestProposalsIDs, Limit: numLimit,
} }
if len(bechDepositerAddr) != 0 { if len(bechDepositerAddr) != 0 {
@ -352,7 +352,7 @@ func GetCmdQueryProposals(queryRoute string, cdc *codec.Codec) *cobra.Command {
}, },
} }
cmd.Flags().String(flagLatestProposalIDs, "", "(optional) limit to latest [number] proposals. Defaults to all proposals") cmd.Flags().String(flagNumLimit, "", "(optional) limit to latest [number] proposals. Defaults to all proposals")
cmd.Flags().String(flagDepositer, "", "(optional) filter by proposals deposited on by depositer") cmd.Flags().String(flagDepositer, "", "(optional) filter by proposals deposited on by depositer")
cmd.Flags().String(flagVoter, "", "(optional) filter by proposals voted on by voted") cmd.Flags().String(flagVoter, "", "(optional) filter by proposals voted on by voted")
cmd.Flags().String(flagStatus, "", "(optional) filter proposals by proposal status, status: deposit_period/voting_period/passed/rejected") cmd.Flags().String(flagStatus, "", "(optional) filter proposals by proposal status, status: deposit_period/voting_period/passed/rejected")
@ -368,7 +368,7 @@ func GetCmdQueryVote(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query details of a single vote", Short: "Query details of a single vote",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID) proposalID := uint64(viper.GetInt64(flagProposalID))
voterAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagVoter)) voterAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagVoter))
if err != nil { if err != nil {
@ -407,7 +407,7 @@ func GetCmdQueryVotes(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query votes on a proposal", Short: "Query votes on a proposal",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID) proposalID := uint64(viper.GetInt64(flagProposalID))
params := gov.QueryVotesParams{ params := gov.QueryVotesParams{
ProposalID: proposalID, ProposalID: proposalID,
@ -440,7 +440,7 @@ func GetCmdQueryDeposit(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query details of a deposit", Short: "Query details of a deposit",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID) proposalID := uint64(viper.GetInt64(flagProposalID))
depositerAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagDepositer)) depositerAddr, err := sdk.AccAddressFromBech32(viper.GetString(flagDepositer))
if err != nil { if err != nil {
@ -479,7 +479,7 @@ func GetCmdQueryDeposits(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Query deposits on a proposal", Short: "Query deposits on a proposal",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID) proposalID := uint64(viper.GetInt64(flagProposalID))
params := gov.QueryDepositsParams{ params := gov.QueryDepositsParams{
ProposalID: proposalID, ProposalID: proposalID,
@ -511,7 +511,7 @@ func GetCmdQueryTally(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Get the tally of a proposal vote", Short: "Get the tally of a proposal vote",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
proposalID := viper.GetInt64(flagProposalID) proposalID := uint64(viper.GetInt64(flagProposalID))
params := gov.QueryTallyParams{ params := gov.QueryTallyParams{
ProposalID: proposalID, ProposalID: proposalID,

View File

@ -22,7 +22,7 @@ const (
RestDepositer = "depositer" RestDepositer = "depositer"
RestVoter = "voter" RestVoter = "voter"
RestProposalStatus = "status" RestProposalStatus = "status"
RestNumLatest = "latest" RestNumLimit = "limit"
storeName = "gov" storeName = "gov"
) )
@ -104,7 +104,7 @@ func depositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerF
return return
} }
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID) proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok { if !ok {
return return
} }
@ -143,7 +143,7 @@ func voteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.HandlerFunc
return return
} }
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID) proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok { if !ok {
return return
} }
@ -188,7 +188,7 @@ func queryProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha
return return
} }
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID) proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok { if !ok {
return return
} }
@ -218,7 +218,7 @@ func queryDepositsHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Ha
vars := mux.Vars(r) vars := mux.Vars(r)
strProposalID := vars[RestProposalID] strProposalID := vars[RestProposalID]
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID) proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok { if !ok {
return return
} }
@ -255,7 +255,7 @@ func queryDepositHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Han
return return
} }
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID) proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok { if !ok {
return return
} }
@ -319,7 +319,7 @@ func queryVoteHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext) http.Handle
return return
} }
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID) proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok { if !ok {
return return
} }
@ -386,7 +386,7 @@ func queryVotesOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext)
return return
} }
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID) proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok { if !ok {
return return
} }
@ -416,7 +416,7 @@ func queryProposalsWithParameterFn(cdc *codec.Codec, cliCtx context.CLIContext)
bechVoterAddr := r.URL.Query().Get(RestVoter) bechVoterAddr := r.URL.Query().Get(RestVoter)
bechDepositerAddr := r.URL.Query().Get(RestDepositer) bechDepositerAddr := r.URL.Query().Get(RestDepositer)
strProposalStatus := r.URL.Query().Get(RestProposalStatus) strProposalStatus := r.URL.Query().Get(RestProposalStatus)
strNumLatest := r.URL.Query().Get(RestNumLatest) strNumLimit := r.URL.Query().Get(RestNumLimit)
params := gov.QueryProposalsParams{} params := gov.QueryProposalsParams{}
@ -446,12 +446,12 @@ func queryProposalsWithParameterFn(cdc *codec.Codec, cliCtx context.CLIContext)
} }
params.ProposalStatus = proposalStatus params.ProposalStatus = proposalStatus
} }
if len(strNumLatest) != 0 { if len(strNumLimit) != 0 {
numLatest, ok := utils.ParseInt64OrReturnBadRequest(w, strNumLatest) numLimit, ok := utils.ParseUint64OrReturnBadRequest(w, strNumLimit)
if !ok { if !ok {
return return
} }
params.NumLatestProposals = numLatest params.Limit = numLimit
} }
bz, err := cdc.MarshalJSON(params) bz, err := cdc.MarshalJSON(params)
@ -484,7 +484,7 @@ func queryTallyOnProposalHandlerFn(cdc *codec.Codec, cliCtx context.CLIContext)
return return
} }
proposalID, ok := utils.ParseInt64OrReturnBadRequest(w, strProposalID) proposalID, ok := utils.ParseUint64OrReturnBadRequest(w, strProposalID)
if !ok { if !ok {
return return
} }

View File

@ -11,7 +11,7 @@ import (
// Vote // Vote
type Vote struct { type Vote struct {
Voter sdk.AccAddress `json:"voter"` // address of the voter Voter sdk.AccAddress `json:"voter"` // address of the voter
ProposalID int64 `json:"proposal_id"` // proposalID of the proposal ProposalID uint64 `json:"proposal_id"` // proposalID of the proposal
Option VoteOption `json:"option"` // option from OptionSet chosen by the voter Option VoteOption `json:"option"` // option from OptionSet chosen by the voter
} }
@ -29,7 +29,7 @@ func (voteA Vote) Empty() bool {
// Deposit // Deposit
type Deposit struct { type Deposit struct {
Depositer sdk.AccAddress `json:"depositer"` // Address of the depositer Depositer sdk.AccAddress `json:"depositer"` // Address of the depositer
ProposalID int64 `json:"proposal_id"` // proposalID of the proposal ProposalID uint64 `json:"proposal_id"` // proposalID of the proposal
Amount sdk.Coins `json:"amount"` // Deposit amount Amount sdk.Coins `json:"amount"` // Deposit amount
} }

View File

@ -16,35 +16,40 @@ func TestTickExpiredDepositPeriod(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
govHandler := NewHandler(keeper) govHandler := NewHandler(keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)}) newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res := govHandler(ctx, newProposalMsg) res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK()) require.True(t, res.IsOK())
EndBlocker(ctx, keeper) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, inactiveQueue.Valid())
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) inactiveQueue.Close()
newHeader := ctx.BlockHeader() newHeader := ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
ctx = ctx.WithBlockHeader(newHeader) ctx = ctx.WithBlockHeader(newHeader)
EndBlocker(ctx, keeper) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, inactiveQueue.Valid())
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) inactiveQueue.Close()
newHeader = ctx.BlockHeader() newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod) newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositParams(ctx).MaxDepositPeriod)
ctx = ctx.WithBlockHeader(newHeader) ctx = ctx.WithBlockHeader(newHeader)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.True(t, inactiveQueue.Valid())
inactiveQueue.Close()
EndBlocker(ctx, keeper) EndBlocker(ctx, keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
} }
func TestTickMultipleExpiredDepositPeriod(t *testing.T) { func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
@ -53,49 +58,54 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
govHandler := NewHandler(keeper) govHandler := NewHandler(keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)}) newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res := govHandler(ctx, newProposalMsg) res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK()) require.True(t, res.IsOK())
EndBlocker(ctx, keeper) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, inactiveQueue.Valid())
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) inactiveQueue.Close()
newHeader := ctx.BlockHeader() newHeader := ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(2) * time.Second) newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(2) * time.Second)
ctx = ctx.WithBlockHeader(newHeader) ctx = ctx.WithBlockHeader(newHeader)
EndBlocker(ctx, keeper) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, inactiveQueue.Valid())
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) inactiveQueue.Close()
newProposalMsg2 := NewMsgSubmitProposal("Test2", "test2", ProposalTypeText, addrs[1], sdk.Coins{sdk.NewInt64Coin("steak", 5)}) newProposalMsg2 := NewMsgSubmitProposal("Test2", "test2", ProposalTypeText, addrs[1], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res = govHandler(ctx, newProposalMsg2) res = govHandler(ctx, newProposalMsg2)
require.True(t, res.IsOK()) require.True(t, res.IsOK())
newHeader = ctx.BlockHeader() newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second) newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(time.Duration(-1) * time.Second)
ctx = ctx.WithBlockHeader(newHeader) ctx = ctx.WithBlockHeader(newHeader)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.True(t, inactiveQueue.Valid())
inactiveQueue.Close()
EndBlocker(ctx, keeper) EndBlocker(ctx, keeper)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
newHeader = ctx.BlockHeader() newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(5) * time.Second) newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(5) * time.Second)
ctx = ctx.WithBlockHeader(newHeader) ctx = ctx.WithBlockHeader(newHeader)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.True(t, inactiveQueue.Valid())
inactiveQueue.Close()
EndBlocker(ctx, keeper) EndBlocker(ctx, keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
} }
func TestTickPassedDepositPeriod(t *testing.T) { func TestTickPassedDepositPeriod(t *testing.T) {
@ -104,45 +114,39 @@ func TestTickPassedDepositPeriod(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
govHandler := NewHandler(keeper) govHandler := NewHandler(keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.False(t, inactiveQueue.Valid())
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) inactiveQueue.Close()
require.False(t, shouldPopActiveProposalQueue(ctx, keeper)) activeQueue := keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, activeQueue.Valid())
activeQueue.Close()
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)}) newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res := govHandler(ctx, newProposalMsg) res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK()) require.True(t, res.IsOK())
var proposalID int64 var proposalID uint64
keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID) keeper.cdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &proposalID)
EndBlocker(ctx, keeper) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, inactiveQueue.Valid())
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) inactiveQueue.Close()
newHeader := ctx.BlockHeader() newHeader := ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
ctx = ctx.WithBlockHeader(newHeader) ctx = ctx.WithBlockHeader(newHeader)
EndBlocker(ctx, keeper) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) require.False(t, inactiveQueue.Valid())
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) inactiveQueue.Close()
newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)}) newDepositMsg := NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res = govHandler(ctx, newDepositMsg) res = govHandler(ctx, newDepositMsg)
require.True(t, res.IsOK()) require.True(t, res.IsOK())
require.NotNil(t, keeper.InactiveProposalQueuePeek(ctx)) activeQueue = keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.True(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.False(t, activeQueue.Valid())
require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx)) activeQueue.Close()
EndBlocker(ctx, keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx))
require.False(t, shouldPopActiveProposalQueue(ctx, keeper))
} }
func TestTickPassedVotingPeriod(t *testing.T) { func TestTickPassedVotingPeriod(t *testing.T) {
@ -152,17 +156,19 @@ func TestTickPassedVotingPeriod(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
govHandler := NewHandler(keeper) govHandler := NewHandler(keeper)
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx)) inactiveQueue := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper)) require.False(t, inactiveQueue.Valid())
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) inactiveQueue.Close()
require.False(t, shouldPopActiveProposalQueue(ctx, keeper)) activeQueue := keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, activeQueue.Valid())
activeQueue.Close()
newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)}) newProposalMsg := NewMsgSubmitProposal("Test", "test", ProposalTypeText, addrs[0], sdk.Coins{sdk.NewInt64Coin("steak", 5)})
res := govHandler(ctx, newProposalMsg) res := govHandler(ctx, newProposalMsg)
require.True(t, res.IsOK()) require.True(t, res.IsOK())
var proposalID int64 var proposalID uint64
keeper.cdc.UnmarshalBinaryBare(res.Data, &proposalID) keeper.cdc.MustUnmarshalBinaryLengthPrefixed(res.Data, &proposalID)
newHeader := ctx.BlockHeader() newHeader := ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second)
@ -172,24 +178,27 @@ func TestTickPassedVotingPeriod(t *testing.T) {
res = govHandler(ctx, newDepositMsg) res = govHandler(ctx, newDepositMsg)
require.True(t, res.IsOK()) require.True(t, res.IsOK())
EndBlocker(ctx, keeper)
newHeader = ctx.BlockHeader() newHeader = ctx.BlockHeader()
newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod).Add(keeper.GetDepositProcedure(ctx).MaxDepositPeriod) newHeader.Time = ctx.BlockHeader().Time.Add(keeper.GetDepositParams(ctx).MaxDepositPeriod).Add(keeper.GetVotingParams(ctx).VotingPeriod)
ctx = ctx.WithBlockHeader(newHeader) ctx = ctx.WithBlockHeader(newHeader)
require.True(t, shouldPopActiveProposalQueue(ctx, keeper)) inactiveQueue = keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.False(t, inactiveQueue.Valid())
inactiveQueue.Close()
activeQueue = keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
require.True(t, activeQueue.Valid())
var activeProposalID uint64
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeQueue.Value(), &activeProposalID)
require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, activeProposalID).GetStatus())
depositsIterator := keeper.GetDeposits(ctx, proposalID) depositsIterator := keeper.GetDeposits(ctx, proposalID)
require.True(t, depositsIterator.Valid()) require.True(t, depositsIterator.Valid())
depositsIterator.Close() depositsIterator.Close()
require.Equal(t, StatusVotingPeriod, keeper.GetProposal(ctx, proposalID).GetStatus()) activeQueue.Close()
EndBlocker(ctx, keeper) EndBlocker(ctx, keeper)
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx)) activeQueue = keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
depositsIterator = keeper.GetDeposits(ctx, proposalID) require.False(t, activeQueue.Valid())
require.False(t, depositsIterator.Valid()) activeQueue.Close()
depositsIterator.Close()
require.Equal(t, StatusRejected, keeper.GetProposal(ctx, proposalID).GetStatus())
require.True(t, keeper.GetProposal(ctx, proposalID).GetTallyResult().Equals(EmptyTallyResult()))
} }

View File

@ -26,19 +26,19 @@ const (
//---------------------------------------- //----------------------------------------
// Error constructors // Error constructors
func ErrUnknownProposal(codespace sdk.CodespaceType, proposalID int64) sdk.Error { func ErrUnknownProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error {
return sdk.NewError(codespace, CodeUnknownProposal, fmt.Sprintf("Unknown proposal with id %d", proposalID)) return sdk.NewError(codespace, CodeUnknownProposal, fmt.Sprintf("Unknown proposal with id %d", proposalID))
} }
func ErrInactiveProposal(codespace sdk.CodespaceType, proposalID int64) sdk.Error { func ErrInactiveProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error {
return sdk.NewError(codespace, CodeInactiveProposal, fmt.Sprintf("Inactive proposal with id %d", proposalID)) return sdk.NewError(codespace, CodeInactiveProposal, fmt.Sprintf("Inactive proposal with id %d", proposalID))
} }
func ErrAlreadyActiveProposal(codespace sdk.CodespaceType, proposalID int64) sdk.Error { func ErrAlreadyActiveProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error {
return sdk.NewError(codespace, CodeAlreadyActiveProposal, fmt.Sprintf("Proposal %d has been already active", proposalID)) return sdk.NewError(codespace, CodeAlreadyActiveProposal, fmt.Sprintf("Proposal %d has been already active", proposalID))
} }
func ErrAlreadyFinishedProposal(codespace sdk.CodespaceType, proposalID int64) sdk.Error { func ErrAlreadyFinishedProposal(codespace sdk.CodespaceType, proposalID uint64) sdk.Error {
return sdk.NewError(codespace, CodeAlreadyFinishedProposal, fmt.Sprintf("Proposal %d has already passed its voting period", proposalID)) return sdk.NewError(codespace, CodeAlreadyFinishedProposal, fmt.Sprintf("Proposal %d has already passed its voting period", proposalID))
} }

View File

@ -8,18 +8,18 @@ import (
// GenesisState - all staking state that must be provided at genesis // GenesisState - all staking state that must be provided at genesis
type GenesisState struct { type GenesisState struct {
StartingProposalID int64 `json:"starting_proposalID"` StartingProposalID uint64 `json:"starting_proposalID"`
DepositProcedure DepositProcedure `json:"deposit_period"` DepositParams DepositParams `json:"deposit_params"`
VotingProcedure VotingProcedure `json:"voting_period"` VotingParams VotingParams `json:"voting_params"`
TallyingProcedure TallyingProcedure `json:"tallying_procedure"` TallyParams TallyParams `json:"tally_params"`
} }
func NewGenesisState(startingProposalID int64, dp DepositProcedure, vp VotingProcedure, tp TallyingProcedure) GenesisState { func NewGenesisState(startingProposalID uint64, dp DepositParams, vp VotingParams, tp TallyParams) GenesisState {
return GenesisState{ return GenesisState{
StartingProposalID: startingProposalID, StartingProposalID: startingProposalID,
DepositProcedure: dp, DepositParams: dp,
VotingProcedure: vp, VotingParams: vp,
TallyingProcedure: tp, TallyParams: tp,
} }
} }
@ -27,14 +27,14 @@ func NewGenesisState(startingProposalID int64, dp DepositProcedure, vp VotingPro
func DefaultGenesisState() GenesisState { func DefaultGenesisState() GenesisState {
return GenesisState{ return GenesisState{
StartingProposalID: 1, StartingProposalID: 1,
DepositProcedure: DepositProcedure{ DepositParams: DepositParams{
MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", 10)}, MinDeposit: sdk.Coins{sdk.NewInt64Coin("steak", 10)},
MaxDepositPeriod: time.Duration(172800) * time.Second, MaxDepositPeriod: time.Duration(172800) * time.Second,
}, },
VotingProcedure: VotingProcedure{ VotingParams: VotingParams{
VotingPeriod: time.Duration(172800) * time.Second, VotingPeriod: time.Duration(172800) * time.Second,
}, },
TallyingProcedure: TallyingProcedure{ TallyParams: TallyParams{
Threshold: sdk.NewDecWithPrec(5, 1), Threshold: sdk.NewDecWithPrec(5, 1),
Veto: sdk.NewDecWithPrec(334, 3), Veto: sdk.NewDecWithPrec(334, 3),
GovernancePenalty: sdk.NewDecWithPrec(1, 2), GovernancePenalty: sdk.NewDecWithPrec(1, 2),
@ -49,22 +49,22 @@ func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
// TODO: Handle this with #870 // TODO: Handle this with #870
panic(err) panic(err)
} }
k.setDepositProcedure(ctx, data.DepositProcedure) k.setDepositParams(ctx, data.DepositParams)
k.setVotingProcedure(ctx, data.VotingProcedure) k.setVotingParams(ctx, data.VotingParams)
k.setTallyingProcedure(ctx, data.TallyingProcedure) k.setTallyParams(ctx, data.TallyParams)
} }
// WriteGenesis - output genesis parameters // WriteGenesis - output genesis parameters
func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState { func WriteGenesis(ctx sdk.Context, k Keeper) GenesisState {
startingProposalID, _ := k.getNewProposalID(ctx) startingProposalID, _ := k.getNewProposalID(ctx)
depositProcedure := k.GetDepositProcedure(ctx) depositParams := k.GetDepositParams(ctx)
votingProcedure := k.GetVotingProcedure(ctx) votingParams := k.GetVotingParams(ctx)
tallyingProcedure := k.GetTallyingProcedure(ctx) tallyParams := k.GetTallyParams(ctx)
return GenesisState{ return GenesisState{
StartingProposalID: startingProposalID, StartingProposalID: startingProposalID,
DepositProcedure: depositProcedure, DepositParams: depositParams,
VotingProcedure: votingProcedure, VotingParams: votingParams,
TallyingProcedure: tallyingProcedure, TallyParams: tallyParams,
} }
} }

View File

@ -33,7 +33,7 @@ func handleMsgSubmitProposal(ctx sdk.Context, keeper Keeper, msg MsgSubmitPropos
return err.Result() return err.Result()
} }
proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(proposal.GetProposalID()) proposalIDBytes := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposal.GetProposalID())
resTags := sdk.NewTags( resTags := sdk.NewTags(
tags.Action, tags.ActionSubmitProposal, tags.Action, tags.ActionSubmitProposal,
@ -102,40 +102,35 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
resTags = sdk.NewTags() resTags = sdk.NewTags()
// Delete proposals that haven't met minDeposit inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
for shouldPopInactiveProposalQueue(ctx, keeper) { for ; inactiveIterator.Valid(); inactiveIterator.Next() {
inactiveProposal := keeper.InactiveProposalQueuePop(ctx) var proposalID uint64
if inactiveProposal.GetStatus() != StatusDepositPeriod { keeper.cdc.MustUnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID)
continue inactiveProposal := keeper.GetProposal(ctx, proposalID)
} keeper.RefundDeposits(ctx, proposalID)
keeper.DeleteProposal(ctx, proposalID)
proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(inactiveProposal.GetProposalID())
keeper.DeleteProposal(ctx, inactiveProposal)
resTags = resTags.AppendTag(tags.Action, tags.ActionProposalDropped) resTags = resTags.AppendTag(tags.Action, tags.ActionProposalDropped)
resTags = resTags.AppendTag(tags.ProposalID, proposalIDBytes) resTags = resTags.AppendTag(tags.ProposalID, []byte(string(proposalID)))
logger.Info( logger.Info(
fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %v steak (had only %v steak); deleted", fmt.Sprintf("proposal %d (%s) didn't meet minimum deposit of %s (had only %s); deleted",
inactiveProposal.GetProposalID(), inactiveProposal.GetProposalID(),
inactiveProposal.GetTitle(), inactiveProposal.GetTitle(),
keeper.GetDepositProcedure(ctx).MinDeposit.AmountOf("steak"), keeper.GetDepositParams(ctx).MinDeposit,
inactiveProposal.GetTotalDeposit().AmountOf("steak"), inactiveProposal.GetTotalDeposit(),
), ),
) )
} }
inactiveIterator.Close()
// Check if earliest Active Proposal ended voting period yet activeIterator := keeper.ActiveProposalQueueIterator(ctx, ctx.BlockHeader().Time)
for shouldPopActiveProposalQueue(ctx, keeper) { for ; activeIterator.Valid(); activeIterator.Next() {
activeProposal := keeper.ActiveProposalQueuePop(ctx) var proposalID uint64
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
proposalStartTime := activeProposal.GetVotingStartTime() activeProposal := keeper.GetProposal(ctx, proposalID)
votingPeriod := keeper.GetVotingProcedure(ctx).VotingPeriod
if ctx.BlockHeader().Time.Before(proposalStartTime.Add(votingPeriod)) {
continue
}
passes, tallyResults := tally(ctx, keeper, activeProposal) passes, tallyResults := tally(ctx, keeper, activeProposal)
proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(activeProposal.GetProposalID())
var action []byte var action []byte
if passes { if passes {
keeper.RefundDeposits(ctx, activeProposal.GetProposalID()) keeper.RefundDeposits(ctx, activeProposal.GetProposalID())
@ -149,37 +144,15 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
activeProposal.SetTallyResult(tallyResults) activeProposal.SetTallyResult(tallyResults)
keeper.SetProposal(ctx, activeProposal) keeper.SetProposal(ctx, activeProposal)
keeper.RemoveFromActiveProposalQueue(ctx, activeProposal.GetVotingEndTime(), activeProposal.GetProposalID())
logger.Info(fmt.Sprintf("proposal %d (%s) tallied; passed: %v", logger.Info(fmt.Sprintf("proposal %d (%s) tallied; passed: %v",
activeProposal.GetProposalID(), activeProposal.GetTitle(), passes)) activeProposal.GetProposalID(), activeProposal.GetTitle(), passes))
resTags = resTags.AppendTag(tags.Action, action) resTags = resTags.AppendTag(tags.Action, action)
resTags = resTags.AppendTag(tags.ProposalID, proposalIDBytes) resTags = resTags.AppendTag(tags.ProposalID, []byte(string(proposalID)))
} }
activeIterator.Close()
return resTags return resTags
} }
func shouldPopInactiveProposalQueue(ctx sdk.Context, keeper Keeper) bool {
depositProcedure := keeper.GetDepositProcedure(ctx)
peekProposal := keeper.InactiveProposalQueuePeek(ctx)
if peekProposal == nil {
return false
} else if peekProposal.GetStatus() != StatusDepositPeriod {
return true
} else if !ctx.BlockHeader().Time.Before(peekProposal.GetSubmitTime().Add(depositProcedure.MaxDepositPeriod)) {
return true
}
return false
}
func shouldPopActiveProposalQueue(ctx sdk.Context, keeper Keeper) bool {
votingProcedure := keeper.GetVotingProcedure(ctx)
peekProposal := keeper.ActiveProposalQueuePeek(ctx)
if peekProposal == nil {
return false
} else if !ctx.BlockHeader().Time.Before(peekProposal.GetVotingStartTime().Add(votingProcedure.VotingPeriod)) {
return true
}
return false
}

View File

@ -1,10 +1,14 @@
package gov package gov
import ( import (
"time"
codec "github.com/cosmos/cosmos-sdk/codec" codec "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/params"
"github.com/tendermint/tendermint/crypto"
) )
// Parameter store default namestore // Parameter store default namestore
@ -14,17 +18,20 @@ const (
// Parameter store key // Parameter store key
var ( var (
ParamStoreKeyDepositProcedure = []byte("depositprocedure") ParamStoreKeyDepositParams = []byte("depositparams")
ParamStoreKeyVotingProcedure = []byte("votingprocedure") ParamStoreKeyVotingParams = []byte("votingparams")
ParamStoreKeyTallyingProcedure = []byte("tallyingprocedure") ParamStoreKeyTallyParams = []byte("tallyparams")
DepositedCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govDepositedCoins")))
BurnedDepositCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins")))
) )
// Type declaration for parameters // Type declaration for parameters
func ParamTypeTable() params.TypeTable { func ParamTypeTable() params.TypeTable {
return params.NewTypeTable( return params.NewTypeTable(
ParamStoreKeyDepositProcedure, DepositProcedure{}, ParamStoreKeyDepositParams, DepositParams{},
ParamStoreKeyVotingProcedure, VotingProcedure{}, ParamStoreKeyVotingParams, VotingParams{},
ParamStoreKeyTallyingProcedure, TallyingProcedure{}, ParamStoreKeyTallyParams, TallyParams{},
) )
} }
@ -92,13 +99,17 @@ func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description
TotalDeposit: sdk.Coins{}, TotalDeposit: sdk.Coins{},
SubmitTime: ctx.BlockHeader().Time, SubmitTime: ctx.BlockHeader().Time,
} }
depositPeriod := keeper.GetDepositParams(ctx).MaxDepositPeriod
proposal.SetDepositEndTime(proposal.GetSubmitTime().Add(depositPeriod))
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
keeper.InactiveProposalQueuePush(ctx, proposal) keeper.InsertInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposalID)
return proposal return proposal
} }
// Get Proposal from store by ProposalID // Get Proposal from store by ProposalID
func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID int64) Proposal { func (keeper Keeper) GetProposal(ctx sdk.Context, proposalID uint64) Proposal {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyProposal(proposalID)) bz := store.Get(KeyProposal(proposalID))
if bz == nil { if bz == nil {
@ -119,13 +130,16 @@ func (keeper Keeper) SetProposal(ctx sdk.Context, proposal Proposal) {
} }
// Implements sdk.AccountKeeper. // Implements sdk.AccountKeeper.
func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposal Proposal) { func (keeper Keeper) DeleteProposal(ctx sdk.Context, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
store.Delete(KeyProposal(proposal.GetProposalID())) proposal := keeper.GetProposal(ctx, proposalID)
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposalID)
keeper.RemoveFromActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposalID)
store.Delete(KeyProposal(proposalID))
} }
// Get Proposal from store by ProposalID // Get Proposal from store by ProposalID
func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddress, depositerAddr sdk.AccAddress, status ProposalStatus, numLatest int64) []Proposal { func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddress, depositerAddr sdk.AccAddress, status ProposalStatus, numLatest uint64) []Proposal {
maxProposalID, err := keeper.peekCurrentProposalID(ctx) maxProposalID, err := keeper.peekCurrentProposalID(ctx)
if err != nil { if err != nil {
@ -134,7 +148,7 @@ func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddr
matchingProposals := []Proposal{} matchingProposals := []Proposal{}
if numLatest <= 0 { if numLatest == 0 {
numLatest = maxProposalID numLatest = maxProposalID
} }
@ -169,7 +183,7 @@ func (keeper Keeper) GetProposalsFiltered(ctx sdk.Context, voterAddr sdk.AccAddr
return matchingProposals return matchingProposals
} }
func (keeper Keeper) setInitialProposalID(ctx sdk.Context, proposalID int64) sdk.Error { func (keeper Keeper) setInitialProposalID(ctx sdk.Context, proposalID uint64) sdk.Error {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyNextProposalID) bz := store.Get(KeyNextProposalID)
if bz != nil { if bz != nil {
@ -181,7 +195,7 @@ func (keeper Keeper) setInitialProposalID(ctx sdk.Context, proposalID int64) sdk
} }
// Get the last used proposal ID // Get the last used proposal ID
func (keeper Keeper) GetLastProposalID(ctx sdk.Context) (proposalID int64) { func (keeper Keeper) GetLastProposalID(ctx sdk.Context) (proposalID uint64) {
proposalID, err := keeper.peekCurrentProposalID(ctx) proposalID, err := keeper.peekCurrentProposalID(ctx)
if err != nil { if err != nil {
return 0 return 0
@ -191,11 +205,11 @@ func (keeper Keeper) GetLastProposalID(ctx sdk.Context) (proposalID int64) {
} }
// Gets the next available ProposalID and increments it // Gets the next available ProposalID and increments it
func (keeper Keeper) getNewProposalID(ctx sdk.Context) (proposalID int64, err sdk.Error) { func (keeper Keeper) getNewProposalID(ctx sdk.Context) (proposalID uint64, err sdk.Error) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyNextProposalID) bz := store.Get(KeyNextProposalID)
if bz == nil { if bz == nil {
return -1, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set") return 0, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set")
} }
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID) keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
bz = keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID + 1) bz = keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID + 1)
@ -204,11 +218,11 @@ func (keeper Keeper) getNewProposalID(ctx sdk.Context) (proposalID int64, err sd
} }
// Peeks the next available ProposalID without incrementing it // Peeks the next available ProposalID without incrementing it
func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID int64, err sdk.Error) { func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID uint64, err sdk.Error) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyNextProposalID) bz := store.Get(KeyNextProposalID)
if bz == nil { if bz == nil {
return -1, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set") return 0, ErrInvalidGenesis(keeper.codespace, "InitialProposalID never set")
} }
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID) keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalID)
return proposalID, nil return proposalID, nil
@ -216,58 +230,62 @@ func (keeper Keeper) peekCurrentProposalID(ctx sdk.Context) (proposalID int64, e
func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) { func (keeper Keeper) activateVotingPeriod(ctx sdk.Context, proposal Proposal) {
proposal.SetVotingStartTime(ctx.BlockHeader().Time) proposal.SetVotingStartTime(ctx.BlockHeader().Time)
votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod
proposal.SetVotingEndTime(proposal.GetVotingStartTime().Add(votingPeriod))
proposal.SetStatus(StatusVotingPeriod) proposal.SetStatus(StatusVotingPeriod)
keeper.SetProposal(ctx, proposal) keeper.SetProposal(ctx, proposal)
keeper.ActiveProposalQueuePush(ctx, proposal)
keeper.RemoveFromInactiveProposalQueue(ctx, proposal.GetDepositEndTime(), proposal.GetProposalID())
keeper.InsertActiveProposalQueue(ctx, proposal.GetVotingEndTime(), proposal.GetProposalID())
} }
// ===================================================== // =====================================================
// Procedures // Params
// Returns the current Deposit Procedure from the global param store // Returns the current DepositParams from the global param store
// nolint: errcheck // nolint: errcheck
func (keeper Keeper) GetDepositProcedure(ctx sdk.Context) DepositProcedure { func (keeper Keeper) GetDepositParams(ctx sdk.Context) DepositParams {
var depositProcedure DepositProcedure var depositParams DepositParams
keeper.paramSpace.Get(ctx, ParamStoreKeyDepositProcedure, &depositProcedure) keeper.paramSpace.Get(ctx, ParamStoreKeyDepositParams, &depositParams)
return depositProcedure return depositParams
} }
// Returns the current Voting Procedure from the global param store // Returns the current Voting Procedure from the global param store
// nolint: errcheck // nolint: errcheck
func (keeper Keeper) GetVotingProcedure(ctx sdk.Context) VotingProcedure { func (keeper Keeper) GetVotingParams(ctx sdk.Context) VotingParams {
var votingProcedure VotingProcedure var votingParams VotingParams
keeper.paramSpace.Get(ctx, ParamStoreKeyVotingProcedure, &votingProcedure) keeper.paramSpace.Get(ctx, ParamStoreKeyVotingParams, &votingParams)
return votingProcedure return votingParams
} }
// Returns the current Tallying Procedure from the global param store // Returns the current Tallying Procedure from the global param store
// nolint: errcheck // nolint: errcheck
func (keeper Keeper) GetTallyingProcedure(ctx sdk.Context) TallyingProcedure { func (keeper Keeper) GetTallyParams(ctx sdk.Context) TallyParams {
var tallyingProcedure TallyingProcedure var tallyParams TallyParams
keeper.paramSpace.Get(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure) keeper.paramSpace.Get(ctx, ParamStoreKeyTallyParams, &tallyParams)
return tallyingProcedure return tallyParams
} }
// nolint: errcheck // nolint: errcheck
func (keeper Keeper) setDepositProcedure(ctx sdk.Context, depositProcedure DepositProcedure) { func (keeper Keeper) setDepositParams(ctx sdk.Context, depositParams DepositParams) {
keeper.paramSpace.Set(ctx, ParamStoreKeyDepositProcedure, &depositProcedure) keeper.paramSpace.Set(ctx, ParamStoreKeyDepositParams, &depositParams)
} }
// nolint: errcheck // nolint: errcheck
func (keeper Keeper) setVotingProcedure(ctx sdk.Context, votingProcedure VotingProcedure) { func (keeper Keeper) setVotingParams(ctx sdk.Context, votingParams VotingParams) {
keeper.paramSpace.Set(ctx, ParamStoreKeyVotingProcedure, &votingProcedure) keeper.paramSpace.Set(ctx, ParamStoreKeyVotingParams, &votingParams)
} }
// nolint: errcheck // nolint: errcheck
func (keeper Keeper) setTallyingProcedure(ctx sdk.Context, tallyingProcedure TallyingProcedure) { func (keeper Keeper) setTallyParams(ctx sdk.Context, tallyParams TallyParams) {
keeper.paramSpace.Set(ctx, ParamStoreKeyTallyingProcedure, &tallyingProcedure) keeper.paramSpace.Set(ctx, ParamStoreKeyTallyParams, &tallyParams)
} }
// ===================================================== // =====================================================
// Votes // Votes
// Adds a vote on a specific proposal // Adds a vote on a specific proposal
func (keeper Keeper) AddVote(ctx sdk.Context, proposalID int64, voterAddr sdk.AccAddress, option VoteOption) sdk.Error { func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, option VoteOption) sdk.Error {
proposal := keeper.GetProposal(ctx, proposalID) proposal := keeper.GetProposal(ctx, proposalID)
if proposal == nil { if proposal == nil {
return ErrUnknownProposal(keeper.codespace, proposalID) return ErrUnknownProposal(keeper.codespace, proposalID)
@ -291,7 +309,7 @@ func (keeper Keeper) AddVote(ctx sdk.Context, proposalID int64, voterAddr sdk.Ac
} }
// Gets the vote of a specific voter on a specific proposal // Gets the vote of a specific voter on a specific proposal
func (keeper Keeper) GetVote(ctx sdk.Context, proposalID int64, voterAddr sdk.AccAddress) (Vote, bool) { func (keeper Keeper) GetVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) (Vote, bool) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyVote(proposalID, voterAddr)) bz := store.Get(KeyVote(proposalID, voterAddr))
if bz == nil { if bz == nil {
@ -302,19 +320,19 @@ func (keeper Keeper) GetVote(ctx sdk.Context, proposalID int64, voterAddr sdk.Ac
return vote, true return vote, true
} }
func (keeper Keeper) setVote(ctx sdk.Context, proposalID int64, voterAddr sdk.AccAddress, vote Vote) { func (keeper Keeper) setVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, vote Vote) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(vote) bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(vote)
store.Set(KeyVote(proposalID, voterAddr), bz) store.Set(KeyVote(proposalID, voterAddr), bz)
} }
// Gets all the votes on a specific proposal // Gets all the votes on a specific proposal
func (keeper Keeper) GetVotes(ctx sdk.Context, proposalID int64) sdk.Iterator { func (keeper Keeper) GetVotes(ctx sdk.Context, proposalID uint64) sdk.Iterator {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
return sdk.KVStorePrefixIterator(store, KeyVotesSubspace(proposalID)) return sdk.KVStorePrefixIterator(store, KeyVotesSubspace(proposalID))
} }
func (keeper Keeper) deleteVote(ctx sdk.Context, proposalID int64, voterAddr sdk.AccAddress) { func (keeper Keeper) deleteVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
store.Delete(KeyVote(proposalID, voterAddr)) store.Delete(KeyVote(proposalID, voterAddr))
} }
@ -323,7 +341,7 @@ func (keeper Keeper) deleteVote(ctx sdk.Context, proposalID int64, voterAddr sdk
// Deposits // Deposits
// Gets the deposit of a specific depositer on a specific proposal // Gets the deposit of a specific depositer on a specific proposal
func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID int64, depositerAddr sdk.AccAddress) (Deposit, bool) { func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID uint64, depositerAddr sdk.AccAddress) (Deposit, bool) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyDeposit(proposalID, depositerAddr)) bz := store.Get(KeyDeposit(proposalID, depositerAddr))
if bz == nil { if bz == nil {
@ -334,7 +352,7 @@ func (keeper Keeper) GetDeposit(ctx sdk.Context, proposalID int64, depositerAddr
return deposit, true return deposit, true
} }
func (keeper Keeper) setDeposit(ctx sdk.Context, proposalID int64, depositerAddr sdk.AccAddress, deposit Deposit) { func (keeper Keeper) setDeposit(ctx sdk.Context, proposalID uint64, depositerAddr sdk.AccAddress, deposit Deposit) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(deposit) bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(deposit)
store.Set(KeyDeposit(proposalID, depositerAddr), bz) store.Set(KeyDeposit(proposalID, depositerAddr), bz)
@ -342,7 +360,7 @@ func (keeper Keeper) setDeposit(ctx sdk.Context, proposalID int64, depositerAddr
// Adds or updates a deposit of a specific depositer on a specific proposal // Adds or updates a deposit of a specific depositer on a specific proposal
// Activates voting period when appropriate // Activates voting period when appropriate
func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID int64, depositerAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) { func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID uint64, depositerAddr sdk.AccAddress, depositAmount sdk.Coins) (sdk.Error, bool) {
// Checks to see if proposal exists // Checks to see if proposal exists
proposal := keeper.GetProposal(ctx, proposalID) proposal := keeper.GetProposal(ctx, proposalID)
if proposal == nil { if proposal == nil {
@ -354,8 +372,8 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID int64, depositerAddr
return ErrAlreadyFinishedProposal(keeper.codespace, proposalID), false return ErrAlreadyFinishedProposal(keeper.codespace, proposalID), false
} }
// Subtract coins from depositer's account // Send coins from depositer's account to DepositedCoinsAccAddr account
_, _, err := keeper.ck.SubtractCoins(ctx, depositerAddr, depositAmount) _, err := keeper.ck.SendCoins(ctx, depositerAddr, DepositedCoinsAccAddr, depositAmount)
if err != nil { if err != nil {
return err, false return err, false
} }
@ -367,7 +385,7 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID int64, depositerAddr
// Check if deposit tipped proposal into voting period // Check if deposit tipped proposal into voting period
// Active voting period if so // Active voting period if so
activatedVotingPeriod := false activatedVotingPeriod := false
if proposal.GetStatus() == StatusDepositPeriod && proposal.GetTotalDeposit().IsGTE(keeper.GetDepositProcedure(ctx).MinDeposit) { if proposal.GetStatus() == StatusDepositPeriod && proposal.GetTotalDeposit().IsGTE(keeper.GetDepositParams(ctx).MinDeposit) {
keeper.activateVotingPeriod(ctx, proposal) keeper.activateVotingPeriod(ctx, proposal)
activatedVotingPeriod = true activatedVotingPeriod = true
} }
@ -386,13 +404,13 @@ func (keeper Keeper) AddDeposit(ctx sdk.Context, proposalID int64, depositerAddr
} }
// Gets all the deposits on a specific proposal // Gets all the deposits on a specific proposal
func (keeper Keeper) GetDeposits(ctx sdk.Context, proposalID int64) sdk.Iterator { func (keeper Keeper) GetDeposits(ctx sdk.Context, proposalID uint64) sdk.Iterator {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
return sdk.KVStorePrefixIterator(store, KeyDepositsSubspace(proposalID)) return sdk.KVStorePrefixIterator(store, KeyDepositsSubspace(proposalID))
} }
// Returns and deletes all the deposits on a specific proposal // Returns and deletes all the deposits on a specific proposal
func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID int64) { func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
depositsIterator := keeper.GetDeposits(ctx, proposalID) depositsIterator := keeper.GetDeposits(ctx, proposalID)
@ -400,7 +418,7 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID int64) {
deposit := &Deposit{} deposit := &Deposit{}
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit) keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit)
_, _, err := keeper.ck.AddCoins(ctx, deposit.Depositer, deposit.Amount) _, err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, deposit.Depositer, deposit.Amount)
if err != nil { if err != nil {
panic("should not happen") panic("should not happen")
} }
@ -412,11 +430,19 @@ func (keeper Keeper) RefundDeposits(ctx sdk.Context, proposalID int64) {
} }
// Deletes all the deposits on a specific proposal without refunding them // Deletes all the deposits on a specific proposal without refunding them
func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID int64) { func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
depositsIterator := keeper.GetDeposits(ctx, proposalID) depositsIterator := keeper.GetDeposits(ctx, proposalID)
for ; depositsIterator.Valid(); depositsIterator.Next() { for ; depositsIterator.Valid(); depositsIterator.Next() {
deposit := &Deposit{}
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(depositsIterator.Value(), deposit)
_, err := keeper.ck.SendCoins(ctx, DepositedCoinsAccAddr, BurnedDepositCoinsAccAddr, deposit.Amount)
if err != nil {
panic("should not happen")
}
store.Delete(depositsIterator.Key()) store.Delete(depositsIterator.Key())
} }
@ -426,93 +452,40 @@ func (keeper Keeper) DeleteDeposits(ctx sdk.Context, proposalID int64) {
// ===================================================== // =====================================================
// ProposalQueues // ProposalQueues
func (keeper Keeper) getActiveProposalQueue(ctx sdk.Context) ProposalQueue { // 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 {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyActiveProposalQueue) return store.Iterator(PrefixActiveProposalQueue, sdk.PrefixEndBytes(PrefixActiveProposalQueueTime(endTime)))
if bz == nil {
return nil
}
var proposalQueue ProposalQueue
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalQueue)
return proposalQueue
} }
func (keeper Keeper) setActiveProposalQueue(ctx sdk.Context, proposalQueue ProposalQueue) { // Inserts a ProposalID into the active proposal queue at endTime
func (keeper Keeper) InsertActiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalQueue) bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID)
store.Set(KeyActiveProposalQueue, bz) store.Set(KeyActiveProposalQueueProposal(endTime, proposalID), bz)
} }
// Return the Proposal at the front of the ProposalQueue // removes a proposalID from the Active Proposal Queue
func (keeper Keeper) ActiveProposalQueuePeek(ctx sdk.Context) Proposal { func (keeper Keeper) RemoveFromActiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
proposalQueue := keeper.getActiveProposalQueue(ctx)
if len(proposalQueue) == 0 {
return nil
}
return keeper.GetProposal(ctx, proposalQueue[0])
}
// Remove and return a Proposal from the front of the ProposalQueue
func (keeper Keeper) ActiveProposalQueuePop(ctx sdk.Context) Proposal {
proposalQueue := keeper.getActiveProposalQueue(ctx)
if len(proposalQueue) == 0 {
return nil
}
frontElement, proposalQueue := proposalQueue[0], proposalQueue[1:]
keeper.setActiveProposalQueue(ctx, proposalQueue)
return keeper.GetProposal(ctx, frontElement)
}
// Add a proposalID to the back of the ProposalQueue
func (keeper Keeper) ActiveProposalQueuePush(ctx sdk.Context, proposal Proposal) {
proposalQueue := append(keeper.getActiveProposalQueue(ctx), proposal.GetProposalID())
keeper.setActiveProposalQueue(ctx, proposalQueue)
}
func (keeper Keeper) getInactiveProposalQueue(ctx sdk.Context) ProposalQueue {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := store.Get(KeyInactiveProposalQueue) store.Delete(KeyActiveProposalQueueProposal(endTime, proposalID))
if bz == nil {
return nil
}
var proposalQueue ProposalQueue
keeper.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &proposalQueue)
return proposalQueue
} }
func (keeper Keeper) setInactiveProposalQueue(ctx sdk.Context, proposalQueue ProposalQueue) { // 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 {
store := ctx.KVStore(keeper.storeKey) store := ctx.KVStore(keeper.storeKey)
bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalQueue) return store.Iterator(PrefixInactiveProposalQueue, sdk.PrefixEndBytes(PrefixInactiveProposalQueueTime(endTime)))
store.Set(KeyInactiveProposalQueue, bz)
} }
// Return the Proposal at the front of the ProposalQueue // Inserts a ProposalID into the inactive proposal queue at endTime
func (keeper Keeper) InactiveProposalQueuePeek(ctx sdk.Context) Proposal { func (keeper Keeper) InsertInactiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
proposalQueue := keeper.getInactiveProposalQueue(ctx) store := ctx.KVStore(keeper.storeKey)
if len(proposalQueue) == 0 { bz := keeper.cdc.MustMarshalBinaryLengthPrefixed(proposalID)
return nil store.Set(KeyInactiveProposalQueueProposal(endTime, proposalID), bz)
}
return keeper.GetProposal(ctx, proposalQueue[0])
} }
// Remove and return a Proposal from the front of the ProposalQueue // removes a proposalID from the Inactive Proposal Queue
func (keeper Keeper) InactiveProposalQueuePop(ctx sdk.Context) Proposal { func (keeper Keeper) RemoveFromInactiveProposalQueue(ctx sdk.Context, endTime time.Time, proposalID uint64) {
proposalQueue := keeper.getInactiveProposalQueue(ctx) store := ctx.KVStore(keeper.storeKey)
if len(proposalQueue) == 0 { store.Delete(KeyInactiveProposalQueueProposal(endTime, proposalID))
return nil
}
frontElement, proposalQueue := proposalQueue[0], proposalQueue[1:]
keeper.setInactiveProposalQueue(ctx, proposalQueue)
return keeper.GetProposal(ctx, frontElement)
}
// Add a proposalID to the back of the ProposalQueue
func (keeper Keeper) InactiveProposalQueuePush(ctx sdk.Context, proposal Proposal) {
proposalQueue := append(keeper.getInactiveProposalQueue(ctx), proposal.GetProposalID())
keeper.setInactiveProposalQueue(ctx, proposalQueue)
} }

View File

@ -1,7 +1,9 @@
package gov package gov
import ( import (
"bytes"
"fmt" "fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
) )
@ -10,32 +12,68 @@ import (
// Key for getting a the next available proposalID from the store // Key for getting a the next available proposalID from the store
var ( var (
KeyDelimiter = []byte(":")
KeyNextProposalID = []byte("newProposalID") KeyNextProposalID = []byte("newProposalID")
KeyActiveProposalQueue = []byte("activeProposalQueue") PrefixActiveProposalQueue = []byte("activeProposalQueue")
KeyInactiveProposalQueue = []byte("inactiveProposalQueue") PrefixInactiveProposalQueue = []byte("inactiveProposalQueue")
) )
// Key for getting a specific proposal from the store // Key for getting a specific proposal from the store
func KeyProposal(proposalID int64) []byte { func KeyProposal(proposalID uint64) []byte {
return []byte(fmt.Sprintf("proposals:%d", proposalID)) return []byte(fmt.Sprintf("proposals:%d", proposalID))
} }
// Key for getting a specific deposit from the store // Key for getting a specific deposit from the store
func KeyDeposit(proposalID int64, depositerAddr sdk.AccAddress) []byte { func KeyDeposit(proposalID uint64, depositerAddr sdk.AccAddress) []byte {
return []byte(fmt.Sprintf("deposits:%d:%d", proposalID, depositerAddr)) return []byte(fmt.Sprintf("deposits:%d:%d", proposalID, depositerAddr))
} }
// Key for getting a specific vote from the store // Key for getting a specific vote from the store
func KeyVote(proposalID int64, voterAddr sdk.AccAddress) []byte { func KeyVote(proposalID uint64, voterAddr sdk.AccAddress) []byte {
return []byte(fmt.Sprintf("votes:%d:%d", proposalID, voterAddr)) return []byte(fmt.Sprintf("votes:%d:%d", proposalID, voterAddr))
} }
// Key for getting all deposits on a proposal from the store // Key for getting all deposits on a proposal from the store
func KeyDepositsSubspace(proposalID int64) []byte { func KeyDepositsSubspace(proposalID uint64) []byte {
return []byte(fmt.Sprintf("deposits:%d:", proposalID)) return []byte(fmt.Sprintf("deposits:%d:", proposalID))
} }
// Key for getting all votes on a proposal from the store // Key for getting all votes on a proposal from the store
func KeyVotesSubspace(proposalID int64) []byte { func KeyVotesSubspace(proposalID uint64) []byte {
return []byte(fmt.Sprintf("votes:%d:", proposalID)) return []byte(fmt.Sprintf("votes:%d:", proposalID))
} }
// Returns the key for a proposalID in the activeProposalQueue
func PrefixActiveProposalQueueTime(endTime time.Time) []byte {
return bytes.Join([][]byte{
PrefixActiveProposalQueue,
sdk.FormatTimeBytes(endTime),
}, KeyDelimiter)
}
// Returns the key for a proposalID in the activeProposalQueue
func KeyActiveProposalQueueProposal(endTime time.Time, proposalID uint64) []byte {
return bytes.Join([][]byte{
PrefixActiveProposalQueue,
sdk.FormatTimeBytes(endTime),
sdk.Uint64ToBigEndian(proposalID),
}, KeyDelimiter)
}
// Returns the key for a proposalID in the activeProposalQueue
func PrefixInactiveProposalQueueTime(endTime time.Time) []byte {
return bytes.Join([][]byte{
PrefixInactiveProposalQueue,
sdk.FormatTimeBytes(endTime),
}, KeyDelimiter)
}
// Returns the key for a proposalID in the activeProposalQueue
func KeyInactiveProposalQueueProposal(endTime time.Time, proposalID uint64) []byte {
return bytes.Join([][]byte{
PrefixInactiveProposalQueue,
sdk.FormatTimeBytes(endTime),
sdk.Uint64ToBigEndian(proposalID),
}, KeyDelimiter)
}

View File

@ -36,7 +36,7 @@ func TestIncrementProposalNumber(t *testing.T) {
keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposal6 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposal6 := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
require.Equal(t, int64(6), proposal6.GetProposalID()) require.Equal(t, uint64(6), proposal6.GetProposalID())
} }
func TestActivateVotingPeriod(t *testing.T) { func TestActivateVotingPeriod(t *testing.T) {
@ -47,12 +47,17 @@ func TestActivateVotingPeriod(t *testing.T) {
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
require.True(t, proposal.GetVotingStartTime().Equal(time.Time{})) require.True(t, proposal.GetVotingStartTime().Equal(time.Time{}))
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
keeper.activateVotingPeriod(ctx, proposal) keeper.activateVotingPeriod(ctx, proposal)
require.True(t, proposal.GetVotingStartTime().Equal(ctx.BlockHeader().Time)) require.True(t, proposal.GetVotingStartTime().Equal(ctx.BlockHeader().Time))
require.Equal(t, proposal.GetProposalID(), keeper.ActiveProposalQueuePeek(ctx).GetProposalID())
activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.GetVotingEndTime())
require.True(t, activeIterator.Valid())
var proposalID uint64
keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
require.Equal(t, proposalID, proposal.GetProposalID())
activeIterator.Close()
} }
func TestDeposits(t *testing.T) { func TestDeposits(t *testing.T) {
@ -79,7 +84,6 @@ func TestDeposits(t *testing.T) {
deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1]) deposit, found := keeper.GetDeposit(ctx, proposalID, addrs[1])
require.False(t, found) require.False(t, found)
require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(time.Time{})) require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(time.Time{}))
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
// Check first deposit // Check first deposit
err, votingStarted := keeper.AddDeposit(ctx, proposalID, addrs[0], fourSteak) err, votingStarted := keeper.AddDeposit(ctx, proposalID, addrs[0], fourSteak)
@ -116,8 +120,6 @@ func TestDeposits(t *testing.T) {
// Check that proposal moved to voting period // Check that proposal moved to voting period
require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(ctx.BlockHeader().Time)) require.True(t, keeper.GetProposal(ctx, proposalID).GetVotingStartTime().Equal(ctx.BlockHeader().Time))
require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx))
require.Equal(t, proposalID, keeper.ActiveProposalQueuePeek(ctx).GetProposalID())
// Test deposit iterator // Test deposit iterator
depositsIterator := keeper.GetDeposits(ctx, proposalID) depositsIterator := keeper.GetDeposits(ctx, proposalID)
@ -207,44 +209,21 @@ func TestProposalQueues(t *testing.T) {
ctx := mapp.BaseApp.NewContext(false, abci.Header{}) ctx := mapp.BaseApp.NewContext(false, abci.Header{})
mapp.InitChainer(ctx, abci.RequestInitChain{}) mapp.InitChainer(ctx, abci.RequestInitChain{})
require.Nil(t, keeper.InactiveProposalQueuePeek(ctx))
require.Nil(t, keeper.ActiveProposalQueuePeek(ctx))
// create test proposals // create test proposals
proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText) proposal := keeper.NewTextProposal(ctx, "Test", "description", ProposalTypeText)
proposal2 := keeper.NewTextProposal(ctx, "Test2", "description", ProposalTypeText)
proposal3 := keeper.NewTextProposal(ctx, "Test3", "description", ProposalTypeText)
proposal4 := keeper.NewTextProposal(ctx, "Test4", "description", ProposalTypeText)
// test pushing to inactive proposal queue inactiveIterator := keeper.InactiveProposalQueueIterator(ctx, proposal.GetDepositEndTime())
keeper.InactiveProposalQueuePush(ctx, proposal) require.True(t, inactiveIterator.Valid())
keeper.InactiveProposalQueuePush(ctx, proposal2) var proposalID uint64
keeper.InactiveProposalQueuePush(ctx, proposal3) keeper.cdc.UnmarshalBinaryLengthPrefixed(inactiveIterator.Value(), &proposalID)
keeper.InactiveProposalQueuePush(ctx, proposal4) require.Equal(t, proposalID, proposal.GetProposalID())
inactiveIterator.Close()
// test peeking and popping from inactive proposal queue keeper.activateVotingPeriod(ctx, proposal)
require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal2.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal2.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal3.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal3.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePeek(ctx).GetProposalID(), proposal4.GetProposalID())
require.Equal(t, keeper.InactiveProposalQueuePop(ctx).GetProposalID(), proposal4.GetProposalID())
// test pushing to active proposal queue activeIterator := keeper.ActiveProposalQueueIterator(ctx, proposal.GetVotingEndTime())
keeper.ActiveProposalQueuePush(ctx, proposal) require.True(t, activeIterator.Valid())
keeper.ActiveProposalQueuePush(ctx, proposal2) keeper.cdc.UnmarshalBinaryLengthPrefixed(activeIterator.Value(), &proposalID)
keeper.ActiveProposalQueuePush(ctx, proposal3) require.Equal(t, proposalID, proposal.GetProposalID())
keeper.ActiveProposalQueuePush(ctx, proposal4) activeIterator.Close()
// test peeking and popping from active proposal queue
require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal2.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal2.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal3.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal3.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePeek(ctx).GetProposalID(), proposal4.GetProposalID())
require.Equal(t, keeper.ActiveProposalQueuePop(ctx).GetProposalID(), proposal4.GetProposalID())
} }

View File

@ -84,12 +84,12 @@ func (msg MsgSubmitProposal) GetSigners() []sdk.AccAddress {
//----------------------------------------------------------- //-----------------------------------------------------------
// MsgDeposit // MsgDeposit
type MsgDeposit struct { type MsgDeposit struct {
ProposalID int64 `json:"proposal_id"` // ID of the proposal ProposalID uint64 `json:"proposal_id"` // ID of the proposal
Depositer sdk.AccAddress `json:"depositer"` // Address of the depositer Depositer sdk.AccAddress `json:"depositer"` // Address of the depositer
Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit Amount sdk.Coins `json:"amount"` // Coins to add to the proposal's deposit
} }
func NewMsgDeposit(depositer sdk.AccAddress, proposalID int64, amount sdk.Coins) MsgDeposit { func NewMsgDeposit(depositer sdk.AccAddress, proposalID uint64, amount sdk.Coins) MsgDeposit {
return MsgDeposit{ return MsgDeposit{
ProposalID: proposalID, ProposalID: proposalID,
Depositer: depositer, Depositer: depositer,
@ -145,12 +145,12 @@ func (msg MsgDeposit) GetSigners() []sdk.AccAddress {
//----------------------------------------------------------- //-----------------------------------------------------------
// MsgVote // MsgVote
type MsgVote struct { type MsgVote struct {
ProposalID int64 `json:"proposal_id"` // ID of the proposal ProposalID uint64 `json:"proposal_id"` // ID of the proposal
Voter sdk.AccAddress `json:"voter"` // address of the voter Voter sdk.AccAddress `json:"voter"` // address of the voter
Option VoteOption `json:"option"` // option from OptionSet chosen by the voter Option VoteOption `json:"option"` // option from OptionSet chosen by the voter
} }
func NewMsgVote(voter sdk.AccAddress, proposalID int64, option VoteOption) MsgVote { func NewMsgVote(voter sdk.AccAddress, proposalID uint64, option VoteOption) MsgVote {
return MsgVote{ return MsgVote{
ProposalID: proposalID, ProposalID: proposalID,
Voter: voter, Voter: voter,

View File

@ -53,13 +53,12 @@ func TestMsgSubmitProposal(t *testing.T) {
func TestMsgDeposit(t *testing.T) { func TestMsgDeposit(t *testing.T) {
_, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{}) _, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{})
tests := []struct { tests := []struct {
proposalID int64 proposalID uint64
depositerAddr sdk.AccAddress depositerAddr sdk.AccAddress
depositAmount sdk.Coins depositAmount sdk.Coins
expectPass bool expectPass bool
}{ }{
{0, addrs[0], coinsPos, true}, {0, addrs[0], coinsPos, true},
{-1, addrs[0], coinsPos, false},
{1, sdk.AccAddress{}, coinsPos, false}, {1, sdk.AccAddress{}, coinsPos, false},
{1, addrs[0], coinsZero, true}, {1, addrs[0], coinsZero, true},
{1, addrs[0], coinsNeg, false}, {1, addrs[0], coinsNeg, false},
@ -80,13 +79,12 @@ func TestMsgDeposit(t *testing.T) {
func TestMsgVote(t *testing.T) { func TestMsgVote(t *testing.T) {
_, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{}) _, addrs, _, _ := mock.CreateGenAccounts(1, sdk.Coins{})
tests := []struct { tests := []struct {
proposalID int64 proposalID uint64
voterAddr sdk.AccAddress voterAddr sdk.AccAddress
option VoteOption option VoteOption
expectPass bool expectPass bool
}{ }{
{0, addrs[0], OptionYes, true}, {0, addrs[0], OptionYes, true},
{-1, addrs[0], OptionYes, false},
{0, sdk.AccAddress{}, OptionYes, false}, {0, sdk.AccAddress{}, OptionYes, false},
{0, addrs[0], OptionNo, true}, {0, addrs[0], OptionNo, true},
{0, addrs[0], OptionNoWithVeto, true}, {0, addrs[0], OptionNoWithVeto, true},

View File

@ -7,19 +7,19 @@ import (
) )
// Procedure around Deposits for governance // Procedure around Deposits for governance
type DepositProcedure struct { type DepositParams struct {
MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period. MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period.
MaxDepositPeriod time.Duration `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months MaxDepositPeriod time.Duration `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
} }
// Procedure around Tallying votes in governance // Procedure around Tallying votes in governance
type TallyingProcedure struct { type TallyParams struct {
Threshold sdk.Dec `json:"threshold"` // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5 Threshold sdk.Dec `json:"threshold"` // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5
Veto sdk.Dec `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 Veto sdk.Dec `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
GovernancePenalty sdk.Dec `json:"governance_penalty"` // Penalty if validator does not vote GovernancePenalty sdk.Dec `json:"governance_penalty"` // Penalty if validator does not vote
} }
// Procedure around Voting in governance // Procedure around Voting in governance
type VotingProcedure struct { type VotingParams struct {
VotingPeriod time.Duration `json:"voting_period"` // Length of the voting period. VotingPeriod time.Duration `json:"voting_period"` // Length of the voting period.
} }

View File

@ -13,8 +13,8 @@ import (
//----------------------------------------------------------- //-----------------------------------------------------------
// Proposal interface // Proposal interface
type Proposal interface { type Proposal interface {
GetProposalID() int64 GetProposalID() uint64
SetProposalID(int64) SetProposalID(uint64)
GetTitle() string GetTitle() string
SetTitle(string) SetTitle(string)
@ -34,11 +34,17 @@ type Proposal interface {
GetSubmitTime() time.Time GetSubmitTime() time.Time
SetSubmitTime(time.Time) SetSubmitTime(time.Time)
GetDepositEndTime() time.Time
SetDepositEndTime(time.Time)
GetTotalDeposit() sdk.Coins GetTotalDeposit() sdk.Coins
SetTotalDeposit(sdk.Coins) SetTotalDeposit(sdk.Coins)
GetVotingStartTime() time.Time GetVotingStartTime() time.Time
SetVotingStartTime(time.Time) SetVotingStartTime(time.Time)
GetVotingEndTime() time.Time
SetVotingEndTime(time.Time)
} }
// checks if two proposals are equal // checks if two proposals are equal
@ -50,8 +56,10 @@ func ProposalEqual(proposalA Proposal, proposalB Proposal) bool {
proposalA.GetStatus() == proposalB.GetStatus() && proposalA.GetStatus() == proposalB.GetStatus() &&
proposalA.GetTallyResult().Equals(proposalB.GetTallyResult()) && proposalA.GetTallyResult().Equals(proposalB.GetTallyResult()) &&
proposalA.GetSubmitTime().Equal(proposalB.GetSubmitTime()) && proposalA.GetSubmitTime().Equal(proposalB.GetSubmitTime()) &&
proposalA.GetDepositEndTime().Equal(proposalB.GetDepositEndTime()) &&
proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) && proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) &&
proposalA.GetVotingStartTime().Equal(proposalB.GetVotingStartTime()) { proposalA.GetVotingStartTime().Equal(proposalB.GetVotingStartTime()) &&
proposalA.GetVotingEndTime().Equal(proposalB.GetVotingEndTime()) {
return true return true
} }
return false return false
@ -60,7 +68,7 @@ func ProposalEqual(proposalA Proposal, proposalB Proposal) bool {
//----------------------------------------------------------- //-----------------------------------------------------------
// Text Proposals // Text Proposals
type TextProposal struct { type TextProposal struct {
ProposalID int64 `json:"proposal_id"` // ID of the proposal ProposalID uint64 `json:"proposal_id"` // ID of the proposal
Title string `json:"title"` // Title of the proposal Title string `json:"title"` // Title of the proposal
Description string `json:"description"` // Description of the proposal Description string `json:"description"` // Description of the proposal
ProposalType ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal} ProposalType ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
@ -68,18 +76,20 @@ type TextProposal struct {
Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected} Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected}
TallyResult TallyResult `json:"tally_result"` // Result of Tallys TallyResult TallyResult `json:"tally_result"` // Result of Tallys
SubmitTime time.Time `json:"submit_time"` // Height of the block where TxGovSubmitProposal was included SubmitTime time.Time `json:"submit_time"` // Time of the block where TxGovSubmitProposal was included
DepositEndTime time.Time `json:"deposit_end_time"` // Time that the Proposal would expire if deposit amount isn't met
TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit
VotingStartTime time.Time `json:"voting_start_time"` // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached VotingStartTime time.Time `json:"voting_start_time"` // Time of the block where MinDeposit was reached. -1 if MinDeposit is not reached
VotingEndTime time.Time `json:"voting_end_time"` // Time that the VotingPeriod for this proposal will end and votes will be tallied
} }
// Implements Proposal Interface // Implements Proposal Interface
var _ Proposal = (*TextProposal)(nil) var _ Proposal = (*TextProposal)(nil)
// nolint // nolint
func (tp TextProposal) GetProposalID() int64 { return tp.ProposalID } func (tp TextProposal) GetProposalID() uint64 { return tp.ProposalID }
func (tp *TextProposal) SetProposalID(proposalID int64) { tp.ProposalID = proposalID } func (tp *TextProposal) SetProposalID(proposalID uint64) { tp.ProposalID = proposalID }
func (tp TextProposal) GetTitle() string { return tp.Title } func (tp TextProposal) GetTitle() string { return tp.Title }
func (tp *TextProposal) SetTitle(title string) { tp.Title = title } func (tp *TextProposal) SetTitle(title string) { tp.Title = title }
func (tp TextProposal) GetDescription() string { return tp.Description } func (tp TextProposal) GetDescription() string { return tp.Description }
@ -92,16 +102,24 @@ func (tp TextProposal) GetTallyResult() TallyResult { return tp.T
func (tp *TextProposal) SetTallyResult(tallyResult TallyResult) { tp.TallyResult = tallyResult } func (tp *TextProposal) SetTallyResult(tallyResult TallyResult) { tp.TallyResult = tallyResult }
func (tp TextProposal) GetSubmitTime() time.Time { return tp.SubmitTime } func (tp TextProposal) GetSubmitTime() time.Time { return tp.SubmitTime }
func (tp *TextProposal) SetSubmitTime(submitTime time.Time) { tp.SubmitTime = submitTime } func (tp *TextProposal) SetSubmitTime(submitTime time.Time) { tp.SubmitTime = submitTime }
func (tp TextProposal) GetDepositEndTime() time.Time { return tp.DepositEndTime }
func (tp *TextProposal) SetDepositEndTime(depositEndTime time.Time) {
tp.DepositEndTime = depositEndTime
}
func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit } func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit }
func (tp *TextProposal) SetTotalDeposit(totalDeposit sdk.Coins) { tp.TotalDeposit = totalDeposit } func (tp *TextProposal) SetTotalDeposit(totalDeposit sdk.Coins) { tp.TotalDeposit = totalDeposit }
func (tp TextProposal) GetVotingStartTime() time.Time { return tp.VotingStartTime } func (tp TextProposal) GetVotingStartTime() time.Time { return tp.VotingStartTime }
func (tp *TextProposal) SetVotingStartTime(votingStartTime time.Time) { func (tp *TextProposal) SetVotingStartTime(votingStartTime time.Time) {
tp.VotingStartTime = votingStartTime tp.VotingStartTime = votingStartTime
} }
func (tp TextProposal) GetVotingEndTime() time.Time { return tp.VotingEndTime }
func (tp *TextProposal) SetVotingEndTime(votingEndTime time.Time) {
tp.VotingEndTime = votingEndTime
}
//----------------------------------------------------------- //-----------------------------------------------------------
// ProposalQueue // ProposalQueue
type ProposalQueue []int64 type ProposalQueue []uint64
//----------------------------------------------------------- //-----------------------------------------------------------
// ProposalKind // ProposalKind

View File

@ -42,7 +42,7 @@ func NewQuerier(keeper Keeper) sdk.Querier {
// Params for query 'custom/gov/proposal' // Params for query 'custom/gov/proposal'
type QueryProposalParams struct { type QueryProposalParams struct {
ProposalID int64 ProposalID uint64
} }
// nolint: unparam // nolint: unparam
@ -67,7 +67,7 @@ func queryProposal(ctx sdk.Context, path []string, req abci.RequestQuery, keeper
// Params for query 'custom/gov/deposit' // Params for query 'custom/gov/deposit'
type QueryDepositParams struct { type QueryDepositParams struct {
ProposalID int64 ProposalID uint64
Depositer sdk.AccAddress Depositer sdk.AccAddress
} }
@ -89,7 +89,7 @@ func queryDeposit(ctx sdk.Context, path []string, req abci.RequestQuery, keeper
// Params for query 'custom/gov/vote' // Params for query 'custom/gov/vote'
type QueryVoteParams struct { type QueryVoteParams struct {
ProposalID int64 ProposalID uint64
Voter sdk.AccAddress Voter sdk.AccAddress
} }
@ -111,7 +111,7 @@ func queryVote(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Kee
// Params for query 'custom/gov/deposits' // Params for query 'custom/gov/deposits'
type QueryDepositsParams struct { type QueryDepositsParams struct {
ProposalID int64 ProposalID uint64
} }
// nolint: unparam // nolint: unparam
@ -139,7 +139,7 @@ func queryDeposits(ctx sdk.Context, path []string, req abci.RequestQuery, keeper
// Params for query 'custom/gov/votes' // Params for query 'custom/gov/votes'
type QueryVotesParams struct { type QueryVotesParams struct {
ProposalID int64 ProposalID uint64
} }
// nolint: unparam // nolint: unparam
@ -171,7 +171,7 @@ type QueryProposalsParams struct {
Voter sdk.AccAddress Voter sdk.AccAddress
Depositer sdk.AccAddress Depositer sdk.AccAddress
ProposalStatus ProposalStatus ProposalStatus ProposalStatus
NumLatestProposals int64 Limit uint64
} }
// nolint: unparam // nolint: unparam
@ -182,7 +182,7 @@ func queryProposals(ctx sdk.Context, path []string, req abci.RequestQuery, keepe
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err2.Error())) return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err2.Error()))
} }
proposals := keeper.GetProposalsFiltered(ctx, params.Voter, params.Depositer, params.ProposalStatus, params.NumLatestProposals) proposals := keeper.GetProposalsFiltered(ctx, params.Voter, params.Depositer, params.ProposalStatus, params.Limit)
bz, err2 := codec.MarshalJSONIndent(keeper.cdc, proposals) bz, err2 := codec.MarshalJSONIndent(keeper.cdc, proposals)
if err2 != nil { if err2 != nil {
@ -193,19 +193,21 @@ func queryProposals(ctx sdk.Context, path []string, req abci.RequestQuery, keepe
// Params for query 'custom/gov/tally' // Params for query 'custom/gov/tally'
type QueryTallyParams struct { type QueryTallyParams struct {
ProposalID int64 ProposalID uint64
} }
// nolint: unparam // nolint: unparam
func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { func queryTally(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
// TODO: Dependant on #1914 // TODO: Dependant on #1914
var proposalID int64 var params QueryTallyParams
err2 := keeper.cdc.UnmarshalJSON(req.Data, proposalID) err2 := keeper.cdc.UnmarshalJSON(req.Data, &params)
if err2 != nil { if err2 != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err2.Error())) return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err2.Error()))
} }
proposalID := params.ProposalID
proposal := keeper.GetProposal(ctx, proposalID) proposal := keeper.GetProposal(ctx, proposalID)
if proposal == nil { if proposal == nil {
return nil, ErrUnknownProposal(DefaultCodespace, proposalID) return nil, ErrUnknownProposal(DefaultCodespace, proposalID)

View File

@ -50,7 +50,7 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
action, ok := simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event) action, ok := simulateHandleMsgSubmitProposal(msg, handler, ctx, event)
// don't schedule votes if proposal failed // don't schedule votes if proposal failed
if !ok { if !ok {
return action, nil, nil return action, nil, nil
@ -64,11 +64,11 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
whoVotes := r.Perm(len(accs)) whoVotes := r.Perm(len(accs))
// didntVote := whoVotes[numVotes:] // didntVote := whoVotes[numVotes:]
whoVotes = whoVotes[:numVotes] whoVotes = whoVotes[:numVotes]
votingPeriod := k.GetVotingProcedure(ctx).VotingPeriod votingPeriod := k.GetVotingParams(ctx).VotingPeriod
fops := make([]simulation.FutureOperation, numVotes+1) fops := make([]simulation.FutureOperation, numVotes+1)
for i := 0; i < numVotes; i++ { for i := 0; i < numVotes; i++ {
whenVote := ctx.BlockHeader().Time.Add(time.Duration(r.Int63n(int64(votingPeriod.Seconds()))) * time.Second) whenVote := ctx.BlockHeader().Time.Add(time.Duration(r.Int63n(int64(votingPeriod.Seconds()))) * time.Second)
fops[i] = simulation.FutureOperation{BlockTime: whenVote, Op: operationSimulateMsgVote(k, sk, accs[whoVotes[i]], proposalID)} fops[i] = simulation.FutureOperation{BlockTime: whenVote, Op: operationSimulateMsgVote(k, accs[whoVotes[i]], proposalID)}
} }
// 3) Make an operation to ensure slashes were done correctly. (Really should be a future invariant) // 3) Make an operation to ensure slashes were done correctly. (Really should be a future invariant)
// TODO: Find a way to check if a validator was slashed other than just checking their balance a block // TODO: Find a way to check if a validator was slashed other than just checking their balance a block
@ -80,7 +80,7 @@ func SimulateSubmittingVotingAndSlashingForProposal(k gov.Keeper, sk stake.Keepe
// SimulateMsgSubmitProposal simulates a msg Submit Proposal // SimulateMsgSubmitProposal simulates a msg Submit Proposal
// Note: Currently doesn't ensure that the proposal txt is in JSON form // Note: Currently doesn't ensure that the proposal txt is in JSON form
func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operation { func SimulateMsgSubmitProposal(k gov.Keeper) simulation.Operation {
handler := gov.NewHandler(k) handler := gov.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOps []simulation.FutureOperation, err error) { return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOps []simulation.FutureOperation, err error) {
sender := simulation.RandomAcc(r, accs) sender := simulation.RandomAcc(r, accs)
@ -88,22 +88,14 @@ func SimulateMsgSubmitProposal(k gov.Keeper, sk stake.Keeper) simulation.Operati
if err != nil { if err != nil {
return "", nil, err return "", nil, err
} }
action, _ = simulateHandleMsgSubmitProposal(msg, sk, handler, ctx, event) action, _ = simulateHandleMsgSubmitProposal(msg, handler, ctx, event)
return action, nil, nil return action, nil, nil
} }
} }
func simulateHandleMsgSubmitProposal(msg gov.MsgSubmitProposal, sk stake.Keeper, handler sdk.Handler, ctx sdk.Context, event func(string)) (action string, ok bool) { func simulateHandleMsgSubmitProposal(msg gov.MsgSubmitProposal, handler sdk.Handler, ctx sdk.Context, event func(string)) (action string, ok bool) {
ctx, write := ctx.CacheContext() ctx, _ = ctx.CacheContext()
result := handler(ctx, msg) handler(ctx, msg)
ok = result.IsOK()
if ok {
// Update pool to keep invariants
pool := sk.GetPool(ctx)
pool.LooseTokens = pool.LooseTokens.Sub(sdk.NewDecFromInt(msg.InitialDeposit.AmountOf(denom)))
sk.SetPool(ctx, pool)
write()
}
event(fmt.Sprintf("gov/MsgSubmitProposal/%v", ok)) event(fmt.Sprintf("gov/MsgSubmitProposal/%v", ok))
action = fmt.Sprintf("TestMsgSubmitProposal: ok %v, msg %s", ok, msg.GetSignBytes()) action = fmt.Sprintf("TestMsgSubmitProposal: ok %v, msg %s", ok, msg.GetSignBytes())
return return
@ -125,7 +117,7 @@ func simulationCreateMsgSubmitProposal(r *rand.Rand, sender simulation.Account)
} }
// SimulateMsgDeposit // SimulateMsgDeposit
func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation { func SimulateMsgDeposit(k gov.Keeper) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
acc := simulation.RandomAcc(r, accs) acc := simulation.RandomAcc(r, accs)
proposalID, ok := randomProposalID(r, k, ctx) proposalID, ok := randomProposalID(r, k, ctx)
@ -137,15 +129,8 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
if msg.ValidateBasic() != nil { if msg.ValidateBasic() != nil {
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes()) return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
} }
ctx, write := ctx.CacheContext() ctx, _ = ctx.CacheContext()
result := gov.NewHandler(k)(ctx, msg) result := gov.NewHandler(k)(ctx, msg)
if result.IsOK() {
// Update pool to keep invariants
pool := sk.GetPool(ctx)
pool.LooseTokens = pool.LooseTokens.Sub(sdk.NewDecFromInt(deposit.AmountOf(denom)))
sk.SetPool(ctx, pool)
write()
}
event(fmt.Sprintf("gov/MsgDeposit/%v", result.IsOK())) event(fmt.Sprintf("gov/MsgDeposit/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgDeposit: ok %v, msg %s", result.IsOK(), msg.GetSignBytes()) action = fmt.Sprintf("TestMsgDeposit: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil, nil return action, nil, nil
@ -154,12 +139,12 @@ func SimulateMsgDeposit(k gov.Keeper, sk stake.Keeper) simulation.Operation {
// SimulateMsgVote // SimulateMsgVote
// nolint: unparam // nolint: unparam
func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation { func SimulateMsgVote(k gov.Keeper) simulation.Operation {
return operationSimulateMsgVote(k, sk, simulation.Account{}, -1) return operationSimulateMsgVote(k, simulation.Account{}, 0)
} }
// nolint: unparam // nolint: unparam
func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, acc simulation.Account, proposalID int64) simulation.Operation { func operationSimulateMsgVote(k gov.Keeper, acc simulation.Account, proposalID uint64) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) { return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
if acc.Equals(simulation.Account{}) { if acc.Equals(simulation.Account{}) {
acc = simulation.RandomAcc(r, accs) acc = simulation.RandomAcc(r, accs)
@ -200,12 +185,12 @@ func randomDeposit(r *rand.Rand) sdk.Coins {
} }
// Pick a random proposal ID // Pick a random proposal ID
func randomProposalID(r *rand.Rand, k gov.Keeper, ctx sdk.Context) (proposalID int64, ok bool) { func randomProposalID(r *rand.Rand, k gov.Keeper, ctx sdk.Context) (proposalID uint64, ok bool) {
lastProposalID := k.GetLastProposalID(ctx) lastProposalID := k.GetLastProposalID(ctx)
if lastProposalID < 1 { if lastProposalID < 1 {
return 0, false return 0, false
} }
proposalID = int64(r.Intn(int(lastProposalID))) proposalID = uint64(r.Intn(int(lastProposalID)))
return proposalID, true return proposalID, true
} }

View File

@ -59,9 +59,9 @@ func TestGovWithRandomMessages(t *testing.T) {
simulation.Simulate( simulation.Simulate(
t, mapp.BaseApp, appStateFn, t, mapp.BaseApp, appStateFn,
[]simulation.WeightedOperation{ []simulation.WeightedOperation{
{2, SimulateMsgSubmitProposal(govKeeper, stakeKeeper)}, {2, SimulateMsgSubmitProposal(govKeeper)},
{3, SimulateMsgDeposit(govKeeper, stakeKeeper)}, {3, SimulateMsgDeposit(govKeeper)},
{20, SimulateMsgVote(govKeeper, stakeKeeper)}, {20, SimulateMsgVote(govKeeper)},
}, []simulation.RandSetup{ }, []simulation.RandSetup{
setup, setup,
}, []simulation.Invariant{ }, []simulation.Invariant{
@ -75,7 +75,7 @@ func TestGovWithRandomMessages(t *testing.T) {
t, mapp.BaseApp, appStateFn, t, mapp.BaseApp, appStateFn,
[]simulation.WeightedOperation{ []simulation.WeightedOperation{
{10, SimulateSubmittingVotingAndSlashingForProposal(govKeeper, stakeKeeper)}, {10, SimulateSubmittingVotingAndSlashingForProposal(govKeeper, stakeKeeper)},
{5, SimulateMsgDeposit(govKeeper, stakeKeeper)}, {5, SimulateMsgDeposit(govKeeper)},
}, []simulation.RandSetup{ }, []simulation.RandSetup{
setup, setup,
}, []simulation.Invariant{ }, []simulation.Invariant{

View File

@ -84,7 +84,7 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
totalVotingPower = totalVotingPower.Add(votingPower) totalVotingPower = totalVotingPower.Add(votingPower)
} }
tallyingProcedure := keeper.GetTallyingProcedure(ctx) tallyParams := keeper.GetTallyParams(ctx)
tallyResults = TallyResult{ tallyResults = TallyResult{
Yes: results[OptionYes], Yes: results[OptionYes],
@ -98,11 +98,11 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tall
return false, tallyResults return false, tallyResults
} }
// If more than 1/3 of voters veto, proposal fails // If more than 1/3 of voters veto, proposal fails
if results[OptionNoWithVeto].Quo(totalVotingPower).GT(tallyingProcedure.Veto) { if results[OptionNoWithVeto].Quo(totalVotingPower).GT(tallyParams.Veto) {
return false, tallyResults return false, tallyResults
} }
// If more than 1/2 of non-abstaining voters vote Yes, proposal passes // If more than 1/2 of non-abstaining voters vote Yes, proposal passes
if results[OptionYes].Quo(totalVotingPower.Sub(results[OptionAbstain])).GT(tallyingProcedure.Threshold) { if results[OptionYes].Quo(totalVotingPower.Sub(results[OptionAbstain])).GT(tallyParams.Threshold) {
return true, tallyResults return true, tallyResults
} }
// If more than 1/2 of non-abstaining voters vote No, proposal fails // If more than 1/2 of non-abstaining voters vote No, proposal fails