github.com/Finschia/finschia-sdk@v0.48.1/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 ### DepositParams 15 16 +++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/gov.proto#L127-L145 17 18 ### VotingParams 19 20 +++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/gov.proto#L147-L156 21 22 ### TallyParams 23 24 +++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/gov.proto#L158-L183 25 26 Parameters are stored in a global `GlobalParams` KVStore. 27 28 Additionally, we introduce some basic types: 29 30 ```go 31 type Vote byte 32 33 const ( 34 VoteYes = 0x1 35 VoteNo = 0x2 36 VoteNoWithVeto = 0x3 37 VoteAbstain = 0x4 38 ) 39 40 type ProposalType string 41 42 const ( 43 ProposalTypePlainText = "Text" 44 ProposalTypeSoftwareUpgrade = "SoftwareUpgrade" 45 ) 46 47 type ProposalStatus byte 48 49 50 const ( 51 StatusNil ProposalStatus = 0x00 52 StatusDepositPeriod ProposalStatus = 0x01 // Proposal is submitted. Participants can deposit on it but not vote 53 StatusVotingPeriod ProposalStatus = 0x02 // MinDeposit is reached, participants can vote 54 StatusPassed ProposalStatus = 0x03 // Proposal passed and successfully executed 55 StatusRejected ProposalStatus = 0x04 // Proposal has been rejected 56 StatusFailed ProposalStatus = 0x05 // Proposal passed but failed execution 57 ) 58 ``` 59 60 ## Deposit 61 62 +++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/gov.proto#L43-L53 63 64 ## ValidatorGovInfo 65 66 This type is used in a temp map when tallying 67 68 ```go 69 type ValidatorGovInfo struct { 70 Minus sdk.Dec 71 Vote Vote 72 } 73 ``` 74 75 ## Proposals 76 77 `Proposal` objects are used to account votes and generally track the proposal's state. They contain `Content` which denotes 78 what this proposal is about, and other fields, which are the mutable state of 79 the governance process. 80 81 +++ https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/gov/v1beta1/gov.proto#L55-L77 82 83 ```go 84 type Content interface { 85 GetTitle() string 86 GetDescription() string 87 ProposalRoute() string 88 ProposalType() string 89 ValidateBasic() sdk.Error 90 String() string 91 } 92 ``` 93 94 The `Content` on a proposal is an interface which contains the information about 95 the `Proposal` such as the tile, description, and any notable changes. Also, this 96 `Content` type can by implemented by any module. The `Content`'s `ProposalRoute` 97 returns a string which must be used to route the `Content`'s `Handler` in the 98 governance keeper. This allows the governance keeper to execute proposal logic 99 implemented by any module. If a proposal passes, the handler is executed. Only 100 if the handler is successful does the state get persisted and the proposal finally 101 passes. Otherwise, the proposal is rejected. 102 103 ```go 104 type Handler func(ctx sdk.Context, content Content) sdk.Error 105 ``` 106 107 The `Handler` is responsible for actually executing the proposal and processing 108 any state changes specified by the proposal. It is executed only if a proposal 109 passes during `EndBlock`. 110 111 We also mention a method to update the tally for a given proposal: 112 113 ```go 114 func (proposal Proposal) updateTally(vote byte, amount sdk.Dec) 115 ``` 116 117 ## Stores 118 119 _Stores are KVStores in the multi-store. The key to find the store is the first 120 parameter in the list_` 121 122 We will use one KVStore `Governance` to store two mappings: 123 124 - A mapping from `proposalID|'proposal'` to `Proposal`. 125 - A mapping from `proposalID|'addresses'|address` to `Vote`. This mapping allows 126 us to query all addresses that voted on the proposal along with their vote by 127 doing a range query on `proposalID:addresses`. 128 129 For pseudocode purposes, here are the two function we will use to read or write in stores: 130 131 - `load(StoreKey, Key)`: Retrieve item stored at key `Key` in store found at key `StoreKey` in the multistore 132 - `store(StoreKey, Key, value)`: Write value `Value` at key `Key` in store found at key `StoreKey` in the multistore 133 134 ## Proposal Processing Queue 135 136 **Store:** 137 138 - `ProposalProcessingQueue`: A queue `queue[proposalID]` containing all the 139 `ProposalIDs` of proposals that reached `MinDeposit`. During each `EndBlock`, 140 all the proposals that have reached the end of their voting period are processed. 141 To process a finished proposal, the application tallies the votes, computes the 142 votes of each validator and checks if every validator in the validator set has 143 voted. If the proposal is accepted, deposits are refunded. Finally, the proposal 144 content `Handler` is executed. 145 146 And the pseudocode for the `ProposalProcessingQueue`: 147 148 ```go 149 in EndBlock do 150 151 for finishedProposalID in GetAllFinishedProposalIDs(block.Time) 152 proposal = load(Governance, <proposalID|'proposal'>) // proposal is a const key 153 154 validators = Keeper.getAllValidators() 155 tmpValMap := map(sdk.AccAddress)ValidatorGovInfo 156 157 // Initiate mapping at 0. This is the amount of shares of the validator's vote that will be overridden by their delegator's votes 158 for each validator in validators 159 tmpValMap(validator.OperatorAddr).Minus = 0 160 161 // Tally 162 voterIterator = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal 163 for each (voterAddress, vote) in voterIterator 164 delegations = stakingKeeper.getDelegations(voterAddress) // get all delegations for current voter 165 166 for each delegation in delegations 167 // make sure delegation.Shares does NOT include shares being unbonded 168 tmpValMap(delegation.ValidatorAddr).Minus += delegation.Shares 169 proposal.updateTally(vote, delegation.Shares) 170 171 _, isVal = stakingKeeper.getValidator(voterAddress) 172 if (isVal) 173 tmpValMap(voterAddress).Vote = vote 174 175 tallyingParam = load(GlobalParams, 'TallyingParam') 176 177 // Update tally if validator voted they voted 178 for each validator in validators 179 if tmpValMap(validator).HasVoted 180 proposal.updateTally(tmpValMap(validator).Vote, (validator.TotalShares - tmpValMap(validator).Minus)) 181 182 183 184 // Check if proposal is accepted or rejected 185 totalNonAbstain := proposal.YesVotes + proposal.NoVotes + proposal.NoWithVetoVotes 186 if (proposal.Votes.YesVotes/totalNonAbstain > tallyingParam.Threshold AND proposal.Votes.NoWithVetoVotes/totalNonAbstain < tallyingParam.Veto) 187 // proposal was accepted at the end of the voting period 188 // refund deposits (non-voters already punished) 189 for each (amount, depositor) in proposal.Deposits 190 depositor.AtomBalance += amount 191 192 stateWriter, err := proposal.Handler() 193 if err != nil 194 // proposal passed but failed during state execution 195 proposal.CurrentStatus = ProposalStatusFailed 196 else 197 // proposal pass and state is persisted 198 proposal.CurrentStatus = ProposalStatusAccepted 199 stateWriter.save() 200 else 201 // proposal was rejected 202 proposal.CurrentStatus = ProposalStatusRejected 203 204 store(Governance, <proposalID|'proposal'>, proposal) 205 ```