github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/gov/keeper/tally.go (about) 1 package keeper 2 3 import ( 4 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 5 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/gov/types" 6 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/staking/exported" 7 ) 8 9 // TODO: Break into several smaller functions for clarity 10 11 // Tally iterates over the votes and updates the tally of a proposal based on the voting power of the 12 // voters 13 func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes bool, burnDeposits bool, tallyResults types.TallyResult) { 14 results := make(map[types.VoteOption]sdk.Dec) 15 results[types.OptionYes] = sdk.ZeroDec() 16 results[types.OptionAbstain] = sdk.ZeroDec() 17 results[types.OptionNo] = sdk.ZeroDec() 18 results[types.OptionNoWithVeto] = sdk.ZeroDec() 19 20 totalVotingPower := sdk.ZeroDec() 21 currValidators := make(map[string]types.ValidatorGovInfo) 22 23 // fetch all the bonded validators, insert them into currValidators 24 keeper.sk.IterateBondedValidatorsByPower(ctx, func(index int64, validator exported.ValidatorI) (stop bool) { 25 currValidators[validator.GetOperator().String()] = types.NewValidatorGovInfo( 26 validator.GetOperator(), 27 validator.GetBondedTokens(), 28 validator.GetDelegatorShares(), 29 sdk.ZeroDec(), 30 types.OptionEmpty, 31 ) 32 33 return false 34 }) 35 36 keeper.IterateVotes(ctx, proposal.ProposalID, func(vote types.Vote) bool { 37 // if validator, just record it in the map 38 valAddrStr := sdk.ValAddress(vote.Voter).String() 39 if val, ok := currValidators[valAddrStr]; ok { 40 val.Vote = vote.Option 41 currValidators[valAddrStr] = val 42 } 43 44 // iterate over all delegations from voter, deduct from any delegated-to validators 45 keeper.sk.IterateDelegations(ctx, vote.Voter, func(index int64, delegation exported.DelegationI) (stop bool) { 46 valAddrStr := delegation.GetValidatorAddr().String() 47 48 if val, ok := currValidators[valAddrStr]; ok { 49 // There is no need to handle the special case that validator address equal to voter address. 50 // Because voter's voting power will tally again even if there will deduct voter's voting power from validator. 51 val.DelegatorDeductions = val.DelegatorDeductions.Add(delegation.GetShares()) 52 currValidators[valAddrStr] = val 53 54 delegatorShare := delegation.GetShares().Quo(val.DelegatorShares) 55 votingPower := delegatorShare.MulInt(val.BondedTokens) 56 57 results[vote.Option] = results[vote.Option].Add(votingPower) 58 totalVotingPower = totalVotingPower.Add(votingPower) 59 } 60 61 return false 62 }) 63 64 keeper.deleteVote(ctx, vote.ProposalID, vote.Voter) 65 return false 66 }) 67 68 // iterate over the validators again to tally their voting power 69 for _, val := range currValidators { 70 if val.Vote == types.OptionEmpty { 71 continue 72 } 73 74 sharesAfterDeductions := val.DelegatorShares.Sub(val.DelegatorDeductions) 75 fractionAfterDeductions := sharesAfterDeductions.Quo(val.DelegatorShares) 76 votingPower := fractionAfterDeductions.MulInt(val.BondedTokens) 77 78 results[val.Vote] = results[val.Vote].Add(votingPower) 79 totalVotingPower = totalVotingPower.Add(votingPower) 80 } 81 82 tallyParams := keeper.GetTallyParams(ctx) 83 tallyResults = types.NewTallyResultFromMap(results) 84 85 // TODO: Upgrade the spec to cover all of these cases & remove pseudocode. 86 // If there is no staked coins, the proposal fails 87 if keeper.sk.TotalBondedTokens(ctx).IsZero() { 88 return false, false, tallyResults 89 } 90 91 // If there is not enough quorum of votes, the proposal fails 92 percentVoting := totalVotingPower.Quo(keeper.sk.TotalBondedTokens(ctx)) 93 if percentVoting.LT(tallyParams.Quorum) { 94 return false, true, tallyResults 95 } 96 97 // If no one votes (everyone abstains), proposal fails 98 if totalVotingPower.Sub(results[types.OptionAbstain]).Equal(sdk.ZeroDec()) { 99 return false, false, tallyResults 100 } 101 102 // If more than 1/3 of voters veto, proposal fails 103 if results[types.OptionNoWithVeto].Quo(totalVotingPower).GT(tallyParams.Veto) { 104 return false, true, tallyResults 105 } 106 107 // If more than 1/2 of non-abstaining voters vote Yes, proposal passes 108 if results[types.OptionYes].Quo(totalVotingPower.Sub(results[types.OptionAbstain])).GT(tallyParams.Threshold) { 109 return true, false, tallyResults 110 } 111 112 // If more than 1/2 of non-abstaining voters vote No, proposal fails 113 return false, false, tallyResults 114 }