Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: tallyResults added to state #1914

Merged
merged 3 commits into from
Aug 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ FEATURES
* [gov] Add slashing for validators who do not vote on a proposal
* [cli] added `gov query-proposals` command to CLI. Can filter by `depositer`, `voter`, and `status`
* [core] added BaseApp.Seal - ability to seal baseapp parameters once they've been set
* [gov] added TallyResult type that gets added stored in Proposal after tallying is finished

IMPROVEMENTS
* [baseapp] Allow any alphanumeric character in route
Expand Down
4 changes: 4 additions & 0 deletions x/gov/endblocker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ func TestTickPassedDepositPeriod(t *testing.T) {
require.False(t, shouldPopInactiveProposalQueue(ctx, keeper))
require.NotNil(t, keeper.ActiveProposalQueuePeek(ctx))
require.False(t, shouldPopActiveProposalQueue(ctx, keeper))

}

func TestTickPassedVotingPeriod(t *testing.T) {
Expand Down Expand Up @@ -166,6 +167,7 @@ func TestTickPassedVotingPeriod(t *testing.T) {
require.False(t, depositsIterator.Valid())
depositsIterator.Close()
require.Equal(t, StatusRejected, keeper.GetProposal(ctx, proposalID).GetStatus())
require.True(t, keeper.GetProposal(ctx, proposalID).GetTallyResult().Equals(EmptyTallyResult()))
}

func TestSlashing(t *testing.T) {
Expand Down Expand Up @@ -204,6 +206,8 @@ func TestSlashing(t *testing.T) {

EndBlocker(ctx, keeper)

require.False(t, keeper.GetProposal(ctx, proposalID).GetTallyResult().Equals(EmptyTallyResult()))

endTotalPower := keeper.ds.GetValidatorSet().TotalPower(ctx)
val0End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[0]).GetPower().Quo(endTotalPower)
val1End := keeper.ds.GetValidatorSet().Validator(ctx, addrs[1]).GetPower().Quo(endTotalPower)
Expand Down
6 changes: 2 additions & 4 deletions x/gov/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,6 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
resTags.AppendTag(tags.ProposalID, proposalIDBytes)
}

var passes bool
var nonVotingVals []sdk.AccAddress

// Check if earliest Active Proposal ended voting period yet
for shouldPopActiveProposalQueue(ctx, keeper) {
activeProposal := keeper.ActiveProposalQueuePop(ctx)
Expand All @@ -124,7 +121,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
continue
}

passes, nonVotingVals = tally(ctx, keeper, activeProposal)
passes, tallyResults, nonVotingVals := tally(ctx, keeper, activeProposal)
proposalIDBytes := keeper.cdc.MustMarshalBinaryBare(activeProposal.GetProposalID())
var action []byte
if passes {
Expand All @@ -136,6 +133,7 @@ func EndBlocker(ctx sdk.Context, keeper Keeper) (resTags sdk.Tags) {
activeProposal.SetStatus(StatusRejected)
action = tags.ActionProposalRejected
}
activeProposal.SetTallyResult(tallyResults)
keeper.SetProposal(ctx, activeProposal)

for _, valAddr := range nonVotingVals {
Expand Down
1 change: 1 addition & 0 deletions x/gov/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func (keeper Keeper) NewTextProposal(ctx sdk.Context, title string, description
Description: description,
ProposalType: proposalType,
Status: StatusDepositPeriod,
TallyResult: EmptyTallyResult(),
TotalDeposit: sdk.Coins{},
SubmitBlock: ctx.BlockHeight(),
VotingStartBlock: -1, // TODO: Make Time
Expand Down
59 changes: 48 additions & 11 deletions x/gov/proposals.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ type Proposal interface {
GetStatus() ProposalStatus
SetStatus(ProposalStatus)

GetTallyResult() TallyResult
SetTallyResult(TallyResult)

GetSubmitBlock() int64
SetSubmitBlock(int64)

Expand All @@ -39,17 +42,18 @@ type Proposal interface {

// checks if two proposals are equal
func ProposalEqual(proposalA Proposal, proposalB Proposal) bool {
if proposalA.GetProposalID() != proposalB.GetProposalID() ||
proposalA.GetTitle() != proposalB.GetTitle() ||
proposalA.GetDescription() != proposalB.GetDescription() ||
proposalA.GetProposalType() != proposalB.GetProposalType() ||
proposalA.GetStatus() != proposalB.GetStatus() ||
proposalA.GetSubmitBlock() != proposalB.GetSubmitBlock() ||
!(proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit())) ||
proposalA.GetVotingStartBlock() != proposalB.GetVotingStartBlock() {
return false
if proposalA.GetProposalID() == proposalB.GetProposalID() &&
proposalA.GetTitle() == proposalB.GetTitle() &&
proposalA.GetDescription() == proposalB.GetDescription() &&
proposalA.GetProposalType() == proposalB.GetProposalType() &&
proposalA.GetStatus() == proposalB.GetStatus() &&
proposalA.GetTallyResult().Equals(proposalB.GetTallyResult()) &&
proposalA.GetSubmitBlock() == proposalB.GetSubmitBlock() &&
proposalA.GetTotalDeposit().IsEqual(proposalB.GetTotalDeposit()) &&
proposalA.GetVotingStartBlock() == proposalB.GetVotingStartBlock() {
return true
}
return true
return false
}

//-----------------------------------------------------------
Expand All @@ -60,7 +64,8 @@ type TextProposal struct {
Description string `json:"description"` // Description of the proposal
ProposalType ProposalKind `json:"proposal_type"` // Type of proposal. Initial set {PlainTextProposal, SoftwareUpgradeProposal}

Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected}
Status ProposalStatus `json:"proposal_status"` // Status of the Proposal {Pending, Active, Passed, Rejected}
TallyResult TallyResult `json:"tally_result"` // Result of Tallys

SubmitBlock int64 `json:"submit_block"` // Height of the block where TxGovSubmitProposal was included
TotalDeposit sdk.Coins `json:"total_deposit"` // Current deposit on this proposal. Initial value is set at InitialDeposit
Expand All @@ -82,6 +87,8 @@ func (tp TextProposal) GetProposalType() ProposalKind { return tp.P
func (tp *TextProposal) SetProposalType(proposalType ProposalKind) { tp.ProposalType = proposalType }
func (tp TextProposal) GetStatus() ProposalStatus { return tp.Status }
func (tp *TextProposal) SetStatus(status ProposalStatus) { tp.Status = status }
func (tp TextProposal) GetTallyResult() TallyResult { return tp.TallyResult }
func (tp *TextProposal) SetTallyResult(tallyResult TallyResult) { tp.TallyResult = tallyResult }
func (tp TextProposal) GetSubmitBlock() int64 { return tp.SubmitBlock }
func (tp *TextProposal) SetSubmitBlock(submitBlock int64) { tp.SubmitBlock = submitBlock }
func (tp TextProposal) GetTotalDeposit() sdk.Coins { return tp.TotalDeposit }
Expand Down Expand Up @@ -286,3 +293,33 @@ func (status ProposalStatus) Format(s fmt.State, verb rune) {
s.Write([]byte(fmt.Sprintf("%v", byte(status))))
}
}

//-----------------------------------------------------------
// Tally Results
type TallyResult struct {
Yes sdk.Rat `json:"yes"`
Abstain sdk.Rat `json:"abstain"`
No sdk.Rat `json:"no"`
NoWithVeto sdk.Rat `json:"no_with_veto"`
}

// checks if two proposals are equal
func EmptyTallyResult() TallyResult {
return TallyResult{
Yes: sdk.ZeroRat(),
Abstain: sdk.ZeroRat(),
No: sdk.ZeroRat(),
NoWithVeto: sdk.ZeroRat(),
}
}

// checks if two proposals are equal
func (resultA TallyResult) Equals(resultB TallyResult) bool {
if resultA.Yes.Equal(resultB.Yes) &&
resultA.Abstain.Equal(resultB.Abstain) &&
resultA.No.Equal(resultB.No) &&
resultA.NoWithVeto.Equal(resultB.NoWithVeto) {
return true
}
return false
}
17 changes: 12 additions & 5 deletions x/gov/tally.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ type validatorGovInfo struct {
Vote VoteOption // Vote of the validator
}

func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, nonVoting []sdk.AccAddress) {
func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, tallyResults TallyResult, nonVoting []sdk.AccAddress) {
results := make(map[VoteOption]sdk.Rat)
results[OptionYes] = sdk.ZeroRat()
results[OptionAbstain] = sdk.ZeroRat()
Expand Down Expand Up @@ -83,18 +83,25 @@ func tally(ctx sdk.Context, keeper Keeper, proposal Proposal) (passes bool, nonV

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.ZeroRat()) {
return false, nonVoting
return false, tallyResults, nonVoting
}
// If more than 1/3 of voters veto, proposal fails
if results[OptionNoWithVeto].Quo(totalVotingPower).GT(tallyingProcedure.Veto) {
return false, nonVoting
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, nonVoting
return true, tallyResults, nonVoting
}
// If more than 1/2 of non-abstaining voters vote No, proposal fails
return false, nonVoting
return false, tallyResults, nonVoting
}
38 changes: 25 additions & 13 deletions x/gov/tally_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,10 @@ func TestTallyNoOneVotes(t *testing.T) {
proposal.SetStatus(StatusVotingPeriod)
keeper.SetProposal(ctx, proposal)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.False(t, passes)
require.True(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyOnlyValidatorsAllYes(t *testing.T) {
Expand All @@ -63,9 +64,10 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionYes)
require.Nil(t, err)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.True(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyOnlyValidators51No(t *testing.T) {
Expand All @@ -86,7 +88,7 @@ func TestTallyOnlyValidators51No(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[1], OptionNo)
require.Nil(t, err)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, _, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.False(t, passes)
}
Expand All @@ -111,9 +113,10 @@ func TestTallyOnlyValidators51Yes(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo)
require.Nil(t, err)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.True(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyOnlyValidatorsVetoed(t *testing.T) {
Expand All @@ -136,9 +139,10 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNoWithVeto)
require.Nil(t, err)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) {
Expand All @@ -161,9 +165,10 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes)
require.Nil(t, err)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.True(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyOnlyValidatorsAbstainFails(t *testing.T) {
Expand All @@ -186,9 +191,10 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo)
require.Nil(t, err)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyOnlyValidatorsNonVoter(t *testing.T) {
Expand All @@ -209,11 +215,12 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo)
require.Nil(t, err)

passes, nonVoting := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, nonVoting := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.False(t, passes)
require.Equal(t, 1, len(nonVoting))
require.Equal(t, addrs[0], nonVoting[0])
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyDelgatorOverride(t *testing.T) {
Expand Down Expand Up @@ -241,9 +248,10 @@ func TestTallyDelgatorOverride(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[3], OptionNo)
require.Nil(t, err)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyDelgatorInherit(t *testing.T) {
Expand All @@ -269,10 +277,11 @@ func TestTallyDelgatorInherit(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionYes)
require.Nil(t, err)

passes, nonVoting := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, nonVoting := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.True(t, passes)
require.Equal(t, 0, len(nonVoting))
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyDelgatorMultipleOverride(t *testing.T) {
Expand Down Expand Up @@ -302,9 +311,10 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[3], OptionNo)
require.Nil(t, err)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyDelgatorMultipleInherit(t *testing.T) {
Expand Down Expand Up @@ -338,9 +348,10 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo)
require.Nil(t, err)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.False(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}

func TestTallyRevokedValidator(t *testing.T) {
Expand Down Expand Up @@ -371,7 +382,8 @@ func TestTallyRevokedValidator(t *testing.T) {
err = keeper.AddVote(ctx, proposalID, addrs[2], OptionNo)
require.Nil(t, err)

passes, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))
passes, tallyResults, _ := tally(ctx, keeper, keeper.GetProposal(ctx, proposalID))

require.True(t, passes)
require.False(t, tallyResults.Equals(EmptyTallyResult()))
}