diff --git a/docs/spec/governance/state.md b/docs/spec/governance/state.md index eb23a1158..0e00bb971 100644 --- a/docs/spec/governance/state.md +++ b/docs/spec/governance/state.md @@ -52,6 +52,7 @@ const ( ProposalStatusActive = 0x2 // MinDeposit is reachhed, participants can vote ProposalStatusAccepted = 0x3 // Proposal has been accepted ProposalStatusRejected = 0x4 // Proposal has been rejected + ProposalStatusClosed. = 0x5 // Proposal never reached MinDeposit ) ``` @@ -90,7 +91,6 @@ type Proposal struct { Submitter sdk.Address // Address of the submitter VotingStartBlock int64 // Height of the block where MinDeposit was reached. -1 if MinDeposit is not reached - InitProcedure Procedure // Active Procedure when proposal enters voting period CurrentStatus ProposalStatus // Current status of the proposal YesVotes sdk.Rat @@ -112,8 +112,8 @@ We also mention a method to update the tally for a given proposal: We will use one KVStore `Governance` to store two mappings: -* A mapping from `proposalID` to `Proposal` -* A mapping from `proposalID:addresses:address` to `Vote`. This mapping allows us to query all addresses that voted on the proposal along with their vote by doing a range query on `proposalID:addresses` +* A mapping from `proposalID|'proposal'` to `Proposal` +* A mapping from `proposalID|'addresses'|address` to `Vote`. This mapping allows us to query all addresses that voted on the proposal along with their vote by doing a range query on `proposalID:addresses` For pseudocode purposes, here are the two function we will use to read or write in stores: @@ -127,7 +127,7 @@ For pseudocode purposes, here are the two function we will use to read or write * `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the `ProposalIDs` of proposals that reached `MinDeposit`. Each round, the oldest element of `ProposalProcessingQueue` is checked during `BeginBlock` to see if - `CurrentBlock == VotingStartBlock + InitProcedure.VotingPeriod`. If it is, + `CurrentBlock == VotingStartBlock + activeProcedure.VotingPeriod`. If it is, then the application tallies the votes, compute the votes of 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. After that proposal is ejected from `ProposalProcessingQueue` and the next element of the queue is evaluated. @@ -146,9 +146,10 @@ And the pseudocode for the `ProposalProcessingQueue`: if (proposalID == nil) return - proposal = load(Governance, proposalID) + proposal = load(Governance, ) // proposal is a const key + activeProcedure = load(params, 'ActiveProcedure') - if (CurrentBlock == proposal.VotingStartBlock + proposal.Procedure.VotingPeriod && proposal.CurrentStatus == ProposalStatusActive) + if (CurrentBlock == proposal.VotingStartBlock + activeProcedure.VotingPeriod && proposal.CurrentStatus == ProposalStatusActive) // End of voting period, tally @@ -163,7 +164,7 @@ And the pseudocode for the `ProposalProcessingQueue`: // Tally - voterIterator = rangeQuery(Governance, ) //return all the addresses that voted on the proposal + voterIterator = rangeQuery(Governance, ) //return all the addresses that voted on the proposal for each (voterAddress, vote) in voterIterator delegations = stakeKeeper.getDelegations(voterAddress) // get all delegations for current voter @@ -188,7 +189,7 @@ And the pseudocode for the `ProposalProcessingQueue`: // Check if proposal is accepted or rejected totalNonAbstain := proposal.YesVotes + proposal.NoVotes + proposal.NoWithVetoVotes - if (proposal.Votes.YesVotes/totalNonAbstain > proposal.InitProcedure.Threshold AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < proposal.InitProcedure.Veto) + if (proposal.Votes.YesVotes/totalNonAbstain > activeProcedure.Threshold AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < activeProcedure.Veto) // proposal was accepted at the end of the voting period // refund deposits (non-voters already punished) proposal.CurrentStatus = ProposalStatusAccepted @@ -199,6 +200,6 @@ And the pseudocode for the `ProposalProcessingQueue`: // proposal was rejected proposal.CurrentStatus = ProposalStatusRejected - store(Governance, proposalID, proposal) + store(Governance, , proposal) checkProposal() ``` diff --git a/docs/spec/governance/transactions.md b/docs/spec/governance/transactions.md index 25beb6d1a..f5c39230c 100644 --- a/docs/spec/governance/transactions.md +++ b/docs/spec/governance/transactions.md @@ -65,17 +65,15 @@ upon receiving txGovSubmitProposal from sender do // MinDeposit is not reached proposal.CurrentStatus = ProposalStatusOpen - proposal.VotingStartBlock = -1 else // MinDeposit is reached proposal.CurrentStatus = ProposalStatusActive proposal.VotingStartBlock = CurrentBlock - proposal.InitProcedure = activeProcedure ProposalProcessingQueue.push(proposalID) - store(Proposals, proposalID, proposal) // Store proposal in Proposals mapping + store(Proposals, , proposal) // Store proposal in Proposals mapping return proposalID ``` @@ -112,7 +110,7 @@ upon receiving txGovDeposit from sender do if !correctlyFormatted(txGovDeposit) throw - proposal = load(Proposals, txGovDeposit.ProposalID) + proposal = load(Proposals, ) // proposal is a const key, proposalID is variable if (proposal == nil) // There is no proposal for this proposalID @@ -120,29 +118,32 @@ upon receiving txGovDeposit from sender do activeProcedure = load(params, 'ActiveProcedure') - if (txGovDeposit.Deposit.Atoms <= 0) OR (sender.AtomBalance < txGovDeposit.Deposit.Atoms) OR (proposal.TotalDeposit >= activeProcedure.MinDeposit) OR (CurrentBlock >= proposal.SubmitBlock + activeProcedure.MaxDepositPeriod) + if (txGovDeposit.Deposit.Atoms <= 0) OR (sender.AtomBalance < txGovDeposit.Deposit.Atoms) OR (proposal.CurrentStatus != ProposalStatusOpen) + // deposit is negative or null // OR sender has insufficient funds - // OR minDeposit has already been reached - // OR Maximum deposit period reached + // OR proposal is not open for deposit anymore throw - - // sender can deposit - sender.AtomBalance -= txGovDeposit.Deposit.Atoms - proposal.Deposits.append({txGovVote.Deposit, sender}) - proposal.TotalDeposit.Plus(txGovDeposit.Deposit) - - if (proposal.TotalDeposit >= activeProcedure.MinDeposit) - // MinDeposit is reached, vote opens + if (CurrentBlock >= proposal.SubmitBlock + activeProcedure.MaxDepositPeriod) + proposal.CurrentStatus = ProposalStatusClosed + + else + // sender can deposit + sender.AtomBalance -= txGovDeposit.Deposit.Atoms + + proposal.Deposits.append({txGovVote.Deposit, sender}) + proposal.TotalDeposit.Plus(txGovDeposit.Deposit) - proposal.VotingStartBlock = CurrentBlock - proposal.CurrentStatus = ProposalStatusActive - proposal.InitProcedure = activeProcedure - ProposalProcessingQueue.push(txGovDeposit.ProposalID) + if (proposal.TotalDeposit >= activeProcedure.MinDeposit) + // MinDeposit is reached, vote opens + + proposal.VotingStartBlock = CurrentBlock + proposal.CurrentStatus = ProposalStatusActive + ProposalProcessingQueue.push(txGovDeposit.ProposalID) - store(Proposals, txGovVote.ProposalID, proposal) + store(Proposals, , proposal) ``` ### Vote @@ -153,7 +154,7 @@ vote on the proposal. ```go type TxGovVote struct { - ProposalID int64 // proposalID of the proposal + ProposalID int64 // proposalID of the proposal Vote byte // option from OptionSet chosen by the voter } ``` @@ -176,21 +177,18 @@ handled: if !correctlyFormatted(txGovDeposit) throw - proposal = load(Proposals, txGovDeposit.ProposalID) + proposal = load(Proposals, ) if (proposal == nil) // There is no proposal for this proposalID throw - if (proposal.VotingStartBlock >= 0) AND - (CurrentBlock <= proposal.VotingStartBlock + proposal.InitProcedure.VotingPeriod) + if (proposal.CurrentStatus == ProposalStatusActive) - // Sender can vote if - // Vote has started AND if - // Vote had notended + // Sender can vote - store(Governance, , txGovVote.Vote) // Voters can vote multiple times. Re-voting overrides previous vote. This is ok because tallying is done once at the end. + store(Governance, , txGovVote.Vote) // Voters can vote multiple times. Re-voting overrides previous vote. This is ok because tallying is done once at the end. ```