cosmos-sdk/x/gov/tally.go
Alexander Bezobchuk 2d92803b9f Merge PR #2040: Refactor Validator Account Types/Bech32 Prefixing
* Add new account bech32 prefixes with godocs

* Restructure spacing of existing account code

* Update account godocs

* More account godoc updates + new tm pub/addr helpers

* Update validator type to use new account types/bech32 prefixes

* Fix account documentation errors

* Update Bech32 prefix for consensus nodes

* Update Bech32 spec doc

* Fix account type tests

* Add missing account consensus functions, clear up godocs, and fix tests

* Add to TestRandBech32PubkeyConsistency check

* Update initialization of validator public keys

* Update query signing info command

* Implement new ConsAddress type with associated unit tests

* [WIP] Update stake and slashing parameters

* Update all calls to MustBech32ifyValPub

* [WIP] Validator operator API updates

* [WIP] Fix and update unit tests

* Fix gov logs (helping to debug failing tests)

* Fix gov tally

* Fix all broken x/ unit tests

* Update gaia app genesis address logic

* Fix linting errors

* Fix broken LCD tests

* Fix broken CLI tests

* Implement command to get validator address and pubkey from key name

* Add support for getting validator key information via REST endpoint

* Update PENDING log

* Update docs

* Revert GaiaGenTx.PubKey bech32 prefix

* Fix broken docs and cli tests

* Update genesis to use correct Bech32 (cons) prefix for pubkeys

* Update docs and unit tests to reflect new cosmos account bech32 prefix

* minor formatting
2018-08-31 00:06:44 -04:00

117 lines
3.9 KiB
Go

package gov
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// validatorGovInfo used for tallying
type validatorGovInfo struct {
Address sdk.ValAddress // address of the validator operator
Power sdk.Dec // Power of a Validator
DelegatorShares sdk.Dec // Total outstanding delegator shares
Minus sdk.Dec // Minus of validator, used to compute validator's voting power
Vote VoteOption // Vote of the validator
}
func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tallyResults TallyResult, nonVoting []sdk.ValAddress) {
results := make(map[VoteOption]sdk.Dec)
results[OptionYes] = sdk.ZeroDec()
results[OptionAbstain] = sdk.ZeroDec()
results[OptionNo] = sdk.ZeroDec()
results[OptionNoWithVeto] = sdk.ZeroDec()
totalVotingPower := sdk.ZeroDec()
currValidators := make(map[string]validatorGovInfo)
keeper.vs.IterateValidatorsBonded(ctx, func(index int64, validator sdk.Validator) (stop bool) {
currValidators[validator.GetOperator().String()] = validatorGovInfo{
Address: validator.GetOperator(),
Power: validator.GetPower(),
DelegatorShares: validator.GetDelegatorShares(),
Minus: sdk.ZeroDec(),
Vote: OptionEmpty,
}
return false
})
// iterate over all the votes
votesIterator := keeper.GetVotes(ctx, proposal.GetProposalID())
defer votesIterator.Close()
for ; votesIterator.Valid(); votesIterator.Next() {
vote := &Vote{}
keeper.cdc.MustUnmarshalBinary(votesIterator.Value(), vote)
// if validator, just record it in the map
// if delegator tally voting power
valAddrStr := sdk.ValAddress(vote.Voter).String()
if val, ok := currValidators[valAddrStr]; ok {
val.Vote = vote.Option
currValidators[valAddrStr] = val
} else {
keeper.ds.IterateDelegations(ctx, vote.Voter, func(index int64, delegation sdk.Delegation) (stop bool) {
valAddrStr := delegation.GetValidator().String()
if val, ok := currValidators[valAddrStr]; ok {
val.Minus = val.Minus.Add(delegation.GetBondShares())
currValidators[valAddrStr] = val
delegatorShare := delegation.GetBondShares().Quo(val.DelegatorShares)
votingPower := val.Power.Mul(delegatorShare)
results[vote.Option] = results[vote.Option].Add(votingPower)
totalVotingPower = totalVotingPower.Add(votingPower)
}
return false
})
}
keeper.deleteVote(ctx, vote.ProposalID, vote.Voter)
}
// iterate over the validators again to tally their voting power and see
// who didn't vote
nonVoting = []sdk.ValAddress{}
for _, val := range currValidators {
if val.Vote == OptionEmpty {
nonVoting = append(nonVoting, val.Address)
continue
}
sharesAfterMinus := val.DelegatorShares.Sub(val.Minus)
percentAfterMinus := sharesAfterMinus.Quo(val.DelegatorShares)
votingPower := val.Power.Mul(percentAfterMinus)
results[val.Vote] = results[val.Vote].Add(votingPower)
totalVotingPower = totalVotingPower.Add(votingPower)
}
tallyingProcedure := keeper.GetTallyingProcedure(ctx)
tallyResults = TallyResult{
Yes: results[OptionYes],
Abstain: results[OptionAbstain],
No: results[OptionNo],
NoWithVeto: results[OptionNoWithVeto],
}
// If no one votes, proposal fails
if totalVotingPower.Sub(results[OptionAbstain]).Equal(sdk.ZeroDec()) {
return false, tallyResults, nonVoting
}
// If more than 1/3 of voters veto, proposal fails
if results[OptionNoWithVeto].Quo(totalVotingPower).GT(tallyingProcedure.Veto) {
return false, tallyResults, nonVoting
}
// If more than 1/2 of non-abstaining voters vote Yes, proposal passes
if results[OptionYes].Quo(totalVotingPower.Sub(results[OptionAbstain])).GT(tallyingProcedure.Threshold) {
return true, tallyResults, nonVoting
}
// If more than 1/2 of non-abstaining voters vote No, proposal fails
SortValAddresses(nonVoting)
return false, tallyResults, nonVoting
}