cosmos-sdk/docs/spec/governance/state.md

198 lines
7.2 KiB
Markdown
Raw Normal View History

2018-02-26 07:35:09 -08:00
# Implementation (1/2)
## State
2018-06-04 08:22:38 -07:00
### Procedures and base types
2018-02-26 07:35:09 -08:00
`Procedures` define the rule according to which votes are run. There can only
be one active procedure at any given time. If governance wants to change a
procedure, either to modify a value or add/remove a parameter, a new procedure
has to be created and the previous one rendered inactive.
2018-06-04 08:22:38 -07:00
```go
2018-06-07 03:02:21 -07:00
type DepositProcedure struct {
2018-06-04 08:22:38 -07:00
MinDeposit sdk.Coins // Minimum deposit for a proposal to enter voting period.
MaxDepositPeriod time.Time // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
2018-06-04 08:22:38 -07:00
}
```
2018-06-07 03:02:21 -07:00
```go
type VotingProcedure struct {
VotingPeriod time.Time // Length of the voting period. Initial value: 2 weeks
2018-06-07 03:02:21 -07:00
}
```
```go
type TallyingProcedure struct {
Threshold sdk.Dec // Minimum propotion of Yes votes for proposal to pass. Initial value: 0.5
Veto sdk.Dec // Minimum proportion of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
GovernancePenalty sdk.Dec // Penalty if validator does not vote
2018-06-07 03:02:21 -07:00
}
```
Procedures are stored in a global `GlobalParams` KVStore.
2018-06-04 08:22:38 -07:00
2018-06-07 03:02:21 -07:00
Additionally, we introduce some basic types:
2018-06-04 08:22:38 -07:00
2018-02-26 07:35:09 -08:00
```go
2018-05-08 12:31:34 -07:00
2018-06-04 08:20:07 -07:00
type Vote byte
2018-05-08 12:31:34 -07:00
const (
2018-06-04 08:20:07 -07:00
VoteYes = 0x1
VoteNo = 0x2
VoteNoWithVeto = 0x3
VoteAbstain = 0x4
2018-05-08 12:31:34 -07:00
)
type ProposalType byte
const (
2018-06-15 07:18:50 -07:00
ProposalTypePlainText = 0x1 // Plain text proposals
ProposalTypeSoftwareUpgrade = 0x2 // Text proposal inducing a software upgrade
2018-06-04 08:20:07 -07:00
)
type ProposalStatus byte
2018-05-08 12:31:34 -07:00
2018-02-26 07:35:09 -08:00
2018-06-04 08:20:07 -07:00
const (
ProposalStatusOpen = 0x1 // Proposal is submitted. Participants can deposit on it but not vote
ProposalStatusActive = 0x2 // MinDeposit is reachhed, participants can vote
ProposalStatusAccepted = 0x3 // Proposal has been accepted
ProposalStatusRejected = 0x4 // Proposal has been rejected
2018-06-05 07:43:56 -07:00
ProposalStatusClosed. = 0x5 // Proposal never reached MinDeposit
2018-05-08 12:31:34 -07:00
)
2018-02-26 07:35:09 -08:00
```
### Deposit
```go
type Deposit struct {
2018-05-08 12:31:34 -07:00
Amount sdk.Coins // Amount of coins deposited by depositer
Depositer crypto.address // Address of depositer
}
```
2018-06-04 08:20:07 -07:00
### ValidatorGovInfo
This type is used in a temp map when tallying
```go
2018-06-04 08:20:07 -07:00
type ValidatorGovInfo struct {
Minus sdk.Dec
2018-06-04 08:20:07 -07:00
Vote Vote
}
```
2018-02-26 07:35:09 -08:00
### Proposals
2018-05-08 12:31:34 -07:00
`Proposals` are an item to be voted on.
2018-02-26 07:35:09 -08:00
```go
type Proposal struct {
Title string // Title of the proposal
Description string // Description of the proposal
2018-05-08 12:31:34 -07:00
Type ProposalType // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}
TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit
Deposits []Deposit // List of deposits on the proposal
SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included
DepositEndTime time.Time // Time that the DepositPeriod of a proposal would expire
Submitter sdk.AccAddress // Address of the submitter
2018-02-26 07:35:09 -08:00
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.
2018-06-04 08:20:07 -07:00
CurrentStatus ProposalStatus // Current status of the proposal
YesVotes sdk.Dec
NoVotes sdk.Dec
NoWithVetoVotes sdk.Dec
AbstainVotes sdk.Dec
2018-02-26 07:35:09 -08:00
}
```
2018-06-04 08:20:07 -07:00
We also mention a method to update the tally for a given proposal:
2018-02-26 07:35:09 -08:00
```go
func (proposal Proposal) updateTally(vote byte, amount sdk.Dec)
2018-02-26 07:35:09 -08:00
```
2018-02-26 08:28:57 -08:00
### Stores
2018-06-04 08:20:07 -07:00
*Stores are KVStores in the multistore. The key to find the store is the first parameter in the list*`
We will use one KVStore `Governance` to store two mappings:
2018-02-26 07:35:09 -08:00
2018-06-05 07:43:56 -07:00
* 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`
2018-02-26 07:35:09 -08:00
2018-02-26 08:28:57 -08:00
For pseudocode purposes, here are the two function we will use to read or write in stores:
* `load(StoreKey, Key)`: Retrieve item stored at key `Key` in store found at key `StoreKey` in the multistore
* `store(StoreKey, Key, value)`: Write value `Value` at key `Key` in store found at key `StoreKey` in the multistore
2018-02-26 07:35:09 -08:00
### Proposal Processing Queue
**Store:**
* `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the
`ProposalIDs` of proposals that reached `MinDeposit`. Each `EndBlock`, all the proposals
that have reached the end of their voting period are processed.
To process a finished proposal, the application tallies the votes, compute the votes of
each validator and checks if every validator in the valdiator set have voted.
If the proposal is accepted, deposits are refunded.
2018-02-26 07:35:09 -08:00
And the pseudocode for the `ProposalProcessingQueue`:
```go
2018-06-04 08:20:07 -07:00
in EndBlock do
2018-02-26 07:35:09 -08:00
for finishedProposalID in GetAllFinishedProposalIDs(block.Time)
proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key
2018-02-26 07:35:09 -08:00
validators = Keeper.getAllValidators()
tmpValMap := map(sdk.AccAddress)ValidatorGovInfo
2018-06-15 07:18:50 -07:00
// Initiate mapping at 0. This is the amount of shares of the validator's vote that will be overridden by their delegator's votes
2018-06-04 08:20:07 -07:00
for each validator in validators
tmpValMap(validator.OperatorAddr).Minus = 0
2018-06-04 08:20:07 -07:00
// Tally
2018-06-05 07:43:56 -07:00
voterIterator = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal
2018-06-04 08:20:07 -07:00
for each (voterAddress, vote) in voterIterator
delegations = stakeKeeper.getDelegations(voterAddress) // get all delegations for current voter
for each delegation in delegations
2018-06-07 03:02:21 -07:00
// make sure delegation.Shares does NOT include shares being unbonded
2018-06-04 08:20:07 -07:00
tmpValMap(delegation.ValidatorAddr).Minus += delegation.Shares
proposal.updateTally(vote, delegation.Shares)
_, isVal = stakeKeeper.getValidator(voterAddress)
if (isVal)
2018-06-15 07:18:50 -07:00
tmpValMap(voterAddress).Vote = vote
2018-06-04 08:34:31 -07:00
2018-06-15 07:18:50 -07:00
tallyingProcedure = load(GlobalParams, 'TallyingProcedure')
2018-06-04 08:34:31 -07:00
// Update tally if validator voted they voted
2018-06-04 08:20:07 -07:00
for each validator in validators
if tmpValMap(validator).HasVoted
proposal.updateTally(tmpValMap(validator).Vote, (validator.TotalShares - tmpValMap(validator).Minus))
2018-06-04 08:20:07 -07:00
2018-06-04 08:34:31 -07:00
2018-06-04 08:20:07 -07:00
// Check if proposal is accepted or rejected
totalNonAbstain := proposal.YesVotes + proposal.NoVotes + proposal.NoWithVetoVotes
2018-06-15 07:18:50 -07:00
if (proposal.Votes.YesVotes/totalNonAbstain > tallyingProcedure.Threshold AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < tallyingProcedure.Veto)
// proposal was accepted at the end of the voting period
2018-05-08 12:31:34 -07:00
// refund deposits (non-voters already punished)
2018-06-04 08:20:07 -07:00
proposal.CurrentStatus = ProposalStatusAccepted
for each (amount, depositer) in proposal.Deposits
depositer.AtomBalance += amount
2018-06-04 08:20:07 -07:00
else
// proposal was rejected
proposal.CurrentStatus = ProposalStatusRejected
2018-06-05 07:43:56 -07:00
store(Governance, <proposalID|'proposal'>, proposal)
2018-05-08 12:31:34 -07:00
```