github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/gov/spec/02_state.md (about) 1 <!-- 2 order: 2 3 --> 4 5 # State 6 7 ## Parameters and base types 8 9 `Parameters` define the rules according to which votes are run. There can only 10 be one active parameter set at any given time. If governance wants to change a 11 parameter set, either to modify a value or add/remove a parameter field, a new 12 parameter set has to be created and the previous one rendered inactive. 13 14 ```go 15 type DepositParams struct { 16 MinDeposit sdk.Coins // Minimum deposit for a proposal to enter voting period. 17 MaxDepositPeriod time.Time // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months 18 } 19 ``` 20 21 ```go 22 type VotingParams struct { 23 VotingPeriod time.Time // Length of the voting period. Initial value: 2 weeks 24 } 25 ``` 26 27 ```go 28 type TallyParams struct { 29 Quorum sdk.Dec // Minimum percentage of stake that needs to vote for a proposal to be considered valid 30 Threshold sdk.Dec // Minimum proportion of Yes votes for proposal to pass. Initial value: 0.5 31 Veto sdk.Dec // Minimum proportion of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 32 } 33 ``` 34 35 Parameters are stored in a global `GlobalParams` KVStore. 36 37 Additionally, we introduce some basic types: 38 39 ```go 40 type Vote byte 41 42 const ( 43 VoteYes = 0x1 44 VoteNo = 0x2 45 VoteNoWithVeto = 0x3 46 VoteAbstain = 0x4 47 ) 48 49 type ProposalType string 50 51 const ( 52 ProposalTypePlainText = "Text" 53 ProposalTypeSoftwareUpgrade = "SoftwareUpgrade" 54 ) 55 56 type ProposalStatus byte 57 58 59 const ( 60 StatusNil ProposalStatus = 0x00 61 StatusDepositPeriod ProposalStatus = 0x01 // Proposal is submitted. Participants can deposit on it but not vote 62 StatusVotingPeriod ProposalStatus = 0x02 // MinDeposit is reached, participants can vote 63 StatusPassed ProposalStatus = 0x03 // Proposal passed and successfully executed 64 StatusRejected ProposalStatus = 0x04 // Proposal has been rejected 65 StatusFailed ProposalStatus = 0x05 // Proposal passed but failed execution 66 ) 67 ``` 68 69 ## Deposit 70 71 ```go 72 type Deposit struct { 73 Amount sdk.Coins // Amount of coins deposited by depositor 74 Depositor crypto.address // Address of depositor 75 } 76 ``` 77 78 ## ValidatorGovInfo 79 80 This type is used in a temp map when tallying 81 82 ```go 83 type ValidatorGovInfo struct { 84 Minus sdk.Dec 85 Vote Vote 86 } 87 ``` 88 89 ## Proposals 90 91 `Proposal` objects are used to account votes and generally track the proposal's state. They contain `Content` which denotes 92 what this proposal is about, and other fields, which are the mutable state of 93 the governance process. 94 95 ```go 96 type Proposal struct { 97 Content // Proposal content interface 98 99 ProposalID uint64 100 Status ProposalStatus // Status of the Proposal {Pending, Active, Passed, Rejected} 101 FinalTallyResult TallyResult // Result of Tallies 102 103 SubmitTime time.Time // Time of the block where TxGovSubmitProposal was included 104 DepositEndTime time.Time // Time that the Proposal would expire if deposit amount isn't met 105 TotalDeposit sdk.Coins // Current deposit on this proposal. Initial value is set at InitialDeposit 106 107 VotingStartTime time.Time // Time of the block where MinDeposit was reached. -1 if MinDeposit is not reached 108 VotingEndTime time.Time // Time that the VotingPeriod for this proposal will end and votes will be tallied 109 } 110 ``` 111 112 ```go 113 type Content interface { 114 GetTitle() string 115 GetDescription() string 116 ProposalRoute() string 117 ProposalType() string 118 ValidateBasic() sdk.Error 119 String() string 120 } 121 ``` 122 123 The `Content` on a proposal is an interface which contains the information about 124 the `Proposal` such as the tile, description, and any notable changes. Also, this 125 `Content` type can by implemented by any module. The `Content`'s `ProposalRoute` 126 returns a string which must be used to route the `Content`'s `Handler` in the 127 governance keeper. This allows the governance keeper to execute proposal logic 128 implemented by any module. If a proposal passes, the handler is executed. Only 129 if the handler is successful does the state get persisted and the proposal finally 130 passes. Otherwise, the proposal is rejected. 131 132 ```go 133 type Handler func(ctx sdk.Context, content Content) sdk.Error 134 ``` 135 136 The `Handler` is responsible for actually executing the proposal and processing 137 any state changes specified by the proposal. It is executed only if a proposal 138 passes during `EndBlock`. 139 140 We also mention a method to update the tally for a given proposal: 141 142 ```go 143 func (proposal Proposal) updateTally(vote byte, amount sdk.Dec) 144 ``` 145 146 ## Stores 147 148 *Stores are KVStores in the multi-store. The key to find the store is the first 149 parameter in the list*` 150 151 We will use one KVStore `Governance` to store two mappings: 152 153 * A mapping from `proposalID|'proposal'` to `Proposal`. 154 * A mapping from `proposalID|'addresses'|address` to `Vote`. This mapping allows 155 us to query all addresses that voted on the proposal along with their vote by 156 doing a range query on `proposalID:addresses`. 157 158 159 For pseudocode purposes, here are the two function we will use to read or write in stores: 160 161 * `load(StoreKey, Key)`: Retrieve item stored at key `Key` in store found at key `StoreKey` in the multistore 162 * `store(StoreKey, Key, value)`: Write value `Value` at key `Key` in store found at key `StoreKey` in the multistore 163 164 ## Proposal Processing Queue 165 166 **Store:** 167 * `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the 168 `ProposalIDs` of proposals that reached `MinDeposit`. During each `EndBlock`, 169 all the proposals that have reached the end of their voting period are processed. 170 To process a finished proposal, the application tallies the votes, computes the 171 votes of each validator and checks if every validator in the validator set has 172 voted. If the proposal is accepted, deposits are refunded. Finally, the proposal 173 content `Handler` is executed. 174 175 And the pseudocode for the `ProposalProcessingQueue`: 176 177 ```go 178 in EndBlock do 179 180 for finishedProposalID in GetAllFinishedProposalIDs(block.Time) 181 proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key 182 183 validators = Keeper.getAllValidators() 184 tmpValMap := map(sdk.AccAddress)ValidatorGovInfo 185 186 // Initiate mapping at 0. This is the amount of shares of the validator's vote that will be overridden by their delegator's votes 187 for each validator in validators 188 tmpValMap(validator.OperatorAddr).Minus = 0 189 190 // Tally 191 voterIterator = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal 192 for each (voterAddress, vote) in voterIterator 193 delegations = stakingKeeper.getDelegations(voterAddress) // get all delegations for current voter 194 195 for each delegation in delegations 196 // make sure delegation.Shares does NOT include shares being unbonded 197 tmpValMap(delegation.ValidatorAddr).Minus += delegation.Shares 198 proposal.updateTally(vote, delegation.Shares) 199 200 _, isVal = stakingKeeper.getValidator(voterAddress) 201 if (isVal) 202 tmpValMap(voterAddress).Vote = vote 203 204 tallyingParam = load(GlobalParams, 'TallyingParam') 205 206 // Update tally if validator voted they voted 207 for each validator in validators 208 if tmpValMap(validator).HasVoted 209 proposal.updateTally(tmpValMap(validator).Vote, (validator.TotalShares - tmpValMap(validator).Minus)) 210 211 212 213 // Check if proposal is accepted or rejected 214 totalNonAbstain := proposal.YesVotes + proposal.NoVotes + proposal.NoWithVetoVotes 215 if (proposal.Votes.YesVotes/totalNonAbstain > tallyingParam.Threshold AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < tallyingParam.Veto) 216 // proposal was accepted at the end of the voting period 217 // refund deposits (non-voters already punished) 218 for each (amount, depositor) in proposal.Deposits 219 depositor.AtomBalance += amount 220 221 stateWriter, err := proposal.Handler() 222 if err != nil 223 // proposal passed but failed during state execution 224 proposal.CurrentStatus = ProposalStatusFailed 225 else 226 // proposal pass and state is persisted 227 proposal.CurrentStatus = ProposalStatusAccepted 228 stateWriter.save() 229 else 230 // proposal was rejected 231 proposal.CurrentStatus = ProposalStatusRejected 232 233 store(Governance, <proposalID|'proposal'>, proposal) 234 ```