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  ```