* 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
117 lines
3.9 KiB
Go
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
|
|
}
|