Skip to content

Commit

Permalink
feat: add additional voting powers hook on gov
Browse files Browse the repository at this point in the history
(cherry picked from commit d76f922)
(cherry picked from commit ea1e4ef)
  • Loading branch information
dongsam authored and jaybxyz committed Oct 17, 2022
1 parent 0dd146d commit 764d6a9
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 7 deletions.
7 changes: 7 additions & 0 deletions x/gov/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,10 @@ func (keeper Keeper) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID
keeper.hooks.AfterProposalVotingPeriodEnded(ctx, proposalID)
}
}

// SetAdditionalVotingPowers - call hook if registered
func (keeper Keeper) SetAdditionalVotingPowers(ctx sdk.Context, votes types.Votes, votingPowers *types.AdditionalVotingPowers) {
if keeper.hooks != nil {
keeper.hooks.SetAdditionalVotingPowers(ctx, votes, votingPowers)
}
}
6 changes: 6 additions & 0 deletions x/gov/keeper/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type MockGovHooksReceiver struct {
AfterProposalVoteValid bool
AfterProposalFailedMinDepositValid bool
AfterProposalVotingPeriodEndedValid bool
SetAdditionalVotingPowersValid bool
}

func (h *MockGovHooksReceiver) AfterProposalSubmission(ctx sdk.Context, proposalID uint64) {
Expand All @@ -44,6 +45,9 @@ func (h *MockGovHooksReceiver) AfterProposalFailedMinDeposit(ctx sdk.Context, pr
func (h *MockGovHooksReceiver) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) {
h.AfterProposalVotingPeriodEndedValid = true
}
func (h *MockGovHooksReceiver) SetAdditionalVotingPowers(ctx sdk.Context, votes types.Votes, votingPowers *types.AdditionalVotingPowers) {
h.SetAdditionalVotingPowersValid = true
}

func TestHooks(t *testing.T) {
app := simapp.Setup(false)
Expand All @@ -63,6 +67,7 @@ func TestHooks(t *testing.T) {
require.False(t, govHooksReceiver.AfterProposalVoteValid)
require.False(t, govHooksReceiver.AfterProposalFailedMinDepositValid)
require.False(t, govHooksReceiver.AfterProposalVotingPeriodEndedValid)
require.False(t, govHooksReceiver.SetAdditionalVotingPowersValid)

tp := TestProposal
_, err := app.GovKeeper.SubmitProposal(ctx, tp)
Expand Down Expand Up @@ -93,4 +98,5 @@ func TestHooks(t *testing.T) {
ctx = ctx.WithBlockHeader(newHeader)
gov.EndBlocker(ctx, app.GovKeeper)
require.True(t, govHooksReceiver.AfterProposalVotingPeriodEndedValid)
require.True(t, govHooksReceiver.SetAdditionalVotingPowersValid)
}
31 changes: 27 additions & 4 deletions x/gov/keeper/tally.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,40 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes boo
return false
})

keeper.IterateVotes(ctx, proposal.ProposalId, func(vote types.Vote) bool {
additionalVotingPower := types.AdditionalVotingPowers{}
votes := keeper.GetVotes(ctx, proposal.ProposalId)
keeper.hooks.SetAdditionalVotingPowers(ctx, votes, &additionalVotingPower)
for _, vote := range votes {
// if validator, just record it in the map
voter := sdk.MustAccAddressFromBech32(vote.Voter)
voter, err := sdk.AccAddressFromBech32(vote.Voter)
if err != nil {
panic(err)
}

valAddrStr := sdk.ValAddress(voter.Bytes()).String()
if val, ok := currValidators[valAddrStr]; ok {
val.Vote = vote.Options
currValidators[valAddrStr] = val
}

if aVote, ok := additionalVotingPower[vote.Voter]; ok {
for valAddrStr, votingPower := range aVote {
if val, ok := currValidators[valAddrStr]; ok && val.BondedTokens.IsPositive() {

// total shares * voting power tokens / bonded
delShares := val.DelegatorShares.MulInt(votingPower.TruncateInt()).QuoInt(val.BondedTokens)
val.DelegatorDeductions = val.DelegatorDeductions.Add(delShares)
currValidators[valAddrStr] = val

for _, option := range vote.Options {
subPower := votingPower.Mul(option.Weight)
results[option.Option] = results[option.Option].Add(subPower)
}
totalVotingPower = totalVotingPower.Add(votingPower)
}
}
}

// iterate over all delegations from voter, deduct from any delegated-to validators
keeper.sk.IterateDelegations(ctx, voter, func(index int64, delegation stakingtypes.DelegationI) (stop bool) {
valAddrStr := delegation.GetValidatorAddr().String()
Expand All @@ -67,8 +91,7 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes boo
})

keeper.deleteVote(ctx, vote.ProposalId, voter)
return false
})
}

// iterate over the validators again to tally their voting power
for _, val := range currValidators {
Expand Down
10 changes: 8 additions & 2 deletions x/gov/spec/02_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,14 @@ And the pseudocode for the `ProposalProcessingQueue`:
tmpValMap(validator.OperatorAddr).Minus = 0

// Tally
voterIterator = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal
for each (voterAddress, vote) in voterIterator
voters = rangeQuery(Governance, <proposalID|'addresses'>) //return all the addresses that voted on the proposal
// set additional voting powers by hooking other modules
additionalVotingPowersMap = SetAdditionalVotingPowers(voters)
for each (voterAddress, vote) in voters
for each (validator, votingPower) in additionalVotingPowersMap[voterAddress]
tmpValMap(validator).Minus += votingPower.Shares
proposal.updateTally(vote, votingPower.Shares)

delegations = stakingKeeper.getDelegations(voterAddress) // get all delegations for current voter

for each delegation in delegations
Expand Down
2 changes: 2 additions & 0 deletions x/gov/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,6 @@ type GovHooks interface {
AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress) // Must be called after a vote on a proposal is cast
AfterProposalFailedMinDeposit(ctx sdk.Context, proposalID uint64) // Must be called when proposal fails to reach min deposit
AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalID uint64) // Must be called when proposal's finishes it's voting period
// SetAdditionalVotingPowers is a hook for calculating and setting additional voting power for votes in modules other than gov.
SetAdditionalVotingPowers(ctx sdk.Context, votes Votes, votingPowers *AdditionalVotingPowers) // Must be called after get votes on tally
}
5 changes: 5 additions & 0 deletions x/gov/types/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,8 @@ func (h MultiGovHooks) AfterProposalVotingPeriodEnded(ctx sdk.Context, proposalI
h[i].AfterProposalVotingPeriodEnded(ctx, proposalID)
}
}
func (h MultiGovHooks) SetAdditionalVotingPowers(ctx sdk.Context, votes Votes, votingPowers *AdditionalVotingPowers) {
for i := range h {
h[i].SetAdditionalVotingPowers(ctx, votes, votingPowers)
}
}
6 changes: 5 additions & 1 deletion x/gov/types/vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"fmt"
"strings"

yaml "gopkg.in/yaml.v2"
"gopkg.in/yaml.v2"

sdk "github.com/cosmos/cosmos-sdk/types"
)
Expand All @@ -25,6 +25,10 @@ func (v Vote) String() string {
// Votes is a collection of Vote objects
type Votes []Vote

// AdditionalVotingPowers is additional votingPower map by validators by voters
// voter addr => (validator addr => additional voting power)
type AdditionalVotingPowers map[string]map[string]sdk.Dec

// Equal returns true if two slices (order-dependant) of votes are equal.
func (v Votes) Equal(other Votes) bool {
if len(v) != len(other) {
Expand Down

0 comments on commit 764d6a9

Please sign in to comment.