Skip to content
This repository has been archived by the owner on Aug 3, 2023. It is now read-only.

Commit

Permalink
End proposals early on impossible conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
alpe committed Mar 3, 2020
1 parent b75e657 commit fa999b2
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 17 deletions.
4 changes: 2 additions & 2 deletions incubator/group/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ func TestFullProposalWorkflow(t *testing.T) {
// verify second proposal
proposal, err = app.GroupKeeper.GetProposal(ctx, 2)
require.NoError(t, err)
assert.Equal(t, group.ProposalBase_Undefined, proposal.GetBase().Result, proposal.GetBase().Result.String())
assert.Equal(t, group.ProposalBase_Submitted, proposal.GetBase().Status, proposal.GetBase().Status.String())
assert.Equal(t, group.ProposalBase_Rejected, proposal.GetBase().Result, proposal.GetBase().Result.String())
assert.Equal(t, group.ProposalBase_Closed, proposal.GetBase().Status, proposal.GetBase().Status.String())
expTally = group.Tally{YesCount: sdk.ZeroDec(), NoCount: sdk.ZeroDec(), AbstainCount: sdk.ZeroDec(), VetoCount: sdk.OneDec()}
assert.Equal(t, expTally, proposal.GetBase().VoteState)
}
16 changes: 10 additions & 6 deletions incubator/group/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,13 +363,15 @@ func (k Keeper) Vote(ctx sdk.Context, id ProposalID, voters []sdk.AccAddress, ch
if err != nil {
return err
}
switch accepted, err := policy.Allow(base.VoteState, electorate.TotalWeight, ctx.BlockTime().Sub(submittedAt)); {
switch result, err := policy.Allow(base.VoteState, electorate.TotalWeight, ctx.BlockTime().Sub(submittedAt)); {
case err != nil:
return errors.Wrap(err, "policy execution")
case accepted:
// with enough votes we can close the proposal early as votes can not be changed
case result == DecisionPolicyResult{Allow: true, Final: true}:
base.Result = ProposalBase_Accepted
base.Status = ProposalBase_Closed
case result == DecisionPolicyResult{Allow: false, Final: true}:
base.Result = ProposalBase_Rejected
base.Status = ProposalBase_Closed
}

proposal.SetBase(base)
Expand Down Expand Up @@ -436,15 +438,17 @@ func (k Keeper) ExecProposal(ctx sdk.Context, id ProposalID) error {
if err != nil {
return errors.Wrap(err, "from proto time")
}
switch accepted, err := policy.Allow(base.VoteState, electorate.TotalWeight, ctx.BlockTime().Sub(submittedAt)); {
switch result, err := policy.Allow(base.VoteState, electorate.TotalWeight, ctx.BlockTime().Sub(submittedAt)); {
case err != nil:
return errors.Wrap(err, "policy execution")
case accepted:
case result == DecisionPolicyResult{Allow: true, Final: true}:
base.Result = ProposalBase_Accepted
base.Status = ProposalBase_Closed
case result == DecisionPolicyResult{Allow: false, Final: true}:
base.Result = ProposalBase_Rejected
base.Status = ProposalBase_Closed
default:
// there might be votes coming so we can not close it
// todo: let decision policy decide on impossible cases to close early with ProposalBase_Rejected
}
}

Expand Down
32 changes: 23 additions & 9 deletions incubator/group/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/params/subspace"
"github.com/cosmos/modules/incubator/orm"
"github.com/gogo/protobuf/types"
"github.com/pkg/errors"
"gopkg.in/yaml.v2"

Expand All @@ -32,18 +33,31 @@ func (p ProposalID) Uint64() uint64 {
return uint64(p)
}

type DecisionPolicyResult struct {
Allow bool
Final bool
}

type DecisionPolicy interface {
// todo: @aaron: not sure if understood the concept of this policy correct but when the
// result is the decision if a proposal is accepted or rejected we need to check we need
// an error state as well. example: MsgExec before voting period end.
Allow(tally Tally, totalPower sdk.Dec, votingDuration time.Duration) (bool, error)
Allow(tally Tally, totalPower sdk.Dec, votingDuration time.Duration) (DecisionPolicyResult, error)
}

func (p ThresholdDecisionPolicy) Allow(tally Tally, totalPower sdk.Dec, votingDuration time.Duration) (bool, error) {
// if p.MinVotingWindow > votingDuration {
// return false, errors.Wrap(ErrInvalid, "min voting period not")
// }
return tally.YesCount.GT(p.Threshold), nil
func (p ThresholdDecisionPolicy) Allow(tally Tally, totalPower sdk.Dec, votingDuration time.Duration) (DecisionPolicyResult, error) {
timeout, err := types.DurationFromProto(&p.Timout)
if err != nil {
return DecisionPolicyResult{}, err
}
if timeout < votingDuration {
return DecisionPolicyResult{Allow: false, Final: true}, nil
}
if tally.YesCount.GT(p.Threshold) {
return DecisionPolicyResult{Allow: true, Final: true}, nil
}
undecided := totalPower.Sub(tally.TotalCounts())
if tally.YesCount.Add(undecided).LTE(p.Threshold) {
return DecisionPolicyResult{Allow: false, Final: true}, nil
}
return DecisionPolicyResult{Allow: false, Final: false}, nil
}

func (g GroupMember) NaturalKey() []byte {
Expand Down

0 comments on commit fa999b2

Please sign in to comment.